<commit_before>//===--- UseDefaultCheck.cpp - clang-tidy----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "UseDefaultCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"

using namespace clang::ast_matchers;

namespace clang {
namespace tidy {
namespace modernize {

static const char SpecialFunction[] = "SpecialFunction";

/// \brief Finds all the named non-static fields of \p Record.
static std::set<const FieldDecl *>
getAllNamedFields(const CXXRecordDecl *Record) {
  std::set<const FieldDecl *> Result;
  for (const auto *Field : Record->fields()) {
    // Static data members are not in this range.
    if (Field->isUnnamedBitfield())
      continue;
    Result.insert(Field);
  }
  return Result;
}

/// \brief Returns the names of the direct bases of \p Record, both virtual and
/// non-virtual.
static std::set<const Type *> getAllDirectBases(const CXXRecordDecl *Record) {
  std::set<const Type *> Result;
  for (auto Base : Record->bases()) {
    // CXXBaseSpecifier.
    const auto *BaseType = Base.getTypeSourceInfo()->getType().getTypePtr();
    Result.insert(BaseType);
  }
  return Result;
}

/// \brief Returns a matcher that matches member expressions where the base is
/// the variable declared as \p Var and the accessed member is the one declared
/// as \p Field.
internal::Matcher<Expr> accessToFieldInVar(const FieldDecl *Field,
                                           const ValueDecl *Var) {
  return ignoringImpCasts(
      memberExpr(hasObjectExpression(declRefExpr(to(varDecl(equalsNode(Var))))),
                 member(fieldDecl(equalsNode(Field)))));
}

/// \brief Check that the given constructor has copy signature and that it
/// copy-initializes all its bases and members.
static bool isCopyConstructorAndCanBeDefaulted(ASTContext *Context,
                                               const CXXConstructorDecl *Ctor) {
  // An explicitly-defaulted constructor cannot have default arguments.
  if (Ctor->getMinRequiredArguments() != 1)
    return false;

  const auto *Record = Ctor->getParent();
  const auto *Param = Ctor->getParamDecl(0);

  // Base classes and members that have to be copied.
  auto BasesToInit = getAllDirectBases(Record);
  auto FieldsToInit = getAllNamedFields(Record);

  // Ensure that all the bases are copied.
  for (const auto *Base : BasesToInit) {
    // The initialization of a base class should be a call to a copy
    // constructor of the base.
    if (match(
            cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer(
                isBaseInitializer(),
                withInitializer(cxxConstructExpr(allOf(
                    hasType(equalsNode(Base)),
                    hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
                    argumentCountIs(1),
                    hasArgument(
                        0, declRefExpr(to(varDecl(equalsNode(Param))))))))))),
            *Ctor, *Context)
            .empty())
      return false;
  }

  // Ensure that all the members are copied.
  for (const auto *Field : FieldsToInit) {
    auto AccessToFieldInParam = accessToFieldInVar(Field, Param);
    // The initialization is a CXXConstructExpr for class types.
    if (match(
            cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer(
                isMemberInitializer(), forField(equalsNode(Field)),
                withInitializer(anyOf(
                    AccessToFieldInParam,
                    cxxConstructExpr(allOf(
                        hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
                        argumentCountIs(1),
                        hasArgument(0, AccessToFieldInParam)))))))),
            *Ctor, *Context)
            .empty())
      return false;
  }

  // Ensure that we don't do anything else, like initializing an indirect base.
  return Ctor->getNumCtorInitializers() ==
         BasesToInit.size() + FieldsToInit.size();
}

/// \brief Checks that the given method is an overloading of the assignment
/// operator, has copy signature, returns a reference to "*this" and copies
/// all its members and subobjects.
static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context,
                                              const CXXMethodDecl *Operator) {
  const auto *Record = Operator->getParent();
  const auto *Param = Operator->getParamDecl(0);

  // Base classes and members that have to be copied.
  auto BasesToInit = getAllDirectBases(Record);
  auto FieldsToInit = getAllNamedFields(Record);

  const auto *Compound = cast<CompoundStmt>(Operator->getBody());

  // The assignment operator definition has to end with the following return
  // statement:
  //   return *this;
  if (Compound->body_empty() ||
      match(returnStmt(has(ignoringParenImpCasts(unaryOperator(
                hasOperatorName("*"), hasUnaryOperand(cxxThisExpr()))))),
            *Compound->body_back(), *Context)
          .empty())
    return false;

  // Ensure that all the bases are copied.
  for (const auto *Base : BasesToInit) {
    // Assignment operator of a base class:
    //   Base::operator=(Other);
    //
    // Clang translates this into:
    //   ((Base*)this)->operator=((Base)Other);
    //
    // So we are looking for a member call that fulfills:
    if (match(compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr(allOf(
                  // - The object is an implicit cast of 'this' to a pointer to
                  //   a base class.
                  onImplicitObjectArgument(
                      implicitCastExpr(hasImplicitDestinationType(
                                           pointsTo(type(equalsNode(Base)))),
                                       hasSourceExpression(cxxThisExpr()))),
                  // - The called method is the operator=.
                  callee(cxxMethodDecl(isCopyAssignmentOperator())),
                  // - The argument is (an implicit cast to a Base of) the
                  // argument taken by "Operator".
                  argumentCountIs(1),
                  hasArgument(0,
                              declRefExpr(to(varDecl(equalsNode(Param)))))))))),
              *Compound, *Context)
            .empty())
      return false;
  }

  // Ensure that all the members are copied.
  for (const auto *Field : FieldsToInit) {
    // The assignment of data members:
    //   Field = Other.Field;
    // Is a BinaryOperator in non-class types, and a CXXOperatorCallExpr
    // otherwise.
    auto LHS = memberExpr(hasObjectExpression(cxxThisExpr()),
                          member(fieldDecl(equalsNode(Field))));
    auto RHS = accessToFieldInVar(Field, Param);
    if (match(
            compoundStmt(has(ignoringParenImpCasts(stmt(anyOf(
                binaryOperator(hasOperatorName("="), hasLHS(LHS), hasRHS(RHS)),
                cxxOperatorCallExpr(hasOverloadedOperatorName("="),
                                    argumentCountIs(2), hasArgument(0, LHS),
                                    hasArgument(1, RHS))))))),
            *Compound, *Context)
            .empty())
      return false;
  }

  // Ensure that we don't do anything else.
  return Compound->size() == BasesToInit.size() + FieldsToInit.size() + 1;
}

/// \brief Returns false if the body has any non-whitespace character.
static bool bodyEmpty(const ASTContext *Context, const CompoundStmt *Body) {
  bool Invalid = false;
  StringRef Text = Lexer::getSourceText(
      CharSourceRange::getCharRange(Body->getLBracLoc().getLocWithOffset(1),
                                    Body->getRBracLoc()),
      Context->getSourceManager(), Context->getLangOpts(), &Invalid);
  return !Invalid && std::strspn(Text.data(), " \t\r\n") == Text.size();
}

void UseDefaultCheck::registerMatchers(MatchFinder *Finder) {
  if (getLangOpts().CPlusPlus) {
    // Destructor.
    Finder->addMatcher(cxxDestructorDecl(isDefinition()).bind(SpecialFunction),
                       this);
    Finder->addMatcher(
        cxxConstructorDecl(
            isDefinition(),
            anyOf(
                // Default constructor.
                allOf(unless(hasAnyConstructorInitializer(isWritten())),
                      parameterCountIs(0)),
                // Copy constructor.
                allOf(isCopyConstructor(),
                      // Discard constructors that can be used as a copy
                      // constructor because all the other arguments have
                      // default values.
                      parameterCountIs(1))))
            .bind(SpecialFunction),
        this);
    // Copy-assignment operator.
    Finder->addMatcher(
        cxxMethodDecl(isDefinition(), isCopyAssignmentOperator(),
                      // isCopyAssignmentOperator() allows the parameter to be
                      // passed by value, and in this case it cannot be
                      // defaulted.
                      hasParameter(0, hasType(lValueReferenceType())))
            .bind(SpecialFunction),
        this);
  }
}

void UseDefaultCheck::check(const MatchFinder::MatchResult &Result) {
  std::string SpecialFunctionName;

  // Both CXXConstructorDecl and CXXDestructorDecl inherit from CXXMethodDecl.
  const auto *SpecialFunctionDecl =
      Result.Nodes.getNodeAs<CXXMethodDecl>(SpecialFunction);

  // Discard explicitly deleted/defaulted special member functions and those
  // that are not user-provided (automatically generated).
  if (SpecialFunctionDecl->isDeleted() ||
      SpecialFunctionDecl->isExplicitlyDefaulted() ||
      SpecialFunctionDecl->isLateTemplateParsed() ||
      !SpecialFunctionDecl->isUserProvided() || !SpecialFunctionDecl->hasBody())
    return;

  const auto *Body = dyn_cast<CompoundStmt>(SpecialFunctionDecl->getBody());
  if (!Body)
    return;

  // If there are comments inside the body, don't do the change.
  if (!SpecialFunctionDecl->isCopyAssignmentOperator() &&
      !bodyEmpty(Result.Context, Body))
    return;

  std::vector<FixItHint> RemoveInitializers;

  if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(SpecialFunctionDecl)) {
    if (Ctor->getNumParams() == 0) {
      SpecialFunctionName = "default constructor";
    } else {
      if (!isCopyConstructorAndCanBeDefaulted(Result.Context, Ctor))
        return;
      SpecialFunctionName = "copy constructor";
      // If there are constructor initializers, they must be removed.
      for (const CXXCtorInitializer *Init : Ctor->inits()) {
        RemoveInitializers.emplace_back(
            FixItHint::CreateRemoval(Init->getSourceRange()));
      }
    }
  } else if (isa<CXXDestructorDecl>(SpecialFunctionDecl)) {
    SpecialFunctionName = "destructor";
  } else {
    if (!isCopyAssignmentAndCanBeDefaulted(Result.Context, SpecialFunctionDecl))
      return;
    SpecialFunctionName = "copy-assignment operator";
  }

  diag(SpecialFunctionDecl->getLocStart(),
       "use '= default' to define a trivial " + SpecialFunctionName)
      << FixItHint::CreateReplacement(Body->getSourceRange(), "= default;")
      << RemoveInitializers;
}

} // namespace modernize
} // namespace tidy
} // namespace clang
<commit_msg>Use auto in for loop<commit_after>//===--- UseDefaultCheck.cpp - clang-tidy----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "UseDefaultCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"

using namespace clang::ast_matchers;

namespace clang {
namespace tidy {
namespace modernize {

static const char SpecialFunction[] = "SpecialFunction";

/// \brief Finds all the named non-static fields of \p Record.
static std::set<const FieldDecl *>
getAllNamedFields(const CXXRecordDecl *Record) {
  std::set<const FieldDecl *> Result;
  for (const auto *Field : Record->fields()) {
    // Static data members are not in this range.
    if (Field->isUnnamedBitfield())
      continue;
    Result.insert(Field);
  }
  return Result;
}

/// \brief Returns the names of the direct bases of \p Record, both virtual and
/// non-virtual.
static std::set<const Type *> getAllDirectBases(const CXXRecordDecl *Record) {
  std::set<const Type *> Result;
  for (auto Base : Record->bases()) {
    // CXXBaseSpecifier.
    const auto *BaseType = Base.getTypeSourceInfo()->getType().getTypePtr();
    Result.insert(BaseType);
  }
  return Result;
}

/// \brief Returns a matcher that matches member expressions where the base is
/// the variable declared as \p Var and the accessed member is the one declared
/// as \p Field.
internal::Matcher<Expr> accessToFieldInVar(const FieldDecl *Field,
                                           const ValueDecl *Var) {
  return ignoringImpCasts(
      memberExpr(hasObjectExpression(declRefExpr(to(varDecl(equalsNode(Var))))),
                 member(fieldDecl(equalsNode(Field)))));
}

/// \brief Check that the given constructor has copy signature and that it
/// copy-initializes all its bases and members.
static bool isCopyConstructorAndCanBeDefaulted(ASTContext *Context,
                                               const CXXConstructorDecl *Ctor) {
  // An explicitly-defaulted constructor cannot have default arguments.
  if (Ctor->getMinRequiredArguments() != 1)
    return false;

  const auto *Record = Ctor->getParent();
  const auto *Param = Ctor->getParamDecl(0);

  // Base classes and members that have to be copied.
  auto BasesToInit = getAllDirectBases(Record);
  auto FieldsToInit = getAllNamedFields(Record);

  // Ensure that all the bases are copied.
  for (const auto *Base : BasesToInit) {
    // The initialization of a base class should be a call to a copy
    // constructor of the base.
    if (match(
            cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer(
                isBaseInitializer(),
                withInitializer(cxxConstructExpr(allOf(
                    hasType(equalsNode(Base)),
                    hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
                    argumentCountIs(1),
                    hasArgument(
                        0, declRefExpr(to(varDecl(equalsNode(Param))))))))))),
            *Ctor, *Context)
            .empty())
      return false;
  }

  // Ensure that all the members are copied.
  for (const auto *Field : FieldsToInit) {
    auto AccessToFieldInParam = accessToFieldInVar(Field, Param);
    // The initialization is a CXXConstructExpr for class types.
    if (match(
            cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer(
                isMemberInitializer(), forField(equalsNode(Field)),
                withInitializer(anyOf(
                    AccessToFieldInParam,
                    cxxConstructExpr(allOf(
                        hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
                        argumentCountIs(1),
                        hasArgument(0, AccessToFieldInParam)))))))),
            *Ctor, *Context)
            .empty())
      return false;
  }

  // Ensure that we don't do anything else, like initializing an indirect base.
  return Ctor->getNumCtorInitializers() ==
         BasesToInit.size() + FieldsToInit.size();
}

/// \brief Checks that the given method is an overloading of the assignment
/// operator, has copy signature, returns a reference to "*this" and copies
/// all its members and subobjects.
static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context,
                                              const CXXMethodDecl *Operator) {
  const auto *Record = Operator->getParent();
  const auto *Param = Operator->getParamDecl(0);

  // Base classes and members that have to be copied.
  auto BasesToInit = getAllDirectBases(Record);
  auto FieldsToInit = getAllNamedFields(Record);

  const auto *Compound = cast<CompoundStmt>(Operator->getBody());

  // The assignment operator definition has to end with the following return
  // statement:
  //   return *this;
  if (Compound->body_empty() ||
      match(returnStmt(has(ignoringParenImpCasts(unaryOperator(
                hasOperatorName("*"), hasUnaryOperand(cxxThisExpr()))))),
            *Compound->body_back(), *Context)
          .empty())
    return false;

  // Ensure that all the bases are copied.
  for (const auto *Base : BasesToInit) {
    // Assignment operator of a base class:
    //   Base::operator=(Other);
    //
    // Clang translates this into:
    //   ((Base*)this)->operator=((Base)Other);
    //
    // So we are looking for a member call that fulfills:
    if (match(compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr(allOf(
                  // - The object is an implicit cast of 'this' to a pointer to
                  //   a base class.
                  onImplicitObjectArgument(
                      implicitCastExpr(hasImplicitDestinationType(
                                           pointsTo(type(equalsNode(Base)))),
                                       hasSourceExpression(cxxThisExpr()))),
                  // - The called method is the operator=.
                  callee(cxxMethodDecl(isCopyAssignmentOperator())),
                  // - The argument is (an implicit cast to a Base of) the
                  // argument taken by "Operator".
                  argumentCountIs(1),
                  hasArgument(0,
                              declRefExpr(to(varDecl(equalsNode(Param)))))))))),
              *Compound, *Context)
            .empty())
      return false;
  }

  // Ensure that all the members are copied.
  for (const auto *Field : FieldsToInit) {
    // The assignment of data members:
    //   Field = Other.Field;
    // Is a BinaryOperator in non-class types, and a CXXOperatorCallExpr
    // otherwise.
    auto LHS = memberExpr(hasObjectExpression(cxxThisExpr()),
                          member(fieldDecl(equalsNode(Field))));
    auto RHS = accessToFieldInVar(Field, Param);
    if (match(
            compoundStmt(has(ignoringParenImpCasts(stmt(anyOf(
                binaryOperator(hasOperatorName("="), hasLHS(LHS), hasRHS(RHS)),
                cxxOperatorCallExpr(hasOverloadedOperatorName("="),
                                    argumentCountIs(2), hasArgument(0, LHS),
                                    hasArgument(1, RHS))))))),
            *Compound, *Context)
            .empty())
      return false;
  }

  // Ensure that we don't do anything else.
  return Compound->size() == BasesToInit.size() + FieldsToInit.size() + 1;
}

/// \brief Returns false if the body has any non-whitespace character.
static bool bodyEmpty(const ASTContext *Context, const CompoundStmt *Body) {
  bool Invalid = false;
  StringRef Text = Lexer::getSourceText(
      CharSourceRange::getCharRange(Body->getLBracLoc().getLocWithOffset(1),
                                    Body->getRBracLoc()),
      Context->getSourceManager(), Context->getLangOpts(), &Invalid);
  return !Invalid && std::strspn(Text.data(), " \t\r\n") == Text.size();
}

void UseDefaultCheck::registerMatchers(MatchFinder *Finder) {
  if (getLangOpts().CPlusPlus) {
    // Destructor.
    Finder->addMatcher(cxxDestructorDecl(isDefinition()).bind(SpecialFunction),
                       this);
    Finder->addMatcher(
        cxxConstructorDecl(
            isDefinition(),
            anyOf(
                // Default constructor.
                allOf(unless(hasAnyConstructorInitializer(isWritten())),
                      parameterCountIs(0)),
                // Copy constructor.
                allOf(isCopyConstructor(),
                      // Discard constructors that can be used as a copy
                      // constructor because all the other arguments have
                      // default values.
                      parameterCountIs(1))))
            .bind(SpecialFunction),
        this);
    // Copy-assignment operator.
    Finder->addMatcher(
        cxxMethodDecl(isDefinition(), isCopyAssignmentOperator(),
                      // isCopyAssignmentOperator() allows the parameter to be
                      // passed by value, and in this case it cannot be
                      // defaulted.
                      hasParameter(0, hasType(lValueReferenceType())))
            .bind(SpecialFunction),
        this);
  }
}

void UseDefaultCheck::check(const MatchFinder::MatchResult &Result) {
  std::string SpecialFunctionName;

  // Both CXXConstructorDecl and CXXDestructorDecl inherit from CXXMethodDecl.
  const auto *SpecialFunctionDecl =
      Result.Nodes.getNodeAs<CXXMethodDecl>(SpecialFunction);

  // Discard explicitly deleted/defaulted special member functions and those
  // that are not user-provided (automatically generated).
  if (SpecialFunctionDecl->isDeleted() ||
      SpecialFunctionDecl->isExplicitlyDefaulted() ||
      SpecialFunctionDecl->isLateTemplateParsed() ||
      !SpecialFunctionDecl->isUserProvided() || !SpecialFunctionDecl->hasBody())
    return;

  const auto *Body = dyn_cast<CompoundStmt>(SpecialFunctionDecl->getBody());
  if (!Body)
    return;

  // If there are comments inside the body, don't do the change.
  if (!SpecialFunctionDecl->isCopyAssignmentOperator() &&
      !bodyEmpty(Result.Context, Body))
    return;

  std::vector<FixItHint> RemoveInitializers;

  if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(SpecialFunctionDecl)) {
    if (Ctor->getNumParams() == 0) {
      SpecialFunctionName = "default constructor";
    } else {
      if (!isCopyConstructorAndCanBeDefaulted(Result.Context, Ctor))
        return;
      SpecialFunctionName = "copy constructor";
      // If there are constructor initializers, they must be removed.
      for (const auto *Init : Ctor->inits()) {
        RemoveInitializers.emplace_back(
            FixItHint::CreateRemoval(Init->getSourceRange()));
      }
    }
  } else if (isa<CXXDestructorDecl>(SpecialFunctionDecl)) {
    SpecialFunctionName = "destructor";
  } else {
    if (!isCopyAssignmentAndCanBeDefaulted(Result.Context, SpecialFunctionDecl))
      return;
    SpecialFunctionName = "copy-assignment operator";
  }

  diag(SpecialFunctionDecl->getLocStart(),
       "use '= default' to define a trivial " + SpecialFunctionName)
      << FixItHint::CreateReplacement(Body->getSourceRange(), "= default;")
      << RemoveInitializers;
}

} // namespace modernize
} // namespace tidy
} // namespace clang
<|endoftext|>


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

#include "ppapi/proxy/ppb_url_loader_proxy.h"

#include <vector>

#include "base/logging.h"
#include "build/build_config.h"
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_resource.h"
#include "ppapi/c/dev/ppb_url_loader_dev.h"
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_resource.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/ppb_url_response_info_proxy.h"

#if defined(OS_LINUX)
#include <sys/shm.h>
#endif

namespace pp {
namespace proxy {

class URLLoader : public PluginResource {
 public:
  URLLoader();
  virtual ~URLLoader();

  // Resource overrides.
  virtual URLLoader* AsURLLoader() { return this; }

  // Initialized to -1. Will be set to nonnegative values by the UpdateProgress
  // message when the values are known.
  int64_t bytes_sent_;
  int64_t total_bytes_to_be_sent_;
  int64_t bytes_received_;
  int64_t total_bytes_to_be_received_;

  // When an asynchronous read is pending, this will contain the callback and
  // the buffer to put the data.
  PP_CompletionCallback current_read_callback_;
  char* current_read_buffer_;

 private:
  DISALLOW_COPY_AND_ASSIGN(URLLoader);
};

URLLoader::URLLoader()
    : bytes_sent_(-1),
      total_bytes_to_be_sent_(-1),
      bytes_received_(-1),
      total_bytes_to_be_received_(-1),
      current_read_callback_(PP_MakeCompletionCallback(NULL, NULL)),
      current_read_buffer_(NULL) {
}

URLLoader::~URLLoader() {
}

namespace {

// Plugin interface implmentation ----------------------------------------------

PP_Resource Create(PP_Instance instance_id) {
  PluginDispatcher* dispatcher = PluginDispatcher::Get();
  PP_Resource result = 0;
  dispatcher->Send(new PpapiHostMsg_PPBURLLoader_Create(
      INTERFACE_ID_PPB_URL_LOADER, instance_id, &result));
  if (result)
    PPB_URLLoader_Proxy::TrackPluginResource(result);
  return result;
}

PP_Bool IsURLLoader(PP_Resource resource) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(resource);
  return BoolToPPBool(!!object);
}

int32_t Open(PP_Resource loader_id,
             PP_Resource request_id,
             PP_CompletionCallback callback) {
  Dispatcher* dispatcher = PluginDispatcher::Get();
  dispatcher->Send(new PpapiHostMsg_PPBURLLoader_Open(
      INTERFACE_ID_PPB_URL_LOADER, loader_id, request_id,
      dispatcher->callback_tracker().SendCallback(callback)));
  return PP_ERROR_WOULDBLOCK;
}

int32_t FollowRedirect(PP_Resource loader_id,
                       PP_CompletionCallback callback) {
  Dispatcher* dispatcher = PluginDispatcher::Get();
  dispatcher->Send(new PpapiHostMsg_PPBURLLoader_FollowRedirect(
      INTERFACE_ID_PPB_URL_LOADER, loader_id,
      dispatcher->callback_tracker().SendCallback(callback)));
  return PP_ERROR_WOULDBLOCK;
}

PP_Bool GetUploadProgress(PP_Resource loader_id,
                          int64_t* bytes_sent,
                          int64_t* total_bytes_to_be_sent) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(loader_id);
  if (!object || object->bytes_sent_ == -1) {
    *bytes_sent = 0;
    *total_bytes_to_be_sent = 0;
    return PP_FALSE;
  }
  *bytes_sent = object->bytes_sent_;
  *total_bytes_to_be_sent = object->total_bytes_to_be_sent_;
  return PP_TRUE;
}

PP_Bool GetDownloadProgress(PP_Resource loader_id,
                            int64_t* bytes_received,
                            int64_t* total_bytes_to_be_received) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(loader_id);
  if (!object || object->bytes_received_ == -1) {
    *bytes_received = 0;
    *total_bytes_to_be_received = 0;
    return PP_FALSE;
  }
  *bytes_received = object->bytes_received_;
  *total_bytes_to_be_received = object->total_bytes_to_be_received_;
  return PP_TRUE;
}

PP_Resource GetResponseInfo(PP_Resource loader_id) {
  // If we find that plugins are frequently requesting the response info, we
  // can improve performance by caching the PP_Resource in the URLLoader
  // object. This way we only have to do IPC for the first request. However,
  // it seems that most plugins will only call this once so there's no use
  // optimizing this case.

  PP_Resource result;
  PluginDispatcher* dispatcher = PluginDispatcher::Get();
  dispatcher->Send(new PpapiHostMsg_PPBURLLoader_GetResponseInfo(
      INTERFACE_ID_PPB_URL_LOADER, loader_id, &result));
  if (dispatcher->plugin_resource_tracker()->PreparePreviouslyTrackedResource(
      result))
    return result;

  // Tell the response info to create a tracking object and add it to the
  // resource tracker.
  PPB_URLResponseInfo_Proxy::TrackPluginResource(result);
  return result;
}

int32_t ReadResponseBody(PP_Resource loader_id,
                         char* buffer,
                         int32_t bytes_to_read,
                         PP_CompletionCallback callback) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(loader_id);
  if (!object)
    return PP_ERROR_BADRESOURCE;

  if (!buffer)
    return PP_ERROR_BADARGUMENT;  // Must specify an output buffer.
  if (object->current_read_callback_.func)
    return PP_ERROR_INPROGRESS;  // Can only have one request pending.

  // Currently we don't support sync calls to read. We'll need to revisit
  // how this works when we allow blocking calls (from background threads).
  if (!callback.func)
    return PP_ERROR_BADARGUMENT;

  object->current_read_callback_ = callback;
  object->current_read_buffer_ = buffer;

  PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBURLLoader_ReadResponseBody(
      INTERFACE_ID_PPB_URL_LOADER, loader_id, bytes_to_read));
  return PP_ERROR_WOULDBLOCK;
}

int32_t FinishStreamingToFile(PP_Resource loader_id,
                              PP_CompletionCallback callback) {
  Dispatcher* dispatcher = PluginDispatcher::Get();
  dispatcher->Send(new PpapiHostMsg_PPBURLLoader_FinishStreamingToFile(
      INTERFACE_ID_PPB_URL_LOADER, loader_id,
      dispatcher->callback_tracker().SendCallback(callback)));
  return PP_ERROR_WOULDBLOCK;
}

void Close(PP_Resource loader_id) {
  PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBURLLoader_Close(
      INTERFACE_ID_PPB_URL_LOADER, loader_id));
}

const PPB_URLLoader_Dev ppb_urlloader = {
  &Create,
  &IsURLLoader,
  &Open,
  &FollowRedirect,
  &GetUploadProgress,
  &GetDownloadProgress,
  &GetResponseInfo,
  &ReadResponseBody,
  &FinishStreamingToFile,
  &Close
};

// Renderer status updates -----------------------------------------------------

// Called in the renderer when the byte counts have changed. We send a message
// to the plugin to synchronize its counts so it can respond to status polls
// from the plugin.
void UpdateResourceLoadStatus(PP_Instance pp_instance,
                              PP_Resource pp_resource,
                              int64 bytes_sent,
                              int64 total_bytes_to_be_sent,
                              int64 bytes_received,
                              int64 total_bytes_to_be_received) {
  Dispatcher* dispatcher = HostDispatcher::GetForInstance(pp_instance);
  dispatcher->Send(new PpapiMsg_PPBURLLoader_UpdateProgress(
      INTERFACE_ID_PPB_URL_LOADER, pp_resource,
      bytes_sent, total_bytes_to_be_sent,
      bytes_received, total_bytes_to_be_received));
}

// Data associated with callbacks for ReadResponseBody.
struct ReadCallbackInfo {
  base::WeakPtr<PPB_URLLoader_Proxy> loader;
  PP_Resource pp_resource;
  std::string read_buffer;
};

// Callback for renderer calls to ReadResponseBody. This function will forward
// the result to the plugin and clean up the callback info.
void ReadCallbackHandler(void* user_data, int32_t result) {
  scoped_ptr<ReadCallbackInfo> info(static_cast<ReadCallbackInfo*>(user_data));
  if (!info->loader)
    return;

  int32_t bytes_read = 0;
  if (result > 0)
    bytes_read = result;  // Positive results indicate bytes read.
  info->read_buffer.resize(bytes_read);

  info->loader->dispatcher()->Send(
      new PpapiMsg_PPBURLLoader_ReadResponseBody_Ack(
          INTERFACE_ID_PPB_URL_LOADER, info->pp_resource,
          result, info->read_buffer));
}

}  // namespace

// PPB_URLLoader_Proxy ---------------------------------------------------------

PPB_URLLoader_Proxy::PPB_URLLoader_Proxy(Dispatcher* dispatcher,
                                         const void* target_interface)
    : InterfaceProxy(dispatcher, target_interface) {
}

PPB_URLLoader_Proxy::~PPB_URLLoader_Proxy() {
}

// static
void PPB_URLLoader_Proxy::TrackPluginResource(PP_Resource url_loader_resource) {
  linked_ptr<URLLoader> object(new URLLoader);
  PluginDispatcher::Get()->plugin_resource_tracker()->AddResource(
      url_loader_resource, object);
}

const void* PPB_URLLoader_Proxy::GetSourceInterface() const {
  return &ppb_urlloader;
}

InterfaceID PPB_URLLoader_Proxy::GetInterfaceId() const {
  return INTERFACE_ID_PPB_URL_LOADER;
}

void PPB_URLLoader_Proxy::OnMessageReceived(const IPC::Message& msg) {
  IPC_BEGIN_MESSAGE_MAP(PPB_URLLoader_Proxy, msg)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Create,
                        OnMsgCreate)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Open,
                        OnMsgOpen)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FollowRedirect,
                        OnMsgFollowRedirect)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_GetResponseInfo,
                        OnMsgGetResponseInfo)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_ReadResponseBody,
                        OnMsgReadResponseBody)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FinishStreamingToFile,
                        OnMsgFinishStreamingToFile)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Close,
                        OnMsgClose)

    IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_UpdateProgress,
                        OnMsgUpdateProgress)
    IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack,
                        OnMsgReadResponseBodyAck)
  IPC_END_MESSAGE_MAP()
  // TODO(brettw) handle bad messages!
}

void PPB_URLLoader_Proxy::OnMsgCreate(PP_Instance instance,
                                      PP_Resource* result) {
  *result = ppb_url_loader_target()->Create(instance);
}

void PPB_URLLoader_Proxy::OnMsgOpen(PP_Resource loader,
                                    PP_Resource request_info,
                                    uint32_t serialized_callback) {
  PP_CompletionCallback callback = ReceiveCallback(serialized_callback);
  int32_t result = ppb_url_loader_target()->Open(
      loader, request_info, callback);
  if (result != PP_ERROR_WOULDBLOCK)
    PP_RunCompletionCallback(&callback, result);
}

void PPB_URLLoader_Proxy::OnMsgFollowRedirect(
    PP_Resource loader,
    uint32_t serialized_callback) {
  PP_CompletionCallback callback = ReceiveCallback(serialized_callback);
  int32_t result = ppb_url_loader_target()->FollowRedirect(
      loader, callback);
  if (result != PP_ERROR_WOULDBLOCK)
    PP_RunCompletionCallback(&callback, result);
}

void PPB_URLLoader_Proxy::OnMsgGetResponseInfo(PP_Resource loader,
                                               PP_Resource* result) {
  *result = ppb_url_loader_target()->GetResponseInfo(loader);
}

void PPB_URLLoader_Proxy::OnMsgReadResponseBody(
    PP_Resource loader,
    int32_t bytes_to_read) {
  // The plugin could be sending us malicious messages, don't accept negative
  // sizes.
  if (bytes_to_read < 0) {
    // TODO(brettw) kill plugin.
    bytes_to_read = 0;
  }

  // This heap object will get deleted by the callback handler.
  // TODO(brettw) this will be leaked if the plugin closes the resource!
  // (Also including the plugin unloading and having the resource implicitly
  // destroyed. Depending on the cleanup ordering, we may not need the weak
  // pointer here.)
  ReadCallbackInfo* info = new ReadCallbackInfo;
  info->loader = AsWeakPtr();
  info->pp_resource = loader;
  info->read_buffer.resize(bytes_to_read);

  int32_t result = ppb_url_loader_target()->ReadResponseBody(
      loader, const_cast<char*>(info->read_buffer.c_str()), bytes_to_read,
      PP_MakeCompletionCallback(&ReadCallbackHandler, info));
  if (result != PP_ERROR_WOULDBLOCK) {
    // Send error (or perhaps success for synchronous reads) back to plugin.
    // The callback function is already set up to do this and also delete the
    // callback info.
    ReadCallbackHandler(info, result);
  }
}

void PPB_URLLoader_Proxy::OnMsgFinishStreamingToFile(
    PP_Resource loader,
    uint32_t serialized_callback) {
  PP_CompletionCallback callback = ReceiveCallback(serialized_callback);
  int32_t result = ppb_url_loader_target()->FinishStreamingToFile(
      loader, callback);
  if (result != PP_ERROR_WOULDBLOCK)
    PP_RunCompletionCallback(&callback, result);
}

void PPB_URLLoader_Proxy::OnMsgClose(PP_Resource loader) {
  ppb_url_loader_target()->Close(loader);
}

void PPB_URLLoader_Proxy::OnMsgUpdateProgress(
    PP_Resource resource,
    int64_t bytes_sent,
    int64_t total_bytes_to_be_sent,
    int64_t bytes_received,
    int64_t total_bytes_to_be_received) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(resource);
  if (!object) {
    NOTREACHED();
    return;
  }

  object->bytes_sent_ = bytes_sent;
  object->total_bytes_to_be_sent_ = total_bytes_to_be_sent;
  object->bytes_received_ = bytes_received;
  object->total_bytes_to_be_received_ = total_bytes_to_be_received;
}

void PPB_URLLoader_Proxy::OnMsgReadResponseBodyAck(PP_Resource pp_resource,
                                                   int32 result,
                                                   const std::string& data) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(pp_resource);
  if (!object) {
    NOTREACHED();
    return;
  }

  if (!object->current_read_callback_.func || !object->current_read_buffer_) {
    NOTREACHED();
    return;
  }

  // In the error case, the string will be empty, so we can always just copy
  // out of it before issuing the callback.
  memcpy(object->current_read_buffer_, data.c_str(), data.length());

  // The plugin should be able to make a new request from their callback, so
  // we have to clear our copy first.
  PP_CompletionCallback temp_callback = object->current_read_callback_;
  object->current_read_callback_ = PP_BlockUntilComplete();
  object->current_read_buffer_ = NULL;
  PP_RunCompletionCallback(&temp_callback, result);
}

}  // namespace proxy
}  // namespace pp
<commit_msg>Remove unused function.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/proxy/ppb_url_loader_proxy.h"

#include <vector>

#include "base/logging.h"
#include "build/build_config.h"
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_resource.h"
#include "ppapi/c/dev/ppb_url_loader_dev.h"
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_resource.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/ppb_url_response_info_proxy.h"

#if defined(OS_LINUX)
#include <sys/shm.h>
#endif

namespace pp {
namespace proxy {

class URLLoader : public PluginResource {
 public:
  URLLoader();
  virtual ~URLLoader();

  // Resource overrides.
  virtual URLLoader* AsURLLoader() { return this; }

  // Initialized to -1. Will be set to nonnegative values by the UpdateProgress
  // message when the values are known.
  int64_t bytes_sent_;
  int64_t total_bytes_to_be_sent_;
  int64_t bytes_received_;
  int64_t total_bytes_to_be_received_;

  // When an asynchronous read is pending, this will contain the callback and
  // the buffer to put the data.
  PP_CompletionCallback current_read_callback_;
  char* current_read_buffer_;

 private:
  DISALLOW_COPY_AND_ASSIGN(URLLoader);
};

URLLoader::URLLoader()
    : bytes_sent_(-1),
      total_bytes_to_be_sent_(-1),
      bytes_received_(-1),
      total_bytes_to_be_received_(-1),
      current_read_callback_(PP_MakeCompletionCallback(NULL, NULL)),
      current_read_buffer_(NULL) {
}

URLLoader::~URLLoader() {
}

namespace {

// Plugin interface implmentation ----------------------------------------------

PP_Resource Create(PP_Instance instance_id) {
  PluginDispatcher* dispatcher = PluginDispatcher::Get();
  PP_Resource result = 0;
  dispatcher->Send(new PpapiHostMsg_PPBURLLoader_Create(
      INTERFACE_ID_PPB_URL_LOADER, instance_id, &result));
  if (result)
    PPB_URLLoader_Proxy::TrackPluginResource(result);
  return result;
}

PP_Bool IsURLLoader(PP_Resource resource) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(resource);
  return BoolToPPBool(!!object);
}

int32_t Open(PP_Resource loader_id,
             PP_Resource request_id,
             PP_CompletionCallback callback) {
  Dispatcher* dispatcher = PluginDispatcher::Get();
  dispatcher->Send(new PpapiHostMsg_PPBURLLoader_Open(
      INTERFACE_ID_PPB_URL_LOADER, loader_id, request_id,
      dispatcher->callback_tracker().SendCallback(callback)));
  return PP_ERROR_WOULDBLOCK;
}

int32_t FollowRedirect(PP_Resource loader_id,
                       PP_CompletionCallback callback) {
  Dispatcher* dispatcher = PluginDispatcher::Get();
  dispatcher->Send(new PpapiHostMsg_PPBURLLoader_FollowRedirect(
      INTERFACE_ID_PPB_URL_LOADER, loader_id,
      dispatcher->callback_tracker().SendCallback(callback)));
  return PP_ERROR_WOULDBLOCK;
}

PP_Bool GetUploadProgress(PP_Resource loader_id,
                          int64_t* bytes_sent,
                          int64_t* total_bytes_to_be_sent) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(loader_id);
  if (!object || object->bytes_sent_ == -1) {
    *bytes_sent = 0;
    *total_bytes_to_be_sent = 0;
    return PP_FALSE;
  }
  *bytes_sent = object->bytes_sent_;
  *total_bytes_to_be_sent = object->total_bytes_to_be_sent_;
  return PP_TRUE;
}

PP_Bool GetDownloadProgress(PP_Resource loader_id,
                            int64_t* bytes_received,
                            int64_t* total_bytes_to_be_received) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(loader_id);
  if (!object || object->bytes_received_ == -1) {
    *bytes_received = 0;
    *total_bytes_to_be_received = 0;
    return PP_FALSE;
  }
  *bytes_received = object->bytes_received_;
  *total_bytes_to_be_received = object->total_bytes_to_be_received_;
  return PP_TRUE;
}

PP_Resource GetResponseInfo(PP_Resource loader_id) {
  // If we find that plugins are frequently requesting the response info, we
  // can improve performance by caching the PP_Resource in the URLLoader
  // object. This way we only have to do IPC for the first request. However,
  // it seems that most plugins will only call this once so there's no use
  // optimizing this case.

  PP_Resource result;
  PluginDispatcher* dispatcher = PluginDispatcher::Get();
  dispatcher->Send(new PpapiHostMsg_PPBURLLoader_GetResponseInfo(
      INTERFACE_ID_PPB_URL_LOADER, loader_id, &result));
  if (dispatcher->plugin_resource_tracker()->PreparePreviouslyTrackedResource(
      result))
    return result;

  // Tell the response info to create a tracking object and add it to the
  // resource tracker.
  PPB_URLResponseInfo_Proxy::TrackPluginResource(result);
  return result;
}

int32_t ReadResponseBody(PP_Resource loader_id,
                         char* buffer,
                         int32_t bytes_to_read,
                         PP_CompletionCallback callback) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(loader_id);
  if (!object)
    return PP_ERROR_BADRESOURCE;

  if (!buffer)
    return PP_ERROR_BADARGUMENT;  // Must specify an output buffer.
  if (object->current_read_callback_.func)
    return PP_ERROR_INPROGRESS;  // Can only have one request pending.

  // Currently we don't support sync calls to read. We'll need to revisit
  // how this works when we allow blocking calls (from background threads).
  if (!callback.func)
    return PP_ERROR_BADARGUMENT;

  object->current_read_callback_ = callback;
  object->current_read_buffer_ = buffer;

  PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBURLLoader_ReadResponseBody(
      INTERFACE_ID_PPB_URL_LOADER, loader_id, bytes_to_read));
  return PP_ERROR_WOULDBLOCK;
}

int32_t FinishStreamingToFile(PP_Resource loader_id,
                              PP_CompletionCallback callback) {
  Dispatcher* dispatcher = PluginDispatcher::Get();
  dispatcher->Send(new PpapiHostMsg_PPBURLLoader_FinishStreamingToFile(
      INTERFACE_ID_PPB_URL_LOADER, loader_id,
      dispatcher->callback_tracker().SendCallback(callback)));
  return PP_ERROR_WOULDBLOCK;
}

void Close(PP_Resource loader_id) {
  PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBURLLoader_Close(
      INTERFACE_ID_PPB_URL_LOADER, loader_id));
}

const PPB_URLLoader_Dev ppb_urlloader = {
  &Create,
  &IsURLLoader,
  &Open,
  &FollowRedirect,
  &GetUploadProgress,
  &GetDownloadProgress,
  &GetResponseInfo,
  &ReadResponseBody,
  &FinishStreamingToFile,
  &Close
};

// Renderer status updates -----------------------------------------------------

// Data associated with callbacks for ReadResponseBody.
struct ReadCallbackInfo {
  base::WeakPtr<PPB_URLLoader_Proxy> loader;
  PP_Resource pp_resource;
  std::string read_buffer;
};

// Callback for renderer calls to ReadResponseBody. This function will forward
// the result to the plugin and clean up the callback info.
void ReadCallbackHandler(void* user_data, int32_t result) {
  scoped_ptr<ReadCallbackInfo> info(static_cast<ReadCallbackInfo*>(user_data));
  if (!info->loader)
    return;

  int32_t bytes_read = 0;
  if (result > 0)
    bytes_read = result;  // Positive results indicate bytes read.
  info->read_buffer.resize(bytes_read);

  info->loader->dispatcher()->Send(
      new PpapiMsg_PPBURLLoader_ReadResponseBody_Ack(
          INTERFACE_ID_PPB_URL_LOADER, info->pp_resource,
          result, info->read_buffer));
}

}  // namespace

// PPB_URLLoader_Proxy ---------------------------------------------------------

PPB_URLLoader_Proxy::PPB_URLLoader_Proxy(Dispatcher* dispatcher,
                                         const void* target_interface)
    : InterfaceProxy(dispatcher, target_interface) {
}

PPB_URLLoader_Proxy::~PPB_URLLoader_Proxy() {
}

// static
void PPB_URLLoader_Proxy::TrackPluginResource(PP_Resource url_loader_resource) {
  linked_ptr<URLLoader> object(new URLLoader);
  PluginDispatcher::Get()->plugin_resource_tracker()->AddResource(
      url_loader_resource, object);
}

const void* PPB_URLLoader_Proxy::GetSourceInterface() const {
  return &ppb_urlloader;
}

InterfaceID PPB_URLLoader_Proxy::GetInterfaceId() const {
  return INTERFACE_ID_PPB_URL_LOADER;
}

void PPB_URLLoader_Proxy::OnMessageReceived(const IPC::Message& msg) {
  IPC_BEGIN_MESSAGE_MAP(PPB_URLLoader_Proxy, msg)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Create,
                        OnMsgCreate)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Open,
                        OnMsgOpen)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FollowRedirect,
                        OnMsgFollowRedirect)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_GetResponseInfo,
                        OnMsgGetResponseInfo)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_ReadResponseBody,
                        OnMsgReadResponseBody)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FinishStreamingToFile,
                        OnMsgFinishStreamingToFile)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Close,
                        OnMsgClose)

    IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_UpdateProgress,
                        OnMsgUpdateProgress)
    IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack,
                        OnMsgReadResponseBodyAck)
  IPC_END_MESSAGE_MAP()
  // TODO(brettw) handle bad messages!
}

void PPB_URLLoader_Proxy::OnMsgCreate(PP_Instance instance,
                                      PP_Resource* result) {
  *result = ppb_url_loader_target()->Create(instance);
}

void PPB_URLLoader_Proxy::OnMsgOpen(PP_Resource loader,
                                    PP_Resource request_info,
                                    uint32_t serialized_callback) {
  PP_CompletionCallback callback = ReceiveCallback(serialized_callback);
  int32_t result = ppb_url_loader_target()->Open(
      loader, request_info, callback);
  if (result != PP_ERROR_WOULDBLOCK)
    PP_RunCompletionCallback(&callback, result);
}

void PPB_URLLoader_Proxy::OnMsgFollowRedirect(
    PP_Resource loader,
    uint32_t serialized_callback) {
  PP_CompletionCallback callback = ReceiveCallback(serialized_callback);
  int32_t result = ppb_url_loader_target()->FollowRedirect(
      loader, callback);
  if (result != PP_ERROR_WOULDBLOCK)
    PP_RunCompletionCallback(&callback, result);
}

void PPB_URLLoader_Proxy::OnMsgGetResponseInfo(PP_Resource loader,
                                               PP_Resource* result) {
  *result = ppb_url_loader_target()->GetResponseInfo(loader);
}

void PPB_URLLoader_Proxy::OnMsgReadResponseBody(
    PP_Resource loader,
    int32_t bytes_to_read) {
  // The plugin could be sending us malicious messages, don't accept negative
  // sizes.
  if (bytes_to_read < 0) {
    // TODO(brettw) kill plugin.
    bytes_to_read = 0;
  }

  // This heap object will get deleted by the callback handler.
  // TODO(brettw) this will be leaked if the plugin closes the resource!
  // (Also including the plugin unloading and having the resource implicitly
  // destroyed. Depending on the cleanup ordering, we may not need the weak
  // pointer here.)
  ReadCallbackInfo* info = new ReadCallbackInfo;
  info->loader = AsWeakPtr();
  info->pp_resource = loader;
  info->read_buffer.resize(bytes_to_read);

  int32_t result = ppb_url_loader_target()->ReadResponseBody(
      loader, const_cast<char*>(info->read_buffer.c_str()), bytes_to_read,
      PP_MakeCompletionCallback(&ReadCallbackHandler, info));
  if (result != PP_ERROR_WOULDBLOCK) {
    // Send error (or perhaps success for synchronous reads) back to plugin.
    // The callback function is already set up to do this and also delete the
    // callback info.
    ReadCallbackHandler(info, result);
  }
}

void PPB_URLLoader_Proxy::OnMsgFinishStreamingToFile(
    PP_Resource loader,
    uint32_t serialized_callback) {
  PP_CompletionCallback callback = ReceiveCallback(serialized_callback);
  int32_t result = ppb_url_loader_target()->FinishStreamingToFile(
      loader, callback);
  if (result != PP_ERROR_WOULDBLOCK)
    PP_RunCompletionCallback(&callback, result);
}

void PPB_URLLoader_Proxy::OnMsgClose(PP_Resource loader) {
  ppb_url_loader_target()->Close(loader);
}

void PPB_URLLoader_Proxy::OnMsgUpdateProgress(
    PP_Resource resource,
    int64_t bytes_sent,
    int64_t total_bytes_to_be_sent,
    int64_t bytes_received,
    int64_t total_bytes_to_be_received) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(resource);
  if (!object) {
    NOTREACHED();
    return;
  }

  object->bytes_sent_ = bytes_sent;
  object->total_bytes_to_be_sent_ = total_bytes_to_be_sent;
  object->bytes_received_ = bytes_received;
  object->total_bytes_to_be_received_ = total_bytes_to_be_received;
}

void PPB_URLLoader_Proxy::OnMsgReadResponseBodyAck(PP_Resource pp_resource,
                                                   int32 result,
                                                   const std::string& data) {
  URLLoader* object = PluginResource::GetAs<URLLoader>(pp_resource);
  if (!object) {
    NOTREACHED();
    return;
  }

  if (!object->current_read_callback_.func || !object->current_read_buffer_) {
    NOTREACHED();
    return;
  }

  // In the error case, the string will be empty, so we can always just copy
  // out of it before issuing the callback.
  memcpy(object->current_read_buffer_, data.c_str(), data.length());

  // The plugin should be able to make a new request from their callback, so
  // we have to clear our copy first.
  PP_CompletionCallback temp_callback = object->current_read_callback_;
  object->current_read_callback_ = PP_BlockUntilComplete();
  object->current_read_buffer_ = NULL;
  PP_RunCompletionCallback(&temp_callback, result);
}

}  // namespace proxy
}  // namespace pp
<|endoftext|>


<commit_before>#pragma once

#include "defaults.hpp"
#include <fstream>
#include <iomanip>

namespace gftools {

/** num_io is a wrapper around another object (of type T).
    num_io does input/output operations.
    such as streaming, saving to/loading from plaintext files.
    Internally it stores references to an instance of type T.
    Typical objects are: numbers, arrays of numbers, complex numbers, grid points*/
template <typename T> class num_io {
public:
    typedef typename std::remove_reference<T>::type type;

    /// Construct from value
    num_io(type& v):value_(v){}

    /// Access the internally stored value
    type &operator()(){return value_;}
    /// Const access to the internally stored value
    const type &operator()() const{return value_;}
    /// Save the object to a file with a filename passed in as a name
    void savetxt(const std::string& filename) {
        std::cout << "Saving " << typeid(*this).name() << " to " << filename << std::endl;
        std::ofstream out; out.open(filename.c_str()); out << *this << std::endl; out.close();
    };
    /// Read the object from a file with a filename passed in as a name
    void loadtxt(const std::string& filename) {
        std::cout << "Loading " << typeid(*this).name() << " from " << filename << std::endl;
        std::ifstream out; out.open(filename.c_str()); if (out.fail()) throw (std::bad_exception()); out >> *this; out.close();
    };

    static constexpr int precision() { return prec_; }
    static constexpr double tolerance() { return tol_; }

private:
    /// Underlying value.
    type& value_;
    /// Output precision. TODO: replace c++-11 construct constexpr with something backwards compatible.
    static constexpr int prec_ = std::numeric_limits<double>::max_digits10;
    /// Comparison tolerance
    static constexpr double tol_ = 1e-10;
};

/// A shortcut to make num_io wrapper objects without specifying the template parameter
template <typename T>
num_io<T> make_num_io (T &v){return num_io<T>(v);}

template <typename T> inline std::ostream& operator<<(std::ostream& lhs, const num_io<T> &in) {
  lhs << std::setprecision(in.precision()) << in(); return lhs;
};
template <typename T>
inline std::istream& operator>>(std::istream& lhs, num_io<T> out) {
  lhs >> out(); return lhs;
}
template <>
inline std::ostream& operator<<(std::ostream& lhs, const num_io<complex_type> &in){lhs << std::setprecision(in.precision()) << real(in()) << " " << imag(in()); return lhs;};
template <>
inline std::istream& operator>>(std::istream& lhs, num_io<complex_type> out){real_type re,im; lhs >> re; lhs >> im; out() = re+I*im; return lhs;};

} // end of namespace gftools
<commit_msg>num_io : add helper value() method<commit_after>#pragma once

#include "defaults.hpp"
#include <fstream>
#include <iomanip>

namespace gftools {

/** num_io is a wrapper around another object (of type T).
    num_io does input/output operations.
    such as streaming, saving to/loading from plaintext files.
    Internally it stores references to an instance of type T.
    Typical objects are: numbers, arrays of numbers, complex numbers, grid points*/
template <typename T> class num_io {
public:
    typedef typename std::remove_reference<T>::type type;

    /// Construct from value
    num_io(type& v):value_(v){}

    /// Access the internally stored value
    type &operator()(){return value_;}
    /// Const access to the internally stored value
    const type &operator()() const{return value_;}
    /// Save the object to a file with a filename passed in as a name
    void savetxt(const std::string& filename) {
        std::cout << "Saving " << typeid(*this).name() << " to " << filename << std::endl;
        std::ofstream out; out.open(filename.c_str()); out << *this << std::endl; out.close();
    };
    /// Read the object from a file with a filename passed in as a name
    void loadtxt(const std::string& filename) {
        std::cout << "Loading " << typeid(*this).name() << " from " << filename << std::endl;
        std::ifstream out; out.open(filename.c_str()); if (out.fail()) throw (std::bad_exception()); out >> *this; out.close();
    };

    type& value() { return value_; } // TODO : test using it
    type const& value() const { return value_; } // TODO : test using it
    static constexpr int precision() { return prec_; }
    static constexpr double tolerance() { return tol_; }

private:
    /// Underlying value.
    type& value_;
    /// Output precision. TODO: replace c++-11 construct constexpr with something backwards compatible.
    static constexpr int prec_ = std::numeric_limits<double>::max_digits10;
    /// Comparison tolerance
    static constexpr double tol_ = 1e-10;
};

/// A shortcut to make num_io wrapper objects without specifying the template parameter
template <typename T>
num_io<T> make_num_io (T &v){return num_io<T>(v);}

template <typename T> inline std::ostream& operator<<(std::ostream& lhs, const num_io<T> &in) {
  lhs << std::setprecision(in.precision()) << in(); return lhs;
};
template <typename T>
inline std::istream& operator>>(std::istream& lhs, num_io<T> out) {
  lhs >> out(); return lhs;
}
template <>
inline std::ostream& operator<<(std::ostream& lhs, const num_io<complex_type> &in){lhs << std::setprecision(in.precision()) << real(in()) << " " << imag(in()); return lhs;};
template <>
inline std::istream& operator>>(std::istream& lhs, num_io<complex_type> out){real_type re,im; lhs >> re; lhs >> im; out() = re+I*im; return lhs;};

} // end of namespace gftools
<|endoftext|>


<commit_before>#include "render/shader.h"

#include "core/assert.h"
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <sstream>

#include "render/gl.h"
#include "render/texture.h"

#include "core/filesystem.h"

ShaderId::ShaderId() : id_(glCreateProgram()) {}

ShaderId::~ShaderId() { glDeleteProgram(id_); }

GLuint ShaderId::id() const { return id_; }

namespace {
const Shader *&currentShader() {
  static const Shader *s = nullptr;
  return s;
}
}

bool ShaderId::IsCurrentlyBound() const { return this == currentShader(); }

void Use(const Shader *shader) {
  if (shader != nullptr) {
    glUseProgram(shader->id());
  }
  else {
    glUseProgram(0);
  }
  currentShader() = shader;
}

const Shader* Shader::CurrentlyBound() {
  return currentShader();
}

////////////////////////////////////////////////////////////////////////////////

namespace {
bool GetShaderCompileStatus(GLuint object) {
  int r = GL_TRUE;
  glGetShaderiv(object, GL_COMPILE_STATUS, &r);
  return r == GL_TRUE;
}

bool GetProgramLinkStatus(GLuint object) {
  int r = GL_TRUE;
  glGetProgramiv(object, GL_LINK_STATUS, &r);
  return r == GL_TRUE;
}

std::string GetShaderLog(GLuint shader) {
  int length = 0;
  glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
  if (length <= 0) return "";
  const int max_length = length + 1;
  std::vector<char> str(max_length, 0);
  glGetShaderInfoLog(shader, max_length, &length, &str[0]);
  return &str[0];
}

std::string GetProgramLog(GLuint shader) {
  int length = 0;
  glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &length);
  if (length <= 0) return "";
  const int max_length = length + 1;
  std::vector<char> str(max_length, 0);
  glGetProgramInfoLog(shader, max_length, &length, &str[0]);
  return &str[0];
}
}

void ReportError(const std::string &log, const std::string &type) {
  std::cerr << "| ERROR::SHADER: Compile-time error: Type: " << type << "\n"
            << log
            << "\n -- --------------------------------------------------- -- "
            << std::endl;
}

bool PrintErrorProgram(GLuint program) {
  if (GetProgramLinkStatus(program)) return true;
  const std::string &log = GetProgramLog(program);
  ReportError(log, "PROGRAM");
  return false;
}

void PrintErrorShader(GLuint shader, const std::string &type) {
  if (GetShaderCompileStatus(shader)) return;
  const std::string &log = GetShaderLog(shader);
  ReportError(log, type);
}

GLuint CompileShader(GLuint type, const GLchar *source,
                     const std::string &name) {
  GLuint shader = glCreateShader(type);
  glShaderSource(shader, 1, &source, NULL);
  glCompileShader(shader);
  PrintErrorShader(shader, name);
  return shader;
}

void Shader::PreBind(const ShaderAttribute& attribute) {
  Assert(this);
  glBindAttribLocation(id(), attribute.id, attribute.name.c_str());
  bound_attributes_.push_back(attribute);
}

bool Shader::Compile(const GLchar *vertexSource, const GLchar *fragmentSource,
                     const GLchar *geometrySource) {
  bool ret = true;

  GLuint sVertex = CompileShader(GL_VERTEX_SHADER, vertexSource, "VERTEX");
  GLuint sFragment =
      CompileShader(GL_FRAGMENT_SHADER, fragmentSource, "FRAGMENT");

  GLuint gShader = 0;
  if (geometrySource != nullptr) {
    gShader = CompileShader(GL_GEOMETRY_SHADER, geometrySource, "GEOMETRY");
  }

  glAttachShader(id(), sVertex);
  glAttachShader(id(), sFragment);
  if (geometrySource != nullptr) glAttachShader(id(), gShader);
  glLinkProgram(id());
  const bool link_error = PrintErrorProgram(id());
  if( link_error == false ) {
    ret = false;
  }

  glDeleteShader(sVertex);
  glDeleteShader(sFragment);
  if (geometrySource != nullptr) glDeleteShader(gShader);

  for(const auto& attribute : bound_attributes_) {
    int attribute_id = glGetAttribLocation(id(), attribute.name.c_str());
    if( attribute_id == attribute.id ) continue;
    if( attribute_id == -1 ) continue;
    std::cerr << attribute.name << " was bound to " << attribute_id << " but was requested at " << attribute.id << "\n";
    ret = false;
  }

  return ret;
}

ShaderUniform Shader::GetUniform(const std::string& name) {
  Assert(this);
  int uniform_id = glGetUniformLocation(id(), name.c_str());
  ShaderUniform uniform(name, uniform_id, this);
  bound_uniforms_.push_back(uniform);

  if(uniform.id == -1) {
    std::cerr << "Failed to load " << uniform.name << " from shader " << shader_name_ << "\n";
  }

  return uniform;
}

void Shader::SetUniform(const ShaderUniform& attribute, glint val) {
  Assert(this);
  Assert(IsCurrentlyBound());
  Assert(HasBoundUniform(attribute));
  glUniform1i(attribute.id, val);
}

void Shader::SetUniform(const ShaderUniform& attribute, const Rgb& val) {
  Assert(this);
  Assert(IsCurrentlyBound());
  Assert(HasBoundUniform(attribute));
  if(attribute.id == -1) return;
  glUniform3f(attribute.id, val.GetRed(), val.GetGreen(), val.GetBlue());
}

void Shader::SetUniform(const ShaderUniform& attribute, const Rgba& val)  {
  Assert(this);
  Assert(IsCurrentlyBound());
  Assert(HasBoundUniform(attribute));
  if(attribute.id == -1) return;
  glUniform4f(attribute.id, val.GetRed(), val.GetGreen(), val.GetBlue(), val.GetAlpha());
}

void Shader::SetUniform(const ShaderUniform& attribute, const vec4f& val) {
  Assert(this);
  Assert(IsCurrentlyBound());
  Assert(HasBoundUniform(attribute));
  if(attribute.id == -1) return;
  glUniform4f(attribute.id, val.x, val.y, val.z, val.w);
}

void Shader::SetUniform(const ShaderUniform& attribute, const mat4f& val) {
  Assert(this);
  Assert(IsCurrentlyBound());
  Assert(HasBoundUniform(attribute));
  if(attribute.id == -1) return;
  glUniformMatrix4fv(attribute.id, 1, GL_FALSE, val.GetDataPtr());
}

Shader::Shader() {}

namespace {
std::string LoadPath(FileSystem* fs, const std::string& path) {
  std::string content;
  if( false == fs->ReadFileToString(path, &content) ) {
    return "";
  }
  else {
    return content;
  }
#if 0
  std::ifstream t(path.c_str());

  if( !t ) {
    return "";
  }

  std::string str;

  t.seekg(0, std::ios::end);
  str.reserve(t.tellg());
  t.seekg(0, std::ios::beg);

  str.assign((std::istreambuf_iterator<char>(t)),
             std::istreambuf_iterator<char>());
  return str;
#endif
}
}

bool Shader::Load(FileSystem* fs, const std::string& file_path) {
  shader_name_ = file_path;
  auto vert = LoadPath(fs, file_path + ".vert");
  auto frag = LoadPath(fs, file_path + ".frag");
  auto geom = LoadPath(fs, file_path + ".geom");
  bool fail = false;
  if( vert.empty() ) {
    std::cerr << "Failed to load vert shader " << file_path << "\n";
    fail = true;
  }
  if( frag.empty() ) {
    std::cerr << "Failed to load frag shader " << file_path << "\n";
    fail = true;
  }
  if( fail ) {
    return false;
  }

  fail = Compile(vert.c_str(), frag.c_str(), geom.empty() ? nullptr : geom.c_str());
  if( fail == false ) {
    std::cerr << "Failed to compile shader " << file_path << "\n";
  }
  return fail;
}

const std::vector<ShaderAttribute>& Shader::GetAttributes() const {
  Assert(this);
  return bound_attributes_;
}

const std::string& Shader::GetName() const {
  Assert(this);
  return shader_name_;
}

bool Shader::HasBoundAttribute(const ShaderAttribute &attribute) const {
  return std::find(bound_attributes_.begin(), bound_attributes_.end(), attribute)
      != bound_attributes_.end();
}

bool Shader::HasBoundUniform(const ShaderUniform& uniform) const {
  return std::find(bound_uniforms_.begin(), bound_uniforms_.end(), uniform)
         != bound_uniforms_.end();
}

void BindTextureToShader(Texture2d* texture, Shader* shader, const ShaderUniform& attribute, unsigned int index)
{
  Assert(index < 16); // at most 16 texture units
  GLenum gl_id = GL_TEXTURE0 + index;
  glActiveTexture(gl_id);
  Use(texture);
  shader->SetUniform(attribute, index);
}
<commit_msg>added todo<commit_after>#include "render/shader.h"

#include "core/assert.h"
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <sstream>

#include "render/gl.h"
#include "render/texture.h"

#include "core/filesystem.h"

ShaderId::ShaderId() : id_(glCreateProgram()) {}

ShaderId::~ShaderId() { glDeleteProgram(id_); }

GLuint ShaderId::id() const { return id_; }

namespace {
const Shader *&currentShader() {
  static const Shader *s = nullptr;
  return s;
}
}

bool ShaderId::IsCurrentlyBound() const { return this == currentShader(); }

void Use(const Shader *shader) {
  if (shader != nullptr) {
    glUseProgram(shader->id());
  }
  else {
    glUseProgram(0);
  }
  currentShader() = shader;
}

const Shader* Shader::CurrentlyBound() {
  return currentShader();
}

////////////////////////////////////////////////////////////////////////////////

namespace {
bool GetShaderCompileStatus(GLuint object) {
  int r = GL_TRUE;
  glGetShaderiv(object, GL_COMPILE_STATUS, &r);
  return r == GL_TRUE;
}

bool GetProgramLinkStatus(GLuint object) {
  int r = GL_TRUE;
  glGetProgramiv(object, GL_LINK_STATUS, &r);
  return r == GL_TRUE;
}

std::string GetShaderLog(GLuint shader) {
  int length = 0;
  glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
  if (length <= 0) return "";
  const int max_length = length + 1;
  std::vector<char> str(max_length, 0);
  glGetShaderInfoLog(shader, max_length, &length, &str[0]);
  return &str[0];
}

std::string GetProgramLog(GLuint shader) {
  int length = 0;
  glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &length);
  if (length <= 0) return "";
  const int max_length = length + 1;
  std::vector<char> str(max_length, 0);
  glGetProgramInfoLog(shader, max_length, &length, &str[0]);
  return &str[0];
}
}

void ReportError(const std::string &log, const std::string &type) {
  std::cerr << "| ERROR::SHADER: Compile-time error: Type: " << type << "\n"
            << log
            << "\n -- --------------------------------------------------- -- "
            << std::endl;
}

bool PrintErrorProgram(GLuint program) {
  if (GetProgramLinkStatus(program)) return true;
  const std::string &log = GetProgramLog(program);
  ReportError(log, "PROGRAM");
  return false;
}

void PrintErrorShader(GLuint shader, const std::string &type) {
  if (GetShaderCompileStatus(shader)) return;
  const std::string &log = GetShaderLog(shader);
  ReportError(log, type);
}

GLuint CompileShader(GLuint type, const GLchar *source,
                     const std::string &name) {
  GLuint shader = glCreateShader(type);
  glShaderSource(shader, 1, &source, NULL);
  glCompileShader(shader);
  PrintErrorShader(shader, name);
  return shader;
}

void Shader::PreBind(const ShaderAttribute& attribute) {
  Assert(this);
  glBindAttribLocation(id(), attribute.id, attribute.name.c_str());
  bound_attributes_.push_back(attribute);
}

bool Shader::Compile(const GLchar *vertexSource, const GLchar *fragmentSource,
                     const GLchar *geometrySource) {
  bool ret = true;

  GLuint sVertex = CompileShader(GL_VERTEX_SHADER, vertexSource, "VERTEX");
  GLuint sFragment =
      CompileShader(GL_FRAGMENT_SHADER, fragmentSource, "FRAGMENT");

  GLuint gShader = 0;
  if (geometrySource != nullptr) {
    gShader = CompileShader(GL_GEOMETRY_SHADER, geometrySource, "GEOMETRY");
  }

  glAttachShader(id(), sVertex);
  glAttachShader(id(), sFragment);
  if (geometrySource != nullptr) glAttachShader(id(), gShader);
  glLinkProgram(id());
  const bool link_error = PrintErrorProgram(id());
  if( link_error == false ) {
    ret = false;
  }

  glDeleteShader(sVertex);
  glDeleteShader(sFragment);
  if (geometrySource != nullptr) glDeleteShader(gShader);

  for(const auto& attribute : bound_attributes_) {
    int attribute_id = glGetAttribLocation(id(), attribute.name.c_str());
    if( attribute_id == attribute.id ) continue;
    if( attribute_id == -1 ) continue;
    std::cerr << attribute.name << " was bound to " << attribute_id << " but was requested at " << attribute.id << "\n";
    ret = false;
  }

  return ret;
}

ShaderUniform Shader::GetUniform(const std::string& name) {
  Assert(this);
  int uniform_id = glGetUniformLocation(id(), name.c_str());
  ShaderUniform uniform(name, uniform_id, this);
  bound_uniforms_.push_back(uniform);

  if(uniform.id == -1) {
    std::cerr << "Failed to load " << uniform.name << " from shader " << shader_name_ << "\n";
  }

  return uniform;
}

void Shader::SetUniform(const ShaderUniform& attribute, glint val) {
  Assert(this);
  Assert(IsCurrentlyBound());
  Assert(HasBoundUniform(attribute));
  glUniform1i(attribute.id, val);
}

void Shader::SetUniform(const ShaderUniform& attribute, const Rgb& val) {
  Assert(this);
  Assert(IsCurrentlyBound());
  Assert(HasBoundUniform(attribute));
  if(attribute.id == -1) return;
  glUniform3f(attribute.id, val.GetRed(), val.GetGreen(), val.GetBlue());
}

void Shader::SetUniform(const ShaderUniform& attribute, const Rgba& val)  {
  Assert(this);
  Assert(IsCurrentlyBound());
  Assert(HasBoundUniform(attribute));
  if(attribute.id == -1) return;
  glUniform4f(attribute.id, val.GetRed(), val.GetGreen(), val.GetBlue(), val.GetAlpha());
}

void Shader::SetUniform(const ShaderUniform& attribute, const vec4f& val) {
  Assert(this);
  Assert(IsCurrentlyBound());
  Assert(HasBoundUniform(attribute));
  if(attribute.id == -1) return;
  glUniform4f(attribute.id, val.x, val.y, val.z, val.w);
}

void Shader::SetUniform(const ShaderUniform& attribute, const mat4f& val) {
  Assert(this);
  Assert(IsCurrentlyBound());
  Assert(HasBoundUniform(attribute));
  if(attribute.id == -1) return;
  glUniformMatrix4fv(attribute.id, 1, GL_FALSE, val.GetDataPtr());
}

Shader::Shader() {}

namespace {
std::string LoadPath(FileSystem* fs, const std::string& path) {
  // todo: replace with a template instead of basic string
  std::string content;
  if( false == fs->ReadFileToString(path, &content) ) {
    return "";
  }
  else {
    return content;
  }
#if 0
  std::ifstream t(path.c_str());

  if( !t ) {
    return "";
  }

  std::string str;

  t.seekg(0, std::ios::end);
  str.reserve(t.tellg());
  t.seekg(0, std::ios::beg);

  str.assign((std::istreambuf_iterator<char>(t)),
             std::istreambuf_iterator<char>());
  return str;
#endif
}
}

bool Shader::Load(FileSystem* fs, const std::string& file_path) {
  shader_name_ = file_path;
  auto vert = LoadPath(fs, file_path + ".vert");
  auto frag = LoadPath(fs, file_path + ".frag");
  auto geom = LoadPath(fs, file_path + ".geom");
  bool fail = false;
  if( vert.empty() ) {
    std::cerr << "Failed to load vert shader " << file_path << "\n";
    fail = true;
  }
  if( frag.empty() ) {
    std::cerr << "Failed to load frag shader " << file_path << "\n";
    fail = true;
  }
  if( fail ) {
    return false;
  }

  fail = Compile(vert.c_str(), frag.c_str(), geom.empty() ? nullptr : geom.c_str());
  if( fail == false ) {
    std::cerr << "Failed to compile shader " << file_path << "\n";
  }
  return fail;
}

const std::vector<ShaderAttribute>& Shader::GetAttributes() const {
  Assert(this);
  return bound_attributes_;
}

const std::string& Shader::GetName() const {
  Assert(this);
  return shader_name_;
}

bool Shader::HasBoundAttribute(const ShaderAttribute &attribute) const {
  return std::find(bound_attributes_.begin(), bound_attributes_.end(), attribute)
      != bound_attributes_.end();
}

bool Shader::HasBoundUniform(const ShaderUniform& uniform) const {
  return std::find(bound_uniforms_.begin(), bound_uniforms_.end(), uniform)
         != bound_uniforms_.end();
}

void BindTextureToShader(Texture2d* texture, Shader* shader, const ShaderUniform& attribute, unsigned int index)
{
  Assert(index < 16); // at most 16 texture units
  GLenum gl_id = GL_TEXTURE0 + index;
  glActiveTexture(gl_id);
  Use(texture);
  shader->SetUniform(attribute, index);
}
<|endoftext|>


<commit_before>#if (defined _WIN32) || (defined _WIN64)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <windows.h>
#else  // (defined _WIN32) || (defined _WIN64)
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <unistd.h>
#endif  // (defined _WIN32) || (defined _WIN64)

#include "mapper.h"

namespace marisa {
namespace grimoire {
namespace io {

#if (defined _WIN32) || (defined _WIN64)
Mapper::Mapper()
    : ptr_(NULL), origin_(NULL), avail_(0), size_(0),
      file_(NULL), map_(NULL) {}
#else  // (defined _WIN32) || (defined _WIN64)
Mapper::Mapper()
    : ptr_(NULL), origin_(MAP_FAILED), avail_(0), size_(0), fd_(-1) {}
#endif  // (defined _WIN32) || (defined _WIN64)

#if (defined _WIN32) || (defined _WIN64)
Mapper::~Mapper() {
  if (origin_ != NULL) {
    ::UnmapViewOfFile(origin_);
  }

  if (map_ != NULL) {
    ::CloseHandle(map_);
  }

  if (file_ != NULL) {
    ::CloseHandle(file_);
  }
}
#else  // (defined _WIN32) || (defined _WIN64)
Mapper::~Mapper() {
  if (origin_ != MAP_FAILED) {
    ::munmap(origin_, size_);
  }

  if (fd_ != -1) {
    ::close(fd_);
  }
}
#endif  // (defined _WIN32) || (defined _WIN64)

void Mapper::open(const char *filename) {
  MARISA_THROW_IF(filename == NULL, MARISA_NULL_ERROR);

  Mapper temp;
  temp.open_(filename);
  swap(temp);
}

void Mapper::open(const void *ptr, std::size_t size) {
  MARISA_THROW_IF((ptr == NULL) && (size != 0), MARISA_NULL_ERROR);

  Mapper temp;
  temp.open_(ptr, size);
  swap(temp);
}

void Mapper::seek(std::size_t size) {
  MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR);
  MARISA_THROW_IF(size > avail_, MARISA_IO_ERROR);

  map_data(size);
}

bool Mapper::is_open() const {
  return ptr_ != NULL;
}

void Mapper::clear() {
  Mapper().swap(*this);
}

void Mapper::swap(Mapper &rhs) {
  marisa::swap(ptr_, rhs.ptr_);
  marisa::swap(avail_, rhs.avail_);
  marisa::swap(origin_, rhs.origin_);
  marisa::swap(size_, rhs.size_);
#if (defined _WIN32) || (defined _WIN64)
  marisa::swap(file_, rhs.file_);
  marisa::swap(map_, rhs.map_);
#else  // (defined _WIN32) || (defined _WIN64)
  marisa::swap(fd_, rhs.fd_);
#endif  // (defined _WIN32) || (defined _WIN64)
}

const void *Mapper::map_data(std::size_t size) {
  MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR);
  MARISA_THROW_IF(size > avail_, MARISA_IO_ERROR);

  const char * const data = static_cast<const char *>(ptr_);
  ptr_ = data + size;
  avail_ -= size;
  return data;
}

#if (defined _WIN32) || (defined _WIN64)
void Mapper::open_(const char *filename) {
  struct __stat64 st;
  MARISA_THROW_IF(::_stat64(filename, &st) != 0, MARISA_IO_ERROR);
  MARISA_THROW_IF((UInt64)st.st_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR);
  size_ = (std::size_t)st.st_size;

  file_ = ::CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ,
      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  MARISA_THROW_IF(file_ == NULL, MARISA_IO_ERROR);

  map_ = ::CreateFileMapping(file_, NULL, PAGE_READONLY, 0, 0, NULL);
  MARISA_THROW_IF(map_ == NULL, MARISA_IO_ERROR);

  origin_ = ::MapViewOfFile(map_, FILE_MAP_READ, 0, 0, 0);
  MARISA_THROW_IF(origin_ == NULL, MARISA_IO_ERROR);

  ptr_ = static_cast<const char *>(origin_);
  avail_ = size_;
}
#else  // (defined _WIN32) || (defined _WIN64)
void Mapper::open_(const char *filename) {
  struct stat st;
  MARISA_THROW_IF(::stat(filename, &st) != 0, MARISA_IO_ERROR);
  MARISA_THROW_IF((UInt64)st.st_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR);
  size_ = (std::size_t)st.st_size;

  fd_ = ::open(filename, O_RDONLY);
  MARISA_THROW_IF(fd_ == -1, MARISA_IO_ERROR);

  origin_ = ::mmap(NULL, size_, PROT_READ, MAP_SHARED, fd_, 0);
  MARISA_THROW_IF(origin_ == MAP_FAILED, MARISA_IO_ERROR);

  ptr_ = static_cast<const char *>(origin_);
  avail_ = size_;
}
#endif  // (defined _WIN32) || (defined _WIN64)

void Mapper::open_(const void *ptr, std::size_t size) {
  ptr_ = ptr;
  avail_ = size;
}

}  // namespace io
}  // namespace grimoire
}  // namespace marisa
<commit_msg>(upstream fix) this should resolve issues with mingw<commit_after>#if (defined _WIN32) || (defined _WIN64)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <windows.h>
#else  // (defined _WIN32) || (defined _WIN64)
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <unistd.h>
#endif  // (defined _WIN32) || (defined _WIN64)

#include "mapper.h"

namespace marisa {
namespace grimoire {
namespace io {

#if (defined _WIN32) || (defined _WIN64)
Mapper::Mapper()
    : ptr_(NULL), origin_(NULL), avail_(0), size_(0),
      file_(NULL), map_(NULL) {}
#else  // (defined _WIN32) || (defined _WIN64)
Mapper::Mapper()
    : ptr_(NULL), origin_(MAP_FAILED), avail_(0), size_(0), fd_(-1) {}
#endif  // (defined _WIN32) || (defined _WIN64)

#if (defined _WIN32) || (defined _WIN64)
Mapper::~Mapper() {
  if (origin_ != NULL) {
    ::UnmapViewOfFile(origin_);
  }

  if (map_ != NULL) {
    ::CloseHandle(map_);
  }

  if (file_ != NULL) {
    ::CloseHandle(file_);
  }
}
#else  // (defined _WIN32) || (defined _WIN64)
Mapper::~Mapper() {
  if (origin_ != MAP_FAILED) {
    ::munmap(origin_, size_);
  }

  if (fd_ != -1) {
    ::close(fd_);
  }
}
#endif  // (defined _WIN32) || (defined _WIN64)

void Mapper::open(const char *filename) {
  MARISA_THROW_IF(filename == NULL, MARISA_NULL_ERROR);

  Mapper temp;
  temp.open_(filename);
  swap(temp);
}

void Mapper::open(const void *ptr, std::size_t size) {
  MARISA_THROW_IF((ptr == NULL) && (size != 0), MARISA_NULL_ERROR);

  Mapper temp;
  temp.open_(ptr, size);
  swap(temp);
}

void Mapper::seek(std::size_t size) {
  MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR);
  MARISA_THROW_IF(size > avail_, MARISA_IO_ERROR);

  map_data(size);
}

bool Mapper::is_open() const {
  return ptr_ != NULL;
}

void Mapper::clear() {
  Mapper().swap(*this);
}

void Mapper::swap(Mapper &rhs) {
  marisa::swap(ptr_, rhs.ptr_);
  marisa::swap(avail_, rhs.avail_);
  marisa::swap(origin_, rhs.origin_);
  marisa::swap(size_, rhs.size_);
#if (defined _WIN32) || (defined _WIN64)
  marisa::swap(file_, rhs.file_);
  marisa::swap(map_, rhs.map_);
#else  // (defined _WIN32) || (defined _WIN64)
  marisa::swap(fd_, rhs.fd_);
#endif  // (defined _WIN32) || (defined _WIN64)
}

const void *Mapper::map_data(std::size_t size) {
  MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR);
  MARISA_THROW_IF(size > avail_, MARISA_IO_ERROR);

  const char * const data = static_cast<const char *>(ptr_);
  ptr_ = data + size;
  avail_ -= size;
  return data;
}

#if (defined _WIN32) || (defined _WIN64)
 #ifdef __MSVCRT_VERSION__
  #if __MSVCRT_VERSION__ >= 0x0601
   #define MARISA_HAS_STAT64
  #endif  // __MSVCRT_VERSION__ >= 0x0601
 #endif  // __MSVCRT_VERSION__
void Mapper::open_(const char *filename) {
 #ifdef MARISA_HAS_STAT64
  struct __stat64 st;
  MARISA_THROW_IF(::_stat64(filename, &st) != 0, MARISA_IO_ERROR);
 #else  // MARISA_HAS_STAT64
  struct _stat st;
  MARISA_THROW_IF(::_stat(filename, &st) != 0, MARISA_IO_ERROR);
 #endif  // MARISA_HAS_STAT64
  MARISA_THROW_IF((UInt64)st.st_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR);
  size_ = (std::size_t)st.st_size;

  file_ = ::CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ,
      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  MARISA_THROW_IF(file_ == NULL, MARISA_IO_ERROR);

  map_ = ::CreateFileMapping(file_, NULL, PAGE_READONLY, 0, 0, NULL);
  MARISA_THROW_IF(map_ == NULL, MARISA_IO_ERROR);

  origin_ = ::MapViewOfFile(map_, FILE_MAP_READ, 0, 0, 0);
  MARISA_THROW_IF(origin_ == NULL, MARISA_IO_ERROR);

  ptr_ = static_cast<const char *>(origin_);
  avail_ = size_;
}
#else  // (defined _WIN32) || (defined _WIN64)
void Mapper::open_(const char *filename) {
  struct stat st;
  MARISA_THROW_IF(::stat(filename, &st) != 0, MARISA_IO_ERROR);
  MARISA_THROW_IF((UInt64)st.st_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR);
  size_ = (std::size_t)st.st_size;

  fd_ = ::open(filename, O_RDONLY);
  MARISA_THROW_IF(fd_ == -1, MARISA_IO_ERROR);

  origin_ = ::mmap(NULL, size_, PROT_READ, MAP_SHARED, fd_, 0);
  MARISA_THROW_IF(origin_ == MAP_FAILED, MARISA_IO_ERROR);

  ptr_ = static_cast<const char *>(origin_);
  avail_ = size_;
}
#endif  // (defined _WIN32) || (defined _WIN64)

void Mapper::open_(const void *ptr, std::size_t size) {
  ptr_ = ptr;
  avail_ = size;
}

}  // namespace io
}  // namespace grimoire
}  // namespace marisa
<|endoftext|>