<commit_before>/*************************************************************************
 *
 *  $RCSfile: cx_c_pp.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2004-11-15 13:38:48 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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 for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <precomp.h>
#include "cx_c_pp.hxx"

// NOT FULLY DECLARED SERVICES
#include "c_dealer.hxx"
#include <tokens/parseinc.hxx>
#include <x_parse.hxx>
#include "all_toks.hxx"

namespace cpp
{

Context_Preprocessor::Context_Preprocessor( TkpContext & i_rFollowUpContext )
    :   Cx_Base(&i_rFollowUpContext),
        pContext_Parent(&i_rFollowUpContext),
        pContext_PP_MacroParams( 0 ),
        pContext_PP_Definition( new Context_PP_Definition(i_rFollowUpContext) )
{
    pContext_PP_MacroParams = new Context_PP_MacroParams(*pContext_PP_Definition);
}

void
Context_Preprocessor::ReadCharChain( CharacterSource &  io_rText )
{
    jumpOverWhite( io_rText );
    jumpToWhite( io_rText );
    const char * sPP_Keyword = io_rText.CutToken();
    if ( strcmp(sPP_Keyword, "define") == 0 )
        ReadDefine(io_rText);
    else
        ReadDefault(io_rText);
}

void
Context_Preprocessor::AssignDealer( Distributor & o_rDealer )
{
    Cx_Base::AssignDealer(o_rDealer);
    pContext_PP_MacroParams->AssignDealer(o_rDealer);
    pContext_PP_Definition->AssignDealer(o_rDealer);
}

void
Context_Preprocessor::ReadDefault( CharacterSource & io_rText )
{
    int o_rCount_BackslashedLineBreaks = 0;
    jumpToEol(io_rText,o_rCount_BackslashedLineBreaks);
    for ( ; o_rCount_BackslashedLineBreaks > 0; --o_rCount_BackslashedLineBreaks )
        Dealer().Deal_Eol();

    if (io_rText.CurChar() != NULCH)
        jumpOverEol(io_rText);
    io_rText.CutToken();
    Dealer().Deal_Eol();
    SetNewToken(0);
    SetFollowUpContext( pContext_Parent );
}

void
Context_Preprocessor::ReadDefine( CharacterSource & io_rText )
{
    jumpOverWhite( io_rText );

    char cNext = '\0';
    for ( cNext = io_rText.CurChar();
          static_cast<UINT8>(cNext) > 32 AND cNext != '(';
          cNext = io_rText.MoveOn() )
    { }

    bool bMacro = cNext == '(';

    if ( NOT bMacro )
    {
        SetNewToken( new Tok_DefineName(io_rText.CutToken()) );
        SetFollowUpContext( pContext_PP_Definition.Ptr() );
    }
    else
    {
        SetNewToken( new Tok_MacroName(io_rText.CutToken()) );
        io_rText.MoveOn();
        io_rText.CutToken();
        SetFollowUpContext( pContext_PP_MacroParams.Ptr() );
    }
}

Context_PP_MacroParams::Context_PP_MacroParams( Cx_Base & i_rFollowUpContext )
    :   Cx_Base(&i_rFollowUpContext),
        pContext_PP_Definition(&i_rFollowUpContext)
{
}

void
Context_PP_MacroParams::ReadCharChain( CharacterSource & io_rText )
{
    uintt nLen;

    jumpOverWhite( io_rText );
    // KORR_FUTURE Handling line breaks within macro parameters:
    char cSeparator = jumpTo( io_rText, ',', ')' );
    csv_assert( cSeparator != 0 );

    static char cBuf[500];
    // KORR_FUTURE, make it still safer, here:
    strcpy( cBuf, io_rText.CutToken() );    // SAFE STRCPY (#100211# - checked)
    for ( nLen = strlen(cBuf);
          nLen > 0 AND cBuf[nLen-1] < 33;
          --nLen )
    { }
    cBuf[nLen] = '\0';
    SetNewToken( new Tok_MacroParameter(cBuf) );

    io_rText.MoveOn();
    io_rText.CutToken();
    if ( cSeparator == ',')
        SetFollowUpContext( this );
    else    // Must be ')'
        SetFollowUpContext( pContext_PP_Definition );
}

Context_PP_Definition::Context_PP_Definition( TkpContext & i_rFollowUpContext )
    :   Cx_Base(&i_rFollowUpContext),
        pContext_Parent(&i_rFollowUpContext)
{
}

void
Context_PP_Definition::ReadCharChain( CharacterSource & io_rText )
{
    int o_rCount_BackslashedLineBreaks = 0;
    jumpToEol(io_rText,o_rCount_BackslashedLineBreaks);
    for ( ; o_rCount_BackslashedLineBreaks > 0; --o_rCount_BackslashedLineBreaks )
        Dealer().Deal_Eol();
    SetNewToken( new Tok_PreProDefinition(io_rText.CutToken()) );
    if (io_rText.CurChar() != NULCH)
        jumpOverEol(io_rText);
    Dealer().Deal_Eol();
}

}   // namespace cpp

<commit_msg>INTEGRATION: CWS ooo19126 (1.4.18); FILE MERGED 2005/09/05 13:11:39 rt 1.4.18.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cx_c_pp.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 18:17:41 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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 for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <precomp.h>
#include "cx_c_pp.hxx"

// NOT FULLY DECLARED SERVICES
#include "c_dealer.hxx"
#include <tokens/parseinc.hxx>
#include <x_parse.hxx>
#include "all_toks.hxx"

namespace cpp
{

Context_Preprocessor::Context_Preprocessor( TkpContext & i_rFollowUpContext )
    :   Cx_Base(&i_rFollowUpContext),
        pContext_Parent(&i_rFollowUpContext),
        pContext_PP_MacroParams( 0 ),
        pContext_PP_Definition( new Context_PP_Definition(i_rFollowUpContext) )
{
    pContext_PP_MacroParams = new Context_PP_MacroParams(*pContext_PP_Definition);
}

void
Context_Preprocessor::ReadCharChain( CharacterSource &  io_rText )
{
    jumpOverWhite( io_rText );
    jumpToWhite( io_rText );
    const char * sPP_Keyword = io_rText.CutToken();
    if ( strcmp(sPP_Keyword, "define") == 0 )
        ReadDefine(io_rText);
    else
        ReadDefault(io_rText);
}

void
Context_Preprocessor::AssignDealer( Distributor & o_rDealer )
{
    Cx_Base::AssignDealer(o_rDealer);
    pContext_PP_MacroParams->AssignDealer(o_rDealer);
    pContext_PP_Definition->AssignDealer(o_rDealer);
}

void
Context_Preprocessor::ReadDefault( CharacterSource & io_rText )
{
    int o_rCount_BackslashedLineBreaks = 0;
    jumpToEol(io_rText,o_rCount_BackslashedLineBreaks);
    for ( ; o_rCount_BackslashedLineBreaks > 0; --o_rCount_BackslashedLineBreaks )
        Dealer().Deal_Eol();

    if (io_rText.CurChar() != NULCH)
        jumpOverEol(io_rText);
    io_rText.CutToken();
    Dealer().Deal_Eol();
    SetNewToken(0);
    SetFollowUpContext( pContext_Parent );
}

void
Context_Preprocessor::ReadDefine( CharacterSource & io_rText )
{
    jumpOverWhite( io_rText );

    char cNext = '\0';
    for ( cNext = io_rText.CurChar();
          static_cast<UINT8>(cNext) > 32 AND cNext != '(';
          cNext = io_rText.MoveOn() )
    { }

    bool bMacro = cNext == '(';

    if ( NOT bMacro )
    {
        SetNewToken( new Tok_DefineName(io_rText.CutToken()) );
        SetFollowUpContext( pContext_PP_Definition.Ptr() );
    }
    else
    {
        SetNewToken( new Tok_MacroName(io_rText.CutToken()) );
        io_rText.MoveOn();
        io_rText.CutToken();
        SetFollowUpContext( pContext_PP_MacroParams.Ptr() );
    }
}

Context_PP_MacroParams::Context_PP_MacroParams( Cx_Base & i_rFollowUpContext )
    :   Cx_Base(&i_rFollowUpContext),
        pContext_PP_Definition(&i_rFollowUpContext)
{
}

void
Context_PP_MacroParams::ReadCharChain( CharacterSource & io_rText )
{
    uintt nLen;

    jumpOverWhite( io_rText );
    // KORR_FUTURE Handling line breaks within macro parameters:
    char cSeparator = jumpTo( io_rText, ',', ')' );
    csv_assert( cSeparator != 0 );

    static char cBuf[500];
    // KORR_FUTURE, make it still safer, here:
    strcpy( cBuf, io_rText.CutToken() );    // SAFE STRCPY (#100211# - checked)
    for ( nLen = strlen(cBuf);
          nLen > 0 AND cBuf[nLen-1] < 33;
          --nLen )
    { }
    cBuf[nLen] = '\0';
    SetNewToken( new Tok_MacroParameter(cBuf) );

    io_rText.MoveOn();
    io_rText.CutToken();
    if ( cSeparator == ',')
        SetFollowUpContext( this );
    else    // Must be ')'
        SetFollowUpContext( pContext_PP_Definition );
}

Context_PP_Definition::Context_PP_Definition( TkpContext & i_rFollowUpContext )
    :   Cx_Base(&i_rFollowUpContext),
        pContext_Parent(&i_rFollowUpContext)
{
}

void
Context_PP_Definition::ReadCharChain( CharacterSource & io_rText )
{
    int o_rCount_BackslashedLineBreaks = 0;
    jumpToEol(io_rText,o_rCount_BackslashedLineBreaks);
    for ( ; o_rCount_BackslashedLineBreaks > 0; --o_rCount_BackslashedLineBreaks )
        Dealer().Deal_Eol();
    SetNewToken( new Tok_PreProDefinition(io_rText.CutToken()) );
    if (io_rText.CurChar() != NULCH)
        jumpOverEol(io_rText);
    Dealer().Deal_Eol();
}

}   // namespace cpp

<|endoftext|>


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

#include "modules/canbus/can_comm/can_receiver.h"

#include <cmath>
#include <iostream>
#include <sstream>

#include "modules/canbus/common/canbus_consts.h"
#include "modules/common/log.h"

namespace apollo {
namespace canbus {

using ::apollo::common::ErrorCode;

ErrorCode CanReceiver::Init(CanClient* can_client, MessageManager* pt_manager,
                            bool enable_log) {
  can_client_ = can_client;
  pt_manager_ = pt_manager;
  enable_log_ = enable_log;
  if (can_client_ == nullptr) {
    AERROR << "Invalid can client.";
    return ErrorCode::CANBUS_ERROR;
  }
  if (pt_manager_ == nullptr) {
    AERROR << "Invalid protocol manager.";
    return ErrorCode::CANBUS_ERROR;
  }
  is_init_ = true;
  return ErrorCode::OK;
}

void CanReceiver::RecvThreadFunc() {
  AINFO << "Can client receiver thread starts.";
  CHECK_NOTNULL(can_client_);
  CHECK_NOTNULL(pt_manager_);

  int32_t receive_error_count = 0;
  int32_t receive_none_count = 0;
  const int32_t ERROR_COUNT_MAX = 10;
  std::chrono::duration<double, std::micro> default_period{10 * 1000};

  while (IsRunning()) {
    std::vector<CanFrame> buf;
    int32_t length = MAX_CAN_RECV_FRAME_LEN;
    if (can_client_->Receive(&buf, &length) != ErrorCode::OK) {
      LOG_IF_EVERY_N(ERROR, receive_error_count++ > ERROR_COUNT_MAX,
                     ERROR_COUNT_MAX)
          << "Received " << receive_error_count << " error messages.";
      std::this_thread::sleep_for(default_period);
      continue;
    }
    receive_error_count = 0;

    if (buf.size() != static_cast<size_t>(length)) {
      AERROR << "Receiver buf size[" << buf.size()
             << "] does not match can_client returned length[" << length
             << "].";
    }

    if (length == 0) {
      LOG_IF_EVERY_N(ERROR, receive_none_count++ > ERROR_COUNT_MAX,
                     ERROR_COUNT_MAX)
          << "Received " << receive_none_count << " empty messages.";
      std::this_thread::sleep_for(default_period);
      continue;
    }
    receive_none_count = 0;

    for (int32_t i = 0; i < length; ++i) {
      uint8_t len = buf.at(i).len;
      uint32_t uid = buf.at(i).id;
      uint8_t* data = buf.at(i).data;
      struct timeval timestamp;
      timestamp.tv_sec = buf.at(i).timestamp.tv_sec;
      timestamp.tv_usec = buf.at(i).timestamp.tv_usec;
      pt_manager_->Parse(uid, data, len, timestamp);
      if (enable_log_) {
        ADEBUG << "recv_can_frame#" << buf.at(i).CanFrameString();
      }
    }
    std::this_thread::yield();
  }
  AINFO << "Can client receiver thread stopped.";
}

bool CanReceiver::IsRunning() const { return is_running_; }

ErrorCode CanReceiver::Start() {
  if (is_init_ == false) {
    return ErrorCode::CANBUS_ERROR;
  }
  is_running_ = true;

  thread_.reset(new std::thread([this] { RecvThreadFunc(); }));
  if (thread_ == nullptr) {
    AERROR << "Unable to create can client receiver thread.";
    return ErrorCode::CANBUS_ERROR;
  }
  return ErrorCode::OK;
}

void CanReceiver::Stop() {
  if (IsRunning()) {
    AINFO << "Stopping can client receiver ...";
    is_running_ = false;
    if (thread_ != nullptr && thread_->joinable()) {
      thread_->join();
    }
    thread_.reset();
  } else {
    AINFO << "Can client receiver is not running.";
  }
  AINFO << "Can client receiver stopped [ok].";
}

}  // namespace canbus
}  // namespace apollo
<commit_msg>Small code tweaks in can_receiver<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/canbus/can_comm/can_receiver.h"

#include <cmath>
#include <iostream>
#include <sstream>

#include "modules/canbus/common/canbus_consts.h"
#include "modules/common/log.h"

namespace apollo {
namespace canbus {

using ::apollo::common::ErrorCode;

ErrorCode CanReceiver::Init(CanClient* can_client, MessageManager* pt_manager,
                            bool enable_log) {
  can_client_ = can_client;
  pt_manager_ = pt_manager;
  enable_log_ = enable_log;
  if (can_client_ == nullptr) {
    AERROR << "Invalid can client.";
    return ErrorCode::CANBUS_ERROR;
  }
  if (pt_manager_ == nullptr) {
    AERROR << "Invalid protocol manager.";
    return ErrorCode::CANBUS_ERROR;
  }
  is_init_ = true;
  return ErrorCode::OK;
}

void CanReceiver::RecvThreadFunc() {
  AINFO << "Can client receiver thread starts.";
  CHECK_NOTNULL(can_client_);
  CHECK_NOTNULL(pt_manager_);

  int32_t receive_error_count = 0;
  int32_t receive_none_count = 0;
  const int32_t ERROR_COUNT_MAX = 10;
  std::chrono::duration<double, std::micro> default_period{10 * 1000};

  while (IsRunning()) {
    std::vector<CanFrame> buf;
    int32_t frame_num = MAX_CAN_RECV_FRAME_LEN;
    if (can_client_->Receive(&buf, &frame_num) != ErrorCode::OK) {
      LOG_IF_EVERY_N(ERROR, receive_error_count++ > ERROR_COUNT_MAX,
                     ERROR_COUNT_MAX)
          << "Received " << receive_error_count << " error messages.";
      std::this_thread::sleep_for(default_period);
      continue;
    }
    receive_error_count = 0;

    if (buf.size() != static_cast<size_t>(frame_num)) {
      AERROR << "Receiver buf size[" << buf.size()
             << "] does not match can_client returned length[" << frame_num
             << "].";
    }

    if (frame_num == 0) {
      LOG_IF_EVERY_N(ERROR, receive_none_count++ > ERROR_COUNT_MAX,
                     ERROR_COUNT_MAX)
          << "Received " << receive_none_count << " empty messages.";
      std::this_thread::sleep_for(default_period);
      continue;
    }
    receive_none_count = 0;

    for (const auto& frame : buf) {
      uint8_t len = frame.len;
      uint32_t uid = frame.id;
      const uint8_t* data = frame.data;
      struct timeval timestamp;
      timestamp.tv_sec = frame.timestamp.tv_sec;
      timestamp.tv_usec = frame.timestamp.tv_usec;
      pt_manager_->Parse(uid, data, len, timestamp);
      if (enable_log_) {
        ADEBUG << "recv_can_frame#" << frame.CanFrameString();
      }
    }
    std::this_thread::yield();
  }
  AINFO << "Can client receiver thread stopped.";
}

bool CanReceiver::IsRunning() const { return is_running_; }

ErrorCode CanReceiver::Start() {
  if (is_init_ == false) {
    return ErrorCode::CANBUS_ERROR;
  }
  is_running_ = true;

  thread_.reset(new std::thread([this] { RecvThreadFunc(); }));
  if (thread_ == nullptr) {
    AERROR << "Unable to create can client receiver thread.";
    return ErrorCode::CANBUS_ERROR;
  }
  return ErrorCode::OK;
}

void CanReceiver::Stop() {
  if (IsRunning()) {
    AINFO << "Stopping can client receiver ...";
    is_running_ = false;
    if (thread_ != nullptr && thread_->joinable()) {
      thread_->join();
    }
    thread_.reset();
  } else {
    AINFO << "Can client receiver is not running.";
  }
  AINFO << "Can client receiver stopped [ok].";
}

}  // namespace canbus
}  // namespace apollo
<|endoftext|>


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

#include "modules/common/adapters/adapter.h"

#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "modules/common/adapters/adapter_gflags.h"
#include "modules/localization/proto/localization.pb.h"

namespace apollo {
namespace common {
namespace adapter {

using IntegerAdapter = Adapter<int>;

TEST(AdapterTest, Empty) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  EXPECT_TRUE(adapter.Empty());
}

TEST(AdapterTest, Observe) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  adapter.OnReceive(173);

  // Before calling Observe.
  EXPECT_TRUE(adapter.Empty());

  // After calling Observe.
  adapter.Observe();
  EXPECT_FALSE(adapter.Empty());
}

TEST(AdapterTest, GetLatestObserved) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  adapter.OnReceive(173);

  adapter.Observe();
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(173, adapter.GetLatestObserved());

  adapter.OnReceive(5);
  adapter.OnReceive(7);
  // Before calling Observe() again.
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(173, adapter.GetLatestObserved());
  adapter.Observe();
  // After calling Observe() again.
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(7, adapter.GetLatestObserved());
}

TEST(AdapterTest, History) {
  IntegerAdapter adapter("Integer", "integer_topic", 3);
  adapter.OnReceive(1);
  adapter.OnReceive(2);

  adapter.Observe();
  {
    // Currently the history contains [2, 1].
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(2, history.size());
    EXPECT_EQ(2, *history[0]);
    EXPECT_EQ(1, *history[1]);
  }

  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(3);
  adapter.OnReceive(4);
  adapter.OnReceive(5);

  {
    // Although there are more messages, without calling Observe,
    // the history is still [2, 1].
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(2, history.size());
    EXPECT_EQ(2, *history[0]);
    EXPECT_EQ(1, *history[1]);
  }

  adapter.Observe();
  {
    // After calling Observe(), the history starts from 5. Since we only
    // maintain 3 elements in this adapter, 1 and 2 will be thrown out.
    //
    // History should be 5, 4, 3.
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(3, history.size());
    EXPECT_EQ(5, *history[0]);
    EXPECT_EQ(4, *history[1]);
    EXPECT_EQ(3, *history[2]);
  }
}

TEST(AdapterTest, Callback) {
  IntegerAdapter adapter("Integer", "integer_topic", 3);

  // Set the callback to act as a counter of messages.
  int count = 0;
  adapter.SetCallback([&count](int x) { count += x; });

  adapter.OnReceive(11);
  adapter.OnReceive(41);
  adapter.OnReceive(31);
  EXPECT_EQ(11 + 41 + 31, count);
}

using MyLocalizationAdapter = Adapter<localization::LocalizationEstimate>;

TEST(AdapterTest, Dump) {
  FLAGS_enable_adapter_dump = true;
  std::string temp_dir = std::getenv("TEST_TMPDIR");

  MyLocalizationAdapter adapter("local", "local_topic", 3, temp_dir);
  localization::LocalizationEstimate loaded;

  localization::LocalizationEstimate msg;

  msg.mutable_header()->set_sequence_num(17);
  adapter.OnReceive(msg);
  apollo::common::util::GetProtoFromASCIIFile(temp_dir + "/local/17.pb.txt",
                                              &loaded);
  EXPECT_EQ(17, loaded.header().sequence_num());

  msg.mutable_header()->set_sequence_num(23);
  adapter.OnReceive(msg);
  apollo::common::util::GetProtoFromASCIIFile(temp_dir + "/local/23.pb.txt",
                                              &loaded);
  EXPECT_EQ(23, loaded.header().sequence_num());
}

}  // namespace adapter
}  // namespace common
}  // namespace apollo
<commit_msg>Fix adapter_test. (#405)<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/common/adapters/adapter.h"

#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "modules/common/adapters/adapter_gflags.h"
#include "modules/localization/proto/localization.pb.h"

namespace apollo {
namespace common {
namespace adapter {

using IntegerAdapter = Adapter<int>;

TEST(AdapterTest, Empty) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  EXPECT_TRUE(adapter.Empty());
}

TEST(AdapterTest, Observe) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  adapter.OnReceive(173);

  // Before calling Observe.
  EXPECT_TRUE(adapter.Empty());

  // After calling Observe.
  adapter.Observe();
  EXPECT_FALSE(adapter.Empty());
}

TEST(AdapterTest, GetLatestObserved) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  adapter.OnReceive(173);

  adapter.Observe();
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(173, adapter.GetLatestObserved());

  adapter.OnReceive(5);
  adapter.OnReceive(7);
  // Before calling Observe() again.
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(173, adapter.GetLatestObserved());
  adapter.Observe();
  // After calling Observe() again.
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(7, adapter.GetLatestObserved());
}

TEST(AdapterTest, History) {
  IntegerAdapter adapter("Integer", "integer_topic", 3);
  adapter.OnReceive(1);
  adapter.OnReceive(2);

  adapter.Observe();
  {
    // Currently the history contains [2, 1].
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(2, history.size());
    EXPECT_EQ(2, *history[0]);
    EXPECT_EQ(1, *history[1]);
  }

  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(3);
  adapter.OnReceive(4);
  adapter.OnReceive(5);

  {
    // Although there are more messages, without calling Observe,
    // the history is still [2, 1].
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(2, history.size());
    EXPECT_EQ(2, *history[0]);
    EXPECT_EQ(1, *history[1]);
  }

  adapter.Observe();
  {
    // After calling Observe(), the history starts from 5. Since we only
    // maintain 3 elements in this adapter, 1 and 2 will be thrown out.
    //
    // History should be 5, 4, 3.
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(3, history.size());
    EXPECT_EQ(5, *history[0]);
    EXPECT_EQ(4, *history[1]);
    EXPECT_EQ(3, *history[2]);
  }
}

TEST(AdapterTest, Callback) {
  IntegerAdapter adapter("Integer", "integer_topic", 3);

  // Set the callback to act as a counter of messages.
  int count = 0;
  adapter.AddCallback([&count](int x) { count += x; });

  adapter.OnReceive(11);
  adapter.OnReceive(41);
  adapter.OnReceive(31);
  EXPECT_EQ(11 + 41 + 31, count);
}

using MyLocalizationAdapter = Adapter<localization::LocalizationEstimate>;

TEST(AdapterTest, Dump) {
  FLAGS_enable_adapter_dump = true;
  std::string temp_dir = std::getenv("TEST_TMPDIR");

  MyLocalizationAdapter adapter("local", "local_topic", 3, temp_dir);
  localization::LocalizationEstimate loaded;

  localization::LocalizationEstimate msg;

  msg.mutable_header()->set_sequence_num(17);
  adapter.OnReceive(msg);
  apollo::common::util::GetProtoFromASCIIFile(temp_dir + "/local/17.pb.txt",
                                              &loaded);
  EXPECT_EQ(17, loaded.header().sequence_num());

  msg.mutable_header()->set_sequence_num(23);
  adapter.OnReceive(msg);
  apollo::common::util::GetProtoFromASCIIFile(temp_dir + "/local/23.pb.txt",
                                              &loaded);
  EXPECT_EQ(23, loaded.header().sequence_num());
}

}  // namespace adapter
}  // namespace common
}  // namespace apollo
<|endoftext|>


<commit_before>#ifndef TCL_BUFFER_HPP
#define TCL_BUFFER_HPP

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL\cl.h>
#endif

#include <vector>
#include <array>
#include <mutex>
#include "CLInformation.hpp"

namespace tcl
{
	// CLExecuteŏzQƂĂ܂
	class CLExecute;

	/**
	* foCẌ̃bp[NX
	*/
	class CLBuffer
	{
	private:
		static CLExecute* exec;			// zQƂĂ܂̂Ń|C^ɂĂ
		static std::mutex execMutex;	// }`Xbh΍
		cl_mem memory;
		size_t size;

	public:
		/**
		* mۂeʂ擾
		* \return mۂe
		*/
		inline const size_t Size() const {
			return size;
		}

		/**
		* mۂIuWFNg擾
		* \return mۂIuWFNg
		*/
		inline cl_mem& Memory() {
			return memory;
		}

		cl_mem& operator() () {
			return memory;
		}

	private:
		/**
		* Rs[֎~
		*/
		CLBuffer(const CLBuffer& copy) { }

		template <typename T>
		void SizeTest(const size_t& size) const
		{
			auto argSize = size * sizeof(T);
			if (this->size < argSize)
			{
				throw CLFailedAllacException("obt@̃TCYzXg̃TCY̕傫");
			}
		}

		void ResultTest(const cl_int result) const
		{
			if (result != CL_SUCCESS)
			{
				throw CLException("WriteReadɎs܂", result);
			}
		}

		void ReadTest(const cl_uint result) const
		{
			if (result != CL_SUCCESS)
			{
				switch (result)
				{
				case CL_INVALID_COMMAND_QUEUE:
					throw CLException("R}hL[ł");
				case CL_INVALID_CONTEXT:
					throw CLException("ReNXgł");
				case CL_INVALID_MEM_OBJECT:
					throw CLException("obt@IuWFNgł");
				case CL_INVALID_VALUE:
					throw CLException("w肵ǂݍݗ̈悪͈͊Oł");
				case CL_INVALID_EVENT_WAIT_LIST:
					throw CLException("Cxg҂Xgł");
				case CL_MISALIGNED_SUB_BUFFER_OFFSET:
					throw CLException("Tuobt@̃ItZbgACgĂ܂");
				case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST:
					throw CLException("ǂݍ݃R}hubLOǂ");
				case CL_MEM_OBJECT_ALLOCATION_FAILURE:
					throw CLException("obt@Ɗ֘Atꂽf[^ۑ̈ւ̃mۂɎs");
				case CL_OUT_OF_RESOURCES:
					throw CLException("foCX̃\[X̊mۂɎs");
				case CL_OUT_OF_HOST_MEMORY:
					throw CLException("zXg̃\[X̊mۂɎs");
				}
			}
		}

		template <typename T>
		void SafeEnqueueRead(size_t size, T* data)
		{
			execMutex.lock();
			auto result = clEnqueueReadBuffer(
				exec->CommandQueue(), memory, CL_TRUE,
				0, size, &data,
				0, NULL, NULL);
			execMutex.unlock();
			ReadTest(result);
		}

		template <typename T>
		void SafeEnqueueWrite(size_t size, T* data)
		{
			execMutex.lock();
			auto result = clEnqueueWriteBuffer(
				exec->CommandQueue(), memory, CL_TRUE,
				0, size, data,
				0, NULL, NULL);
			execMutex.unlock();
			ResultTest(result);
		}

	protected:
		/**
		* ň̂͊댯Ȃ̂ŃftHgRXgN^͋֎~
		*/
		CLBuffer()
			: size(0) {}

		CLBuffer(const cl_mem_flags flag, const size_t size, void* hostPtr)
			: size(size)
		{
			memory = clCreateBuffer(information.context, flag, size, hostPtr, &information.result);
		}

	public:
		virtual ~CLBuffer()
		{
			clReleaseMemObject(memory);
		}

		/**
		* zXgfoCXɓ]
		*/
		template <typename T>
		CLBuffer& Write(const std::vector<T>& enqueueData)
		{
			SizeTest<T>(enqueueData.size());
			SafeEnqueueWrite(sizeof(T) * enqueueData.size(), &enqueueData[0]);
			return *this;
		}

		/**
		* zXgfoCXɓ]
		*/
		template <typename T, size_t NUM>
		CLBuffer& Write(const std::array<T, NUM>& enqueueData)
		{
			SizeTest<T>(enqueueData.size());
			SafeEnqueueWrite(sizeof(T) * enqueueData.size(), &enqueueData[0]);
			return *this;
		}

		/**
		* zXgfoCXɓ]
		* \attention z񓊂Ɨ܂
		*/
		template <typename T>
		CLBuffer& Write(const T& data)
		{
			SafeEnqueueWrite(sizeof(T), &data);
			return *this;
		}

		/**
		* zXgfoCXɓ]
		* \attention |C^zꍇ
		*/
		template <typename T>
		CLBuffer& Write(T* data, const size_t num)
		{
			SafeEnqueueWrite(sizeof(T) * num, data);
			return *this;
		}

		/**
		* foCXzXgɓ]
		*/
		template <typename T>
		CLBuffer& Read(std::vector<T>& dequeueData)
		{
			SizeTest<T>(dequeueData.size());
			SafeEnqueueRead(sizeof(T) * dequeueData.size(), &dequeueData[0]);
			return *this;
		}

		/**
		* foCXzXgɓ]
		*/
		template <typename T, size_t NUM>
		CLBuffer& Read(std::array<T, NUM>& dequeueData)
		{
			SizeTest<T>(dequeueData.size());
			SafeEnqueueRead(sizeof(T) * dequeueData.size(), &dequeueData[0]);
			return *this;
		}

		/**
		* foCXzXgɓ]
		* \attention z񓊂Ɨ܂
		*/
		template <typename T>
		CLBuffer& Read(T& data)
		{
			SafeEnqueueRead(sizeof(T), &data);
			return *this;
		}

		/**
		* foCXzXgɓ]
		* \attention |C^zꍇ
		*/
		template <typename T>
		CLBuffer& Read(T* data, const size_t num)
		{
			SafeEnqueueRead(sizeof(T) * num, data);
			return *this;
		}

		/**
		* obt@ΏۂƂexecutew
		* BufferNX̃CX^X𐶐OɕKv
		*/
		static void SetCurrentExecute(CLExecute* exec)
		{
			CLBuffer::exec = exec;
		}
	};

	CLExecute* CLBuffer::exec = nullptr;
	std::mutex CLBuffer::execMutex;
}

#endif<commit_msg>間違えてvoid**を渡してた<commit_after>#ifndef TCL_BUFFER_HPP
#define TCL_BUFFER_HPP

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL\cl.h>
#endif

#include <vector>
#include <array>
#include <mutex>
#include "CLInformation.hpp"

namespace tcl
{
	// CLExecuteŏzQƂĂ܂
	class CLExecute;

	/**
	* foCẌ̃bp[NX
	*/
	class CLBuffer
	{
	private:
		static CLExecute* exec;			// zQƂĂ܂̂Ń|C^ɂĂ
		static std::mutex execMutex;	// }`Xbh΍
		cl_mem memory;
		size_t size;

	public:
		/**
		* mۂeʂ擾
		* \return mۂe
		*/
		inline const size_t Size() const {
			return size;
		}

		/**
		* mۂIuWFNg擾
		* \return mۂIuWFNg
		*/
		inline cl_mem& Memory() {
			return memory;
		}

		cl_mem& operator() () {
			return memory;
		}

	private:
		/**
		* Rs[֎~
		*/
		CLBuffer(const CLBuffer& copy) { }

		template <typename T>
		void SizeTest(const size_t& size) const
		{
			auto argSize = size * sizeof(T);
			if (this->size < argSize)
			{
				throw CLFailedAllacException("obt@̃TCYzXg̃TCY̕傫");
			}
		}

		void ResultTest(const cl_int result) const
		{
			if (result != CL_SUCCESS)
			{
				throw CLException("WriteReadɎs܂", result);
			}
		}

		void ReadTest(const cl_uint result) const
		{
			if (result != CL_SUCCESS)
			{
				switch (result)
				{
				case CL_INVALID_COMMAND_QUEUE:
					throw CLException("R}hL[ł");
				case CL_INVALID_CONTEXT:
					throw CLException("ReNXgł");
				case CL_INVALID_MEM_OBJECT:
					throw CLException("obt@IuWFNgł");
				case CL_INVALID_VALUE:
					throw CLException("w肵ǂݍݗ̈悪͈͊Oł");
				case CL_INVALID_EVENT_WAIT_LIST:
					throw CLException("Cxg҂Xgł");
				case CL_MISALIGNED_SUB_BUFFER_OFFSET:
					throw CLException("Tuobt@̃ItZbgACgĂ܂");
				case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST:
					throw CLException("ǂݍ݃R}hubLOǂ");
				case CL_MEM_OBJECT_ALLOCATION_FAILURE:
					throw CLException("obt@Ɗ֘Atꂽf[^ۑ̈ւ̃mۂɎs");
				case CL_OUT_OF_RESOURCES:
					throw CLException("foCX̃\[X̊mۂɎs");
				case CL_OUT_OF_HOST_MEMORY:
					throw CLException("zXg̃\[X̊mۂɎs");
				}
			}
		}

		template <typename T>
		void SafeEnqueueRead(size_t size, T* data)
		{
			execMutex.lock();
			auto result = clEnqueueReadBuffer(
				exec->CommandQueue(), memory, CL_TRUE,
				0, size, data,
				0, NULL, NULL);
			execMutex.unlock();
			ReadTest(result);
		}

		template <typename T>
		void SafeEnqueueWrite(size_t size, T* data)
		{
			execMutex.lock();
			auto result = clEnqueueWriteBuffer(
				exec->CommandQueue(), memory, CL_TRUE,
				0, size, data,
				0, NULL, NULL);
			execMutex.unlock();
			ResultTest(result);
		}

	protected:
		/**
		* ň̂͊댯Ȃ̂ŃftHgRXgN^͋֎~
		*/
		CLBuffer()
			: size(0) {}

		CLBuffer(const cl_mem_flags flag, const size_t size, void* hostPtr)
			: size(size)
		{
			memory = clCreateBuffer(information.context, flag, size, hostPtr, &information.result);
		}

	public:
		virtual ~CLBuffer()
		{
			clReleaseMemObject(memory);
		}

		/**
		* zXgfoCXɓ]
		*/
		template <typename T>
		CLBuffer& Write(const std::vector<T>& enqueueData)
		{
			SizeTest<T>(enqueueData.size());
			SafeEnqueueWrite(sizeof(T) * enqueueData.size(), &enqueueData[0]);
			return *this;
		}

		/**
		* zXgfoCXɓ]
		*/
		template <typename T, size_t NUM>
		CLBuffer& Write(const std::array<T, NUM>& enqueueData)
		{
			SizeTest<T>(enqueueData.size());
			SafeEnqueueWrite(sizeof(T) * enqueueData.size(), &enqueueData[0]);
			return *this;
		}

		/**
		* zXgfoCXɓ]
		* \attention z񓊂Ɨ܂
		*/
		template <typename T>
		CLBuffer& Write(const T& data)
		{
			SafeEnqueueWrite(sizeof(T), &data);
			return *this;
		}

		/**
		* zXgfoCXɓ]
		* \attention |C^zꍇ
		*/
		template <typename T>
		CLBuffer& Write(T* data, const size_t num)
		{
			SafeEnqueueWrite(sizeof(T) * num, data);
			return *this;
		}

		/**
		* foCXzXgɓ]
		*/
		template <typename T>
		CLBuffer& Read(std::vector<T>& dequeueData)
		{
			SizeTest<T>(dequeueData.size());
			SafeEnqueueRead(sizeof(T) * dequeueData.size(), &dequeueData[0]);
			return *this;
		}

		/**
		* foCXzXgɓ]
		*/
		template <typename T, size_t NUM>
		CLBuffer& Read(std::array<T, NUM>& dequeueData)
		{
			SizeTest<T>(dequeueData.size());
			SafeEnqueueRead(sizeof(T) * dequeueData.size(), &dequeueData[0]);
			return *this;
		}

		/**
		* foCXzXgɓ]
		* \attention z񓊂Ɨ܂
		*/
		template <typename T>
		CLBuffer& Read(T& data)
		{
			SafeEnqueueRead(sizeof(T), &data);
			return *this;
		}

		/**
		* foCXzXgɓ]
		* \attention |C^zꍇ
		*/
		template <typename T>
		CLBuffer& Read(T* data, const size_t num)
		{
			SafeEnqueueRead(sizeof(T) * num, data);
			return *this;
		}

		/**
		* obt@ΏۂƂexecutew
		* BufferNX̃CX^X𐶐OɕKv
		*/
		static void SetCurrentExecute(CLExecute* exec)
		{
			CLBuffer::exec = exec;
		}
	};

	CLExecute* CLBuffer::exec = nullptr;
	std::mutex CLBuffer::execMutex;
}

#endif<|endoftext|>


<commit_before>#include "DVBTable.h"
#include "ProgramAssociationTable.h"
#include "ProgramMapTable.h"
#include "ServiceDescriptionTable.h"
#include "NetworkInformationTable.h"
#include "Util.h"
#include <iostream>
#include <cstring>
#include <cassert>
#include <cxxabi.h>

extern "C" {
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
}

using namespace std;

DVBTable *DVBTable::read(int fd) {
	DVBTable *t=new DVBTable(fd);
	switch(t->tableId()) {
	case ProgramAssociation:
		return new ProgramAssociationTable(t);
	case ProgramMap:
		return new ProgramMapTable(t);
	case ServiceDescription:
	case ServiceDescriptionOther:
		return new ServiceDescriptionTable(t);
	case NetworkInformation:
	case NetworkInformationOther:
		return new NetworkInformationTable(t);
	case Invalid:
		std::cerr << "Received Invalid table" << std::endl;
		delete t;
		return nullptr;
	default:
		std::cerr << "Received table with unknown id " << static_cast<int>(t->tableId()) << std::endl;
	}
	return t;
}

DVBTable::DVBTable(int fd):_data(nullptr) {
	ssize_t count;
	unsigned char header[8];
	do {
		if(!Util::waitForData(fd)) {
			_tableId = Invalid;
			return;
		}
		count = ::read(fd, header, sizeof(header));
		if(count != sizeof(header)) {
			std::cerr << "Incomplete packet, got " << count << ", expected at least " << sizeof(header) << " from " << fd << std::endl;
			if(count<0)
				std::cerr << strerror(errno) << std::endl;
			ioctl(fd, DMX_STOP);
			sleep(1);
			ioctl(fd, DMX_START);
			continue;
		}
		_tableId = header[0];
		_sectionSyntaxIndicator = (header[1]&0b10000000)>>7;
		_private = (header[1]&0b01000000)>>6;
		// The next 12 bits are the section length (number of
		// following bytes including CRC). We change it to
		// data length by subtracting the CRC and the rest of
		// the header...
		_dataLength = (((header[1]&0xf)<<8)|header[2]);
		if(_dataLength < 9) {
			std::cerr << "Length smaller than header+CRC" << std::endl;
			ioctl(fd, DMX_STOP);
			sleep(1);
			ioctl(fd, DMX_START);
			continue;
		}
		_dataLength -= 9;
		_number = (header[3]<<8)|header[4];
		_version = (header[5]&0b00111110)>>1;
		_currentNext = header[5]&1;
		_section = header[6];
		_lastSection = header[7];
		_data = new unsigned char[_dataLength];
		count = ::read(fd, _data, _dataLength);
		if(count != _dataLength) {
			std::cerr << "Got unexpected data: Expected " << _dataLength << " bytes, got " << count << std::endl;
			ioctl(fd, DMX_STOP);
			sleep(1);
			ioctl(fd, DMX_START);
			continue;
		}
		count = ::read(fd, &_crc, 4);
		if(count != 4) {
			std::cerr << "Incomplete CRC" << std::endl;
			ioctl(fd, DMX_STOP);
			sleep(1);
			ioctl(fd, DMX_START);
			continue;
		}
	} while(count != 4);
	_crc = ntohl(_crc);
	_calculatedCrc = Util::crc32(header, sizeof(header));
	_calculatedCrc = Util::crc32(_data, _dataLength, _calculatedCrc);
	if(_crc != _calculatedCrc) {
		Util::SaveIOState sis(std::cerr);
		std::cerr << "CRC mismatch! Given: " << hex << _crc << ", calculated: " << _calculatedCrc << std::endl;
	}
}

DVBTable::DVBTable(DVBTable *t):
	_tableId(std::move(t->_tableId)),
	_sectionSyntaxIndicator(std::move(t->_sectionSyntaxIndicator)),
	_private(std::move(t->_private)),
	_dataLength(std::move(t->_dataLength)),
	_number(std::move(t->_number)),
	_version(std::move(t->_version)),
	_currentNext(std::move(t->_currentNext)),
	_section(std::move(t->_section)),
	_lastSection(std::move(t->_lastSection)),
	_data(std::move(t->_data)),
	_crc(std::move(t->_crc)),
	_calculatedCrc(std::move(t->_calculatedCrc))
{
	t->_data = nullptr;
	delete t;
}

bool DVBTable::ok() const {
	return _sectionSyntaxIndicator && (_crc == _calculatedCrc);
}

DVBTable::~DVBTable() {
	if(_data)
		delete[] _data;
}

void DVBTable::dump(std::ostream &where, std::string const &indent) const {
	where << indent << "DVB Table type " << static_cast<int>(_tableId) << std::endl;
	where << indent << "Section " << static_cast<int>(_section) << "/" << static_cast<int>(_lastSection) << std::endl;
	if(_data)
		Util::hexdump(_data, _dataLength, where, indent);
}
<commit_msg>better debug output<commit_after>#include "DVBTable.h"
#include "ProgramAssociationTable.h"
#include "ProgramMapTable.h"
#include "ServiceDescriptionTable.h"
#include "NetworkInformationTable.h"
#include "Util.h"
#include <iostream>
#include <cstring>
#include <cassert>
#include <cxxabi.h>

extern "C" {
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
}

using namespace std;

DVBTable *DVBTable::read(int fd) {
	DVBTable *t=new DVBTable(fd);
	switch(t->tableId()) {
	case ProgramAssociation:
		return new ProgramAssociationTable(t);
	case ProgramMap:
		return new ProgramMapTable(t);
	case ServiceDescription:
	case ServiceDescriptionOther:
		return new ServiceDescriptionTable(t);
	case NetworkInformation:
	case NetworkInformationOther:
		return new NetworkInformationTable(t);
	case Invalid:
		std::cerr << "Received Invalid table" << std::endl;
		delete t;
		return nullptr;
	default:
		std::cerr << "Received table with unknown id " << static_cast<int>(t->tableId()) << std::endl;
	}
	return t;
}

DVBTable::DVBTable(int fd):_data(nullptr) {
	ssize_t count;
	unsigned char header[8];
	do {
		if(!Util::waitForData(fd)) {
			_tableId = Invalid;
			return;
		}
		count = ::read(fd, header, sizeof(header));
		if(count != sizeof(header)) {
			std::cerr << "Incomplete packet, got " << count << ", expected at least " << sizeof(header) << " from " << fd << std::endl;
			if(count<0)
				std::cerr << strerror(errno) << std::endl;
			ioctl(fd, DMX_STOP);
			sleep(1);
			ioctl(fd, DMX_START);
			continue;
		}
		_tableId = header[0];
		_sectionSyntaxIndicator = (header[1]&0b10000000)>>7;
		_private = (header[1]&0b01000000)>>6;
		// The next 12 bits are the section length (number of
		// following bytes including CRC). We change it to
		// data length by subtracting the CRC and the rest of
		// the header...
		_dataLength = (((header[1]&0xf)<<8)|header[2]);
		if(_dataLength < 9) {
			std::cerr << "Length smaller than header+CRC" << std::endl;
			ioctl(fd, DMX_STOP);
			sleep(1);
			ioctl(fd, DMX_START);
			continue;
		}
		_dataLength -= 9;
		_number = (header[3]<<8)|header[4];
		_version = (header[5]&0b00111110)>>1;
		_currentNext = header[5]&1;
		_section = header[6];
		_lastSection = header[7];
		_data = new unsigned char[_dataLength];
		count = ::read(fd, _data, _dataLength);
		if(count != _dataLength) {
			std::cerr << "Got unexpected data: Expected " << _dataLength << " bytes, got " << count << std::endl;
			ioctl(fd, DMX_STOP);
			sleep(1);
			ioctl(fd, DMX_START);
			continue;
		}
		count = ::read(fd, &_crc, 4);
		if(count != 4) {
			std::cerr << "Incomplete CRC" << std::endl;
			ioctl(fd, DMX_STOP);
			sleep(1);
			ioctl(fd, DMX_START);
			continue;
		}
	} while(count != 4);
	_crc = ntohl(_crc);
	_calculatedCrc = Util::crc32(header, sizeof(header));
	_calculatedCrc = Util::crc32(_data, _dataLength, _calculatedCrc);
	if(_crc != _calculatedCrc) {
		Util::SaveIOState sis(std::cerr);
		std::cerr << "CRC mismatch! Given: " << hex << _crc << ", calculated: " << _calculatedCrc << std::endl;
	}
}

DVBTable::DVBTable(DVBTable *t):
	_tableId(std::move(t->_tableId)),
	_sectionSyntaxIndicator(std::move(t->_sectionSyntaxIndicator)),
	_private(std::move(t->_private)),
	_dataLength(std::move(t->_dataLength)),
	_number(std::move(t->_number)),
	_version(std::move(t->_version)),
	_currentNext(std::move(t->_currentNext)),
	_section(std::move(t->_section)),
	_lastSection(std::move(t->_lastSection)),
	_data(std::move(t->_data)),
	_crc(std::move(t->_crc)),
	_calculatedCrc(std::move(t->_calculatedCrc))
{
	t->_data = nullptr;
	delete t;
}

bool DVBTable::ok() const {
	return _sectionSyntaxIndicator && (_crc == _calculatedCrc);
}

DVBTable::~DVBTable() {
	if(_data)
		delete[] _data;
}

void DVBTable::dump(std::ostream &where, std::string const &indent) const {
	Util::SaveIOState ios(where);
	where << indent << "DVB Table type " << hex << static_cast<int>(_tableId) << std::endl;
	where << indent << "Section " << dec << static_cast<int>(_section) << "/" << static_cast<int>(_lastSection) << std::endl;
	if(_data)
		Util::hexdump(_data, _dataLength, where, indent);
}
<|endoftext|>


<commit_before>//===- PDB.cpp ------------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "PDB.h"
#include "Chunks.h"
#include "Config.h"
#include "Error.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include <memory>

using namespace lld;
using namespace lld::coff;
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::support;
using namespace llvm::support::endian;

using llvm::object::coff_section;

static ExitOnError ExitOnErr;

// Returns a list of all SectionChunks.
static std::vector<coff_section> getInputSections(SymbolTable *Symtab) {
  std::vector<coff_section> V;
  for (Chunk *C : Symtab->getChunks())
    if (auto *SC = dyn_cast<SectionChunk>(C))
      V.push_back(*SC->Header);
  return V;
}

static SectionChunk *findByName(std::vector<SectionChunk *> &Sections,
                                StringRef Name) {
  for (SectionChunk *C : Sections)
    if (C->getSectionName() == Name)
      return C;
  return nullptr;
}

static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
  SectionChunk *Sec = findByName(File->getDebugChunks(), SecName);
  if (!Sec)
    return {};

  // First 4 bytes are section magic.
  ArrayRef<uint8_t> Data = Sec->getContents();
  if (Data.size() < 4)
    fatal(SecName + " too short");
  if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
    fatal(SecName + " has an invalid magic");
  return Data.slice(4);
}

static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
                        codeview::TypeTableBuilder &TypeTable) {
  // Start the TPI or IPI stream header.
  TpiBuilder.setVersionHeader(pdb::PdbTpiV80);

  // Flatten the in memory type table.
  TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
    // FIXME: Hash types.
    TpiBuilder.addTypeRecord(Rec, None);
  });
}

// Merge .debug$T sections into IpiData and TpiData.
static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder,
                        codeview::TypeTableBuilder &TypeTable,
                        codeview::TypeTableBuilder &IDTable) {
  // Visit all .debug$T sections to add them to Builder.
  for (ObjectFile *File : Symtab->ObjectFiles) {
    ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
    if (Data.empty())
      continue;

    BinaryByteStream Stream(Data, support::little);
    codeview::CVTypeArray Types;
    BinaryStreamReader Reader(Stream);
    // Follow type servers.  If the same type server is encountered more than
    // once for this instance of `PDBTypeServerHandler` (for example if many
    // object files reference the same TypeServer), the types from the
    // TypeServer will only be visited once.
    pdb::PDBTypeServerHandler Handler;
    Handler.addSearchPath(llvm::sys::path::parent_path(File->getName()));
    if (auto EC = Reader.readArray(Types, Reader.getLength()))
      fatal(EC, "Reader::readArray failed");
    if (auto Err =
            codeview::mergeTypeStreams(IDTable, TypeTable, &Handler, Types))
      fatal(Err, "codeview::mergeTypeStreams failed");
  }

  // Construct TPI stream contents.
  addTypeInfo(Builder.getTpiBuilder(), TypeTable);

  // Construct IPI stream contents.
  addTypeInfo(Builder.getIpiBuilder(), IDTable);
}

static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugT");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
  if (Data.empty())
    return;

  TypeDatabase TDB;
  TypeDumpVisitor TDV(TDB, &W, false);
  // Use a default implementation that does not follow type servers and instead
  // just dumps the contents of the TypeServer2 record.
  CVTypeDumper TypeDumper(TDB);
  if (auto EC = TypeDumper.dump(Data, TDV))
    fatal(EC, "CVTypeDumper::dump failed");
}

static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugS");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$S");
  if (Data.empty())
    return;

  BinaryByteStream Stream(Data, llvm::support::little);
  CVSymbolArray Symbols;
  BinaryStreamReader Reader(Stream);
  if (auto EC = Reader.readArray(Symbols, Reader.getLength()))
    fatal(EC, "StreamReader.readArray<CVSymbolArray> failed");

  TypeDatabase TDB;
  CVSymbolDumper SymbolDumper(W, TDB, nullptr, false);
  if (auto EC = SymbolDumper.dump(Symbols))
    fatal(EC, "CVSymbolDumper::dump failed");
}

// Dump CodeView debug info. This is for debugging.
static void dumpCodeView(SymbolTable *Symtab) {
  ScopedPrinter W(outs());

  for (ObjectFile *File : Symtab->ObjectFiles) {
    dumpDebugT(W, File);
    dumpDebugS(W, File);
  }
}

// Creates a PDB file.
void coff::createPDB(StringRef Path, SymbolTable *Symtab,
                     ArrayRef<uint8_t> SectionTable,
                     const llvm::codeview::DebugInfo *DI) {
  if (Config->DumpPdb)
    dumpCodeView(Symtab);

  BumpPtrAllocator Alloc;
  pdb::PDBFileBuilder Builder(Alloc);
  ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize

  // Create streams in MSF for predefined streams, namely
  // PDB, TPI, DBI and IPI.
  for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I)
    ExitOnErr(Builder.getMsfBuilder().addStream(0));

  // Add an Info stream.
  auto &InfoBuilder = Builder.getInfoBuilder();
  InfoBuilder.setAge(DI ? DI->PDB70.Age : 0);

  pdb::PDB_UniqueId uuid{};
  if (DI)
    memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid));
  InfoBuilder.setGuid(uuid);
  // Should be the current time, but set 0 for reproducibilty.
  InfoBuilder.setSignature(0);
  InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);

  // Add an empty DPI stream.
  auto &DbiBuilder = Builder.getDbiBuilder();
  DbiBuilder.setVersionHeader(pdb::PdbDbiV110);

  codeview::TypeTableBuilder TypeTable(BAlloc);
  codeview::TypeTableBuilder IDTable(BAlloc);
  mergeDebugT(Symtab, Builder, TypeTable, IDTable);

  // Add Section Contributions.
  std::vector<pdb::SectionContrib> Contribs =
      pdb::DbiStreamBuilder::createSectionContribs(getInputSections(Symtab));
  DbiBuilder.setSectionContribs(Contribs);

  // Add Section Map stream.
  ArrayRef<object::coff_section> Sections = {
      (const object::coff_section *)SectionTable.data(),
      SectionTable.size() / sizeof(object::coff_section)};
  std::vector<pdb::SecMapEntry> SectionMap =
      pdb::DbiStreamBuilder::createSectionMap(Sections);
  DbiBuilder.setSectionMap(SectionMap);

  ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));

  // Add COFF section header stream.
  ExitOnErr(
      DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));

  // Write to a file.
  ExitOnErr(Builder.commit(Path));
}
<commit_msg>Rename pdb::StringTable -> pdb::PDBStringTable.<commit_after>//===- PDB.cpp ------------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "PDB.h"
#include "Chunks.h"
#include "Config.h"
#include "Error.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include <memory>

using namespace lld;
using namespace lld::coff;
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::support;
using namespace llvm::support::endian;

using llvm::object::coff_section;

static ExitOnError ExitOnErr;

// Returns a list of all SectionChunks.
static std::vector<coff_section> getInputSections(SymbolTable *Symtab) {
  std::vector<coff_section> V;
  for (Chunk *C : Symtab->getChunks())
    if (auto *SC = dyn_cast<SectionChunk>(C))
      V.push_back(*SC->Header);
  return V;
}

static SectionChunk *findByName(std::vector<SectionChunk *> &Sections,
                                StringRef Name) {
  for (SectionChunk *C : Sections)
    if (C->getSectionName() == Name)
      return C;
  return nullptr;
}

static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
  SectionChunk *Sec = findByName(File->getDebugChunks(), SecName);
  if (!Sec)
    return {};

  // First 4 bytes are section magic.
  ArrayRef<uint8_t> Data = Sec->getContents();
  if (Data.size() < 4)
    fatal(SecName + " too short");
  if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
    fatal(SecName + " has an invalid magic");
  return Data.slice(4);
}

static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
                        codeview::TypeTableBuilder &TypeTable) {
  // Start the TPI or IPI stream header.
  TpiBuilder.setVersionHeader(pdb::PdbTpiV80);

  // Flatten the in memory type table.
  TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
    // FIXME: Hash types.
    TpiBuilder.addTypeRecord(Rec, None);
  });
}

// Merge .debug$T sections into IpiData and TpiData.
static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder,
                        codeview::TypeTableBuilder &TypeTable,
                        codeview::TypeTableBuilder &IDTable) {
  // Visit all .debug$T sections to add them to Builder.
  for (ObjectFile *File : Symtab->ObjectFiles) {
    ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
    if (Data.empty())
      continue;

    BinaryByteStream Stream(Data, support::little);
    codeview::CVTypeArray Types;
    BinaryStreamReader Reader(Stream);
    // Follow type servers.  If the same type server is encountered more than
    // once for this instance of `PDBTypeServerHandler` (for example if many
    // object files reference the same TypeServer), the types from the
    // TypeServer will only be visited once.
    pdb::PDBTypeServerHandler Handler;
    Handler.addSearchPath(llvm::sys::path::parent_path(File->getName()));
    if (auto EC = Reader.readArray(Types, Reader.getLength()))
      fatal(EC, "Reader::readArray failed");
    if (auto Err =
            codeview::mergeTypeStreams(IDTable, TypeTable, &Handler, Types))
      fatal(Err, "codeview::mergeTypeStreams failed");
  }

  // Construct TPI stream contents.
  addTypeInfo(Builder.getTpiBuilder(), TypeTable);

  // Construct IPI stream contents.
  addTypeInfo(Builder.getIpiBuilder(), IDTable);
}

static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugT");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
  if (Data.empty())
    return;

  TypeDatabase TDB;
  TypeDumpVisitor TDV(TDB, &W, false);
  // Use a default implementation that does not follow type servers and instead
  // just dumps the contents of the TypeServer2 record.
  CVTypeDumper TypeDumper(TDB);
  if (auto EC = TypeDumper.dump(Data, TDV))
    fatal(EC, "CVTypeDumper::dump failed");
}

static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugS");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$S");
  if (Data.empty())
    return;

  BinaryByteStream Stream(Data, llvm::support::little);
  CVSymbolArray Symbols;
  BinaryStreamReader Reader(Stream);
  if (auto EC = Reader.readArray(Symbols, Reader.getLength()))
    fatal(EC, "StreamReader.readArray<CVSymbolArray> failed");

  TypeDatabase TDB;
  CVSymbolDumper SymbolDumper(W, TDB, nullptr, false);
  if (auto EC = SymbolDumper.dump(Symbols))
    fatal(EC, "CVSymbolDumper::dump failed");
}

// Dump CodeView debug info. This is for debugging.
static void dumpCodeView(SymbolTable *Symtab) {
  ScopedPrinter W(outs());

  for (ObjectFile *File : Symtab->ObjectFiles) {
    dumpDebugT(W, File);
    dumpDebugS(W, File);
  }
}

// Creates a PDB file.
void coff::createPDB(StringRef Path, SymbolTable *Symtab,
                     ArrayRef<uint8_t> SectionTable,
                     const llvm::codeview::DebugInfo *DI) {
  if (Config->DumpPdb)
    dumpCodeView(Symtab);

  BumpPtrAllocator Alloc;
  pdb::PDBFileBuilder Builder(Alloc);
  ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize

  // Create streams in MSF for predefined streams, namely
  // PDB, TPI, DBI and IPI.
  for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I)
    ExitOnErr(Builder.getMsfBuilder().addStream(0));

  // Add an Info stream.
  auto &InfoBuilder = Builder.getInfoBuilder();
  InfoBuilder.setAge(DI ? DI->PDB70.Age : 0);

  pdb::PDB_UniqueId uuid{};
  if (DI)
    memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid));
  InfoBuilder.setGuid(uuid);
  // Should be the current time, but set 0 for reproducibilty.
  InfoBuilder.setSignature(0);
  InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);

  // Add an empty DPI stream.
  auto &DbiBuilder = Builder.getDbiBuilder();
  DbiBuilder.setVersionHeader(pdb::PdbDbiV110);

  codeview::TypeTableBuilder TypeTable(BAlloc);
  codeview::TypeTableBuilder IDTable(BAlloc);
  mergeDebugT(Symtab, Builder, TypeTable, IDTable);

  // Add Section Contributions.
  std::vector<pdb::SectionContrib> Contribs =
      pdb::DbiStreamBuilder::createSectionContribs(getInputSections(Symtab));
  DbiBuilder.setSectionContribs(Contribs);

  // Add Section Map stream.
  ArrayRef<object::coff_section> Sections = {
      (const object::coff_section *)SectionTable.data(),
      SectionTable.size() / sizeof(object::coff_section)};
  std::vector<pdb::SecMapEntry> SectionMap =
      pdb::DbiStreamBuilder::createSectionMap(Sections);
  DbiBuilder.setSectionMap(SectionMap);

  ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));

  // Add COFF section header stream.
  ExitOnErr(
      DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));

  // Write to a file.
  ExitOnErr(Builder.commit(Path));
}
<|endoftext|>


<commit_before>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * File:   Director.cpp
 * Author: interloper
 *
 * Created on May 29, 2016, 4:11 PM
 */

#include "Director.h"

Director* Director::instance = NULL;

Director::Director()
{
    m_running = false;

    m_windows = NULL;

    m_default_font = NULL;

    m_input_handler = NULL;
}

Director::~Director()
{
    //stuff
}

Director* Director::getInstance()
{
    if(instance == NULL)
        instance = new Director;

    return instance;
}

void Director::quit()
{
    m_running = false;
}

bool Director::isRunning()
{
    return m_running;
}

void Director::cleanUp()
{
    delete m_windows;

    delete m_input_handler;

    IMG_Quit();

    //TTF_Quit():?????

    SDL_Quit();
}

bool Director::initSDL()
{
    if(SDL_Init(SDL_INIT_VIDEO) != 0)// error initializing SDL
    {
        std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
        return false;
    }

    m_windows = new WindowWrapper("RPG Battle",
                                  WINDOW_X, WINDOW_Y,
                                  WINDOW_W, WINDOW_H,
                                  SDL_WINDOW_SHOWN
                                 );

    if(m_windows->errorsExist())
        return false;

    int img_flags = IMG_INIT_PNG;
    if(IMG_Init(img_flags) & img_flags)
         m_surface = SDL_GetWindowSurface(m_windows->getWindow());
    else
    {
        std::cerr << "IMG_Init error: " << SDL_GetError() << std::endl;
        return false;
    }

    if(TTF_Init() == -1)
    {
        std::cerr << "TTF_Init error: " << SDL_GetError() << std::endl;
        return false;
    }

    return true;
}

bool Director::init()
{
    if(!initSDL())
    return (m_running = false);

    m_input_handler = new InputHandler;

    setupDefaultFont();

    setupCursor();

    return (m_running = true);
}

void Director::setupDefaultFont()
{
    m_default_font = TTF_OpenFont(DEFAULT_FONT.c_str(), 90);
}

void Director::setupCursor()
{
    SDL_ShowCursor(SDL_DISABLE);

    addNode(Cursor::getInstance());
}

void Director::handleEvents()
{
    SDL_Event e;

    while(SDL_PollEvent(&e) != 0)
    {
        if(e.type == SDL_QUIT)
            quit();
        else if (e.type == SDL_MOUSEMOTION)
        {
            int x = e.motion.x;
            int y = e.motion.y;
            Cursor::getInstance()->setPosition(Vec2<double>(x, y));
        }
        else if(e.type == SDL_KEYDOWN)
        {
            switch(e.key.keysym.sym)
            {
                case SDLK_UP:     m_input_handler->pressKey(KEY_UP);    break;
                case SDLK_RIGHT:  m_input_handler->pressKey(KEY_RIGHT); break;
                case SDLK_DOWN:   m_input_handler->pressKey(KEY_DOWN);  break;
                case SDLK_LEFT:   m_input_handler->pressKey(KEY_LEFT);  break;
                case SDLK_SPACE:  m_input_handler->pressKey(KEY_SPACE); break;
                //case SDLK_RETURN: m_input_handler->pressKey(KEY_ENTER); break;
                //case SDLK_z:      m_input_handler->pressKey(KEY_z);     break;
                //case SDLK_x:      m_input_handler->pressKey(KEY_x);     break;
            }
        }
        else if(e.type == SDL_KEYUP)
        {
            switch(e.key.keysym.sym)
            {
                case SDLK_UP:     m_input_handler->releaseKey(KEY_UP);    break;
                case SDLK_RIGHT:  m_input_handler->releaseKey(KEY_RIGHT); break;
                case SDLK_DOWN:   m_input_handler->releaseKey(KEY_DOWN);  break;
                case SDLK_LEFT:   m_input_handler->releaseKey(KEY_LEFT);  break;
                case SDLK_SPACE:  m_input_handler->releaseKey(KEY_SPACE); break;
                //case SDLK_RETURN: m_input_handler->releaseKey(KEY_ENTER); break;
                //case SDLK_z:      m_input_handler->releaseKey(KEY_z);     break;
                //case SDLK_x:      m_input_handler->releaseKey(KEY_x);     break;
            }
        }
    }
}

void Director::resetInput()
{
    m_input_handler->resetInput();
}

bool Director::getKey(int p_key)
{
    return m_input_handler->getKey(p_key);
}

void Director::resetKey(int p_key)
{
    m_input_handler->resetKey(p_key);
}

/*TTF_Font* Director::getDefaultFont()
{
    return m_default_font;
}*/

void Director::addNode(Sprite* pSprite)
{
    p_nodes.push_back(pSprite);

    // Create textures if needed
    if(pSprite->getSpritePath() != "")
        Director::getInstance()->assignTexture(pSprite);
}

void Director::deleteNode(Sprite* pSprite)
{
    int id = pSprite->getId();
    for(std::vector<Node*>::iterator it = p_nodes.begin(); it != p_nodes.end(); it++)
    {
        if((*it)->getId() == id)
        {
            delete (*it);
            it = p_nodes.erase(it);
            break;
        }
    }
}

SDL_Texture* Director::createTexture(Sprite* p_sprite)
{
    // find loaded texture
    std::map<std::string, SDL_Texture*>::iterator it = m_loaded_textures.find(p_sprite->getSpritePath());
    if (it != m_loaded_textures.end())
        return it->second;

    //load new texture
    SDL_Surface* temp_surface = IMG_Load(p_sprite->getSpritePath().c_str());
    SDL_Texture* temp_texture = SDL_CreateTextureFromSurface(m_windows->getRenderer(), temp_surface);

    // free surface
    SDL_FreeSurface(temp_surface);

    // store new texture
    m_loaded_textures[p_sprite->getSpritePath()] = temp_texture;

    return temp_texture;
}

void Director::assignTexture(Sprite* pSprite)
{
    pSprite->setTexture(createTexture(pSprite));
}

SDL_Texture* Director::createTexture(Label* p_label)
{
    SDL_Surface* temp_surface = TTF_RenderText_Blended(p_label->getFont(), p_label->getText().c_str(), p_label->getColor());
    SDL_Texture* temp_texture = SDL_CreateTextureFromSurface(m_windows->getRenderer(), temp_surface);

    SDL_QueryTexture(temp_texture, NULL, NULL, NULL, NULL);

    SDL_FreeSurface(temp_surface);

    return temp_texture;
}

void Director::assignTexture(Label* p_label)
{
    p_label->setTexture(createTexture(p_label));
}

void Director::render()
{
    SDL_SetRenderDrawColor(m_windows->getRenderer(), 0, 0, 0, 255);
    SDL_RenderClear(m_windows->getRenderer());

    SDL_SetRenderDrawColor(m_windows->getRenderer(), 255, 255, 255, 255);
    draw();

    SDL_RenderPresent(m_windows->getRenderer());
}

void Director::draw()
{
    // Draw Sprites
    for (std::vector<Node*>::iterator it = p_nodes.begin(); it != p_nodes.end();)
    {
        if ((*it) == NULL)
            it = p_nodes.erase(it);
        else
        {
            draw(*it);
            it++;
        }
    }
}

void Director::draw(Node* p_node)
{
    SDL_RenderCopy(m_windows->getRenderer(), p_node->getTexture(), p_node->getTextureSrc(), p_node->getTextureDst());
}

void Director::animation()
{
    //stuff
}

void Director::passiveAnimation()
{
    //stuff
}

void Director::activeAnimation()
{
    //stuff
}

long Director::getTimer()
{
    return clock();
}

int Director::getRandomNumber()
{
    return (int)clock();
}
<commit_msg>Sets vector<Nodes*> element-pointer to NULL, on delete<commit_after>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * File:   Director.cpp
 * Author: interloper
 *
 * Created on May 29, 2016, 4:11 PM
 */

#include "Director.h"

Director* Director::instance = NULL;

Director::Director()
{
    m_running = false;

    m_windows = NULL;

    m_default_font = NULL;

    m_input_handler = NULL;
}

Director::~Director()
{
    //stuff
}

Director* Director::getInstance()
{
    if(instance == NULL)
        instance = new Director;

    return instance;
}

void Director::quit()
{
    m_running = false;
}

bool Director::isRunning()
{
    return m_running;
}

void Director::cleanUp()
{
    delete m_windows;

    delete m_input_handler;

    IMG_Quit();

    //TTF_Quit():?????

    SDL_Quit();
}

bool Director::initSDL()
{
    if(SDL_Init(SDL_INIT_VIDEO) != 0)// error initializing SDL
    {
        std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
        return false;
    }

    m_windows = new WindowWrapper("RPG Battle",
                                  WINDOW_X, WINDOW_Y,
                                  WINDOW_W, WINDOW_H,
                                  SDL_WINDOW_SHOWN
                                 );

    if(m_windows->errorsExist())
        return false;

    int img_flags = IMG_INIT_PNG;
    if(IMG_Init(img_flags) & img_flags)
         m_surface = SDL_GetWindowSurface(m_windows->getWindow());
    else
    {
        std::cerr << "IMG_Init error: " << SDL_GetError() << std::endl;
        return false;
    }

    if(TTF_Init() == -1)
    {
        std::cerr << "TTF_Init error: " << SDL_GetError() << std::endl;
        return false;
    }

    return true;
}

bool Director::init()
{
    if(!initSDL())
    return (m_running = false);

    m_input_handler = new InputHandler;

    setupDefaultFont();

    setupCursor();

    return (m_running = true);
}

void Director::setupDefaultFont()
{
    m_default_font = TTF_OpenFont(DEFAULT_FONT.c_str(), 90);
}

void Director::setupCursor()
{
    SDL_ShowCursor(SDL_DISABLE);

    addNode(Cursor::getInstance());
}

void Director::handleEvents()
{
    SDL_Event e;

    while(SDL_PollEvent(&e) != 0)
    {
        if(e.type == SDL_QUIT)
            quit();
        else if (e.type == SDL_MOUSEMOTION)
        {
            int x = e.motion.x;
            int y = e.motion.y;
            Cursor::getInstance()->setPosition(Vec2<double>(x, y));
        }
        else if(e.type == SDL_KEYDOWN)
        {
            switch(e.key.keysym.sym)
            {
                case SDLK_UP:     m_input_handler->pressKey(KEY_UP);    break;
                case SDLK_RIGHT:  m_input_handler->pressKey(KEY_RIGHT); break;
                case SDLK_DOWN:   m_input_handler->pressKey(KEY_DOWN);  break;
                case SDLK_LEFT:   m_input_handler->pressKey(KEY_LEFT);  break;
                case SDLK_SPACE:  m_input_handler->pressKey(KEY_SPACE); break;
                //case SDLK_RETURN: m_input_handler->pressKey(KEY_ENTER); break;
                //case SDLK_z:      m_input_handler->pressKey(KEY_z);     break;
                //case SDLK_x:      m_input_handler->pressKey(KEY_x);     break;
            }
        }
        else if(e.type == SDL_KEYUP)
        {
            switch(e.key.keysym.sym)
            {
                case SDLK_UP:     m_input_handler->releaseKey(KEY_UP);    break;
                case SDLK_RIGHT:  m_input_handler->releaseKey(KEY_RIGHT); break;
                case SDLK_DOWN:   m_input_handler->releaseKey(KEY_DOWN);  break;
                case SDLK_LEFT:   m_input_handler->releaseKey(KEY_LEFT);  break;
                case SDLK_SPACE:  m_input_handler->releaseKey(KEY_SPACE); break;
                //case SDLK_RETURN: m_input_handler->releaseKey(KEY_ENTER); break;
                //case SDLK_z:      m_input_handler->releaseKey(KEY_z);     break;
                //case SDLK_x:      m_input_handler->releaseKey(KEY_x);     break;
            }
        }
    }
}

void Director::resetInput()
{
    m_input_handler->resetInput();
}

bool Director::getKey(int p_key)
{
    return m_input_handler->getKey(p_key);
}

void Director::resetKey(int p_key)
{
    m_input_handler->resetKey(p_key);
}

/*TTF_Font* Director::getDefaultFont()
{
    return m_default_font;
}*/

void Director::addNode(Sprite* pSprite)
{
    p_nodes.push_back(pSprite);

    // Create textures if needed
    if(pSprite->getSpritePath() != "")
        Director::getInstance()->assignTexture(pSprite);
}

void Director::deleteNode(Sprite* pSprite)
{
    int id = pSprite->getId();
    for(std::vector<Node*>::iterator it = p_nodes.begin(); it != p_nodes.end(); it++)
    {
        if((*it)->getId() == id)
        {
            delete (*it);
            (*it) = NULL;
            it = p_nodes.erase(it);
            break;
        }
    }
}

SDL_Texture* Director::createTexture(Sprite* p_sprite)
{
    // find loaded texture
    std::map<std::string, SDL_Texture*>::iterator it = m_loaded_textures.find(p_sprite->getSpritePath());
    if (it != m_loaded_textures.end())
        return it->second;

    //load new texture
    SDL_Surface* temp_surface = IMG_Load(p_sprite->getSpritePath().c_str());
    SDL_Texture* temp_texture = SDL_CreateTextureFromSurface(m_windows->getRenderer(), temp_surface);

    // free surface
    SDL_FreeSurface(temp_surface);

    // store new texture
    m_loaded_textures[p_sprite->getSpritePath()] = temp_texture;

    return temp_texture;
}

void Director::assignTexture(Sprite* pSprite)
{
    pSprite->setTexture(createTexture(pSprite));
}

SDL_Texture* Director::createTexture(Label* p_label)
{
    SDL_Surface* temp_surface = TTF_RenderText_Blended(p_label->getFont(), p_label->getText().c_str(), p_label->getColor());
    SDL_Texture* temp_texture = SDL_CreateTextureFromSurface(m_windows->getRenderer(), temp_surface);

    SDL_QueryTexture(temp_texture, NULL, NULL, NULL, NULL);

    SDL_FreeSurface(temp_surface);

    return temp_texture;
}

void Director::assignTexture(Label* p_label)
{
    p_label->setTexture(createTexture(p_label));
}

void Director::render()
{
    SDL_SetRenderDrawColor(m_windows->getRenderer(), 0, 0, 0, 255);
    SDL_RenderClear(m_windows->getRenderer());

    SDL_SetRenderDrawColor(m_windows->getRenderer(), 255, 255, 255, 255);
    draw();

    SDL_RenderPresent(m_windows->getRenderer());
}

void Director::draw()
{
    // Draw Sprites
    for (std::vector<Node*>::iterator it = p_nodes.begin(); it != p_nodes.end();)
    {
        if ((*it) == NULL)
            it = p_nodes.erase(it);
        else
        {
            draw(*it);
            it++;
        }
    }
}

void Director::draw(Node* p_node)
{
    SDL_RenderCopy(m_windows->getRenderer(), p_node->getTexture(), p_node->getTextureSrc(), p_node->getTextureDst());
}

void Director::animation()
{
    //stuff
}

void Director::passiveAnimation()
{
    //stuff
}

void Director::activeAnimation()
{
    //stuff
}

long Director::getTimer()
{
    return clock();
}

int Director::getRandomNumber()
{
    return (int)clock();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"

#include "SkPaint.h"
#include "SkPicture.h"
#include "SkPictureRecorder.h"
#include "SkShader.h"

static const SkScalar kPictureSize = SK_Scalar1;
static const SkScalar kFillSize = 100;
static const unsigned kRowSize = 6;

static const struct {
    SkScalar x, y, w, h;
    SkScalar offsetX, offsetY;
} tiles[] = {
    {      0,      0,    1,    1,      0,    0 },
    {  -0.5f,  -0.5f,    1,    1,      0,    0 },
    {   0.5f,   0.5f,    1,    1,      0,    0 },

    {      0,      0, 1.5f, 1.5f,      0,    0 },
    {  -0.5f,  -0.5f, 1.5f, 1.5f,      0,    0 },
    {   0.5f,   0.5f, 1.5f, 1.5f,      0,    0 },

    {      0,      0, 0.5f, 0.5f,      0,    0 },
    {  0.25f,  0.25f, 0.5f, 0.5f,      0,    0 },
    { -0.25f, -0.25f, 0.5f, 0.5f,      0,    0 },

    {      0,      0,    1,    1,   0.5f, 0.5f },
    {  -0.5f,  -0.5f,    1,    1,   0.5f, 0.5f },
    {   0.5f,   0.5f,    1,    1,   0.5f, 0.5f },

    {      0,      0, 1.5f, 1.5f,   0.5f, 0.5f },
    {  -0.5f,  -0.5f, 1.5f, 1.5f,   0.5f, 0.5f },
    {   0.5f,   0.5f, 1.5f, 1.5f,   0.5f, 0.5f },

    {      0,      0, 1.5f,    1,      0,    0 },
    {  -0.5f,  -0.5f, 1.5f,    1,      0,    0 },
    {   0.5f,   0.5f, 1.5f,    1,      0,    0 },

    {      0,      0, 0.5f,    1,      0,    0 },
    {  0.25f,  0.25f, 0.5f,    1,      0,    0 },
    { -0.25f, -0.25f, 0.5f,    1,      0,    0 },

    {      0,      0,    1, 1.5f,      0,    0 },
    {  -0.5f,  -0.5f,    1, 1.5f,      0,    0 },
    {   0.5f,   0.5f,    1, 1.5f,      0,    0 },

    {      0,      0,    1, 0.5f,      0,    0 },
    {  0.25f,  0.25f,    1, 0.5f,      0,    0 },
    { -0.25f, -0.25f,    1, 0.5f,      0,    0 },
};

class PictureShaderTileGM : public skiagm::GM {
protected:
    virtual uint32_t onGetFlags() const SK_OVERRIDE {
        return kSkipTiled_Flag;
    }

    virtual SkString onShortName() SK_OVERRIDE {
        return SkString("pictureshadertile");
    }

    virtual SkISize onISize() SK_OVERRIDE {
        return SkISize::Make(800, 600);
    }

    virtual void onOnceBeforeDraw() SK_OVERRIDE {
        SkPictureRecorder recorder;
        SkCanvas* pictureCanvas = recorder.beginRecording(kPictureSize, kPictureSize);
        drawScene(pictureCanvas, kPictureSize);
        SkAutoTUnref<SkPicture> picture(recorder.endRecording());

        SkPoint offset = SkPoint::Make(100, 100);
        pictureCanvas = recorder.beginRecording(SkRect::MakeXYWH(offset.x(), offset.y(),
                                                                 kPictureSize, kPictureSize));
        pictureCanvas->translate(offset.x(), offset.y());
        drawScene(pictureCanvas, kPictureSize);
        SkAutoTUnref<SkPicture> offsetPicture(recorder.endRecording());

        for (unsigned i = 0; i < SK_ARRAY_COUNT(tiles); ++i) {
            SkRect tile = SkRect::MakeXYWH(tiles[i].x * kPictureSize,
                                           tiles[i].y * kPictureSize,
                                           tiles[i].w * kPictureSize,
                                           tiles[i].h * kPictureSize);
            SkMatrix localMatrix;
            localMatrix.setTranslate(tiles[i].offsetX * kPictureSize,
                                     tiles[i].offsetY * kPictureSize);
            localMatrix.postScale(kFillSize / (2 * kPictureSize),
                                  kFillSize / (2 * kPictureSize));

            SkPicture* picturePtr = picture.get();
            SkRect* tilePtr = &tile;

            if (tile == SkRect::MakeWH(kPictureSize, kPictureSize)) {
                // When the tile == picture bounds, exercise the picture + offset path.
                picturePtr = offsetPicture.get();
                tilePtr = NULL;
            }

            fShaders[i].reset(SkShader::CreatePictureShader(picturePtr,
                              SkShader::kRepeat_TileMode,
                              SkShader::kRepeat_TileMode,
                              &localMatrix,
                              tilePtr));
        }
    }

    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
        canvas->clear(SK_ColorBLACK);

        SkPaint paint;
        paint.setStyle(SkPaint::kFill_Style);

        for (unsigned i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) {
            paint.setShader(fShaders[i]);

            canvas->save();
            canvas->translate((i % kRowSize) * kFillSize * 1.1f,
                              (i / kRowSize) * kFillSize * 1.1f);
            canvas->drawRect(SkRect::MakeWH(kFillSize, kFillSize), paint);
            canvas->restore();
        }
    }

private:
    void drawScene(SkCanvas* canvas, SkScalar pictureSize) {
        canvas->clear(SK_ColorWHITE);

        SkPaint paint;
        paint.setColor(SK_ColorGREEN);
        paint.setStyle(SkPaint::kFill_Style);
        paint.setAntiAlias(true);

        canvas->drawCircle(pictureSize / 4, pictureSize / 4, pictureSize / 4, paint);
        canvas->drawRect(SkRect::MakeXYWH(pictureSize / 2, pictureSize / 2,
                                          pictureSize / 2, pictureSize / 2), paint);

        paint.setColor(SK_ColorRED);
        canvas->drawLine(pictureSize / 2, pictureSize * 1 / 3,
                         pictureSize / 2, pictureSize * 2 / 3, paint);
        canvas->drawLine(pictureSize * 1 / 3, pictureSize / 2,
                         pictureSize * 2 / 3, pictureSize / 2, paint);

        paint.setColor(SK_ColorBLACK);
        paint.setStyle(SkPaint::kStroke_Style);
        canvas->drawRect(SkRect::MakeWH(pictureSize, pictureSize), paint);
    }

    SkAutoTUnref<SkShader> fShaders[SK_ARRAY_COUNT(tiles)];

    typedef GM INHERITED;
};

DEF_GM( return SkNEW(PictureShaderTileGM); )
<commit_msg>Cleanup GM:pictureshadertile<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"

#include "SkPaint.h"
#include "SkPicture.h"
#include "SkPictureRecorder.h"
#include "SkShader.h"

static const SkScalar kPictureSize = SK_Scalar1;
static const SkScalar kFillSize = 100;
static const unsigned kRowSize = 6;

static const struct {
    SkScalar x, y, w, h;
    SkScalar offsetX, offsetY;
} tiles[] = {
    {      0,      0,    1,    1,      0,    0 },
    {  -0.5f,  -0.5f,    1,    1,      0,    0 },
    {   0.5f,   0.5f,    1,    1,      0,    0 },

    {      0,      0, 1.5f, 1.5f,      0,    0 },
    {  -0.5f,  -0.5f, 1.5f, 1.5f,      0,    0 },
    {   0.5f,   0.5f, 1.5f, 1.5f,      0,    0 },

    {      0,      0, 0.5f, 0.5f,      0,    0 },
    {  0.25f,  0.25f, 0.5f, 0.5f,      0,    0 },
    { -0.25f, -0.25f, 0.5f, 0.5f,      0,    0 },

    {      0,      0,    1,    1,   0.5f, 0.5f },
    {  -0.5f,  -0.5f,    1,    1,   0.5f, 0.5f },
    {   0.5f,   0.5f,    1,    1,   0.5f, 0.5f },

    {      0,      0, 1.5f, 1.5f,   0.5f, 0.5f },
    {  -0.5f,  -0.5f, 1.5f, 1.5f,   0.5f, 0.5f },
    {   0.5f,   0.5f, 1.5f, 1.5f,   0.5f, 0.5f },

    {      0,      0, 1.5f,    1,      0,    0 },
    {  -0.5f,  -0.5f, 1.5f,    1,      0,    0 },
    {   0.5f,   0.5f, 1.5f,    1,      0,    0 },

    {      0,      0, 0.5f,    1,      0,    0 },
    {  0.25f,  0.25f, 0.5f,    1,      0,    0 },
    { -0.25f, -0.25f, 0.5f,    1,      0,    0 },

    {      0,      0,    1, 1.5f,      0,    0 },
    {  -0.5f,  -0.5f,    1, 1.5f,      0,    0 },
    {   0.5f,   0.5f,    1, 1.5f,      0,    0 },

    {      0,      0,    1, 0.5f,      0,    0 },
    {  0.25f,  0.25f,    1, 0.5f,      0,    0 },
    { -0.25f, -0.25f,    1, 0.5f,      0,    0 },
};

static void draw_scene(SkCanvas* canvas, SkScalar pictureSize) {
    canvas->clear(SK_ColorWHITE);

    SkPaint paint;
    paint.setColor(SK_ColorGREEN);
    paint.setStyle(SkPaint::kFill_Style);
    paint.setAntiAlias(true);

    canvas->drawCircle(pictureSize / 4, pictureSize / 4, pictureSize / 4, paint);
    canvas->drawRect(SkRect::MakeXYWH(pictureSize / 2, pictureSize / 2,
                                      pictureSize / 2, pictureSize / 2), paint);

    paint.setColor(SK_ColorRED);
    canvas->drawLine(pictureSize / 2, pictureSize * 1 / 3,
                     pictureSize / 2, pictureSize * 2 / 3, paint);
    canvas->drawLine(pictureSize * 1 / 3, pictureSize / 2,
                     pictureSize * 2 / 3, pictureSize / 2, paint);

    paint.setColor(SK_ColorBLACK);
    paint.setStyle(SkPaint::kStroke_Style);
    canvas->drawRect(SkRect::MakeWH(pictureSize, pictureSize), paint);
}

class PictureShaderTileGM : public skiagm::GM {
protected:
    uint32_t onGetFlags() const SK_OVERRIDE {
        return kSkipTiled_Flag;
    }

    SkString onShortName() SK_OVERRIDE {
        return SkString("pictureshadertile");
    }

    SkISize onISize() SK_OVERRIDE {
        return SkISize::Make(800, 600);
    }

    void onOnceBeforeDraw() SK_OVERRIDE {
        SkPictureRecorder recorder;
        SkCanvas* pictureCanvas = recorder.beginRecording(kPictureSize, kPictureSize);
        draw_scene(pictureCanvas, kPictureSize);
        SkAutoTUnref<SkPicture> picture(recorder.endRecording());

        SkPoint offset = SkPoint::Make(100, 100);
        pictureCanvas = recorder.beginRecording(SkRect::MakeXYWH(offset.x(), offset.y(),
                                                                 kPictureSize, kPictureSize));
        pictureCanvas->translate(offset.x(), offset.y());
        draw_scene(pictureCanvas, kPictureSize);
        SkAutoTUnref<SkPicture> offsetPicture(recorder.endRecording());

        for (unsigned i = 0; i < SK_ARRAY_COUNT(tiles); ++i) {
            SkRect tile = SkRect::MakeXYWH(tiles[i].x * kPictureSize,
                                           tiles[i].y * kPictureSize,
                                           tiles[i].w * kPictureSize,
                                           tiles[i].h * kPictureSize);
            SkMatrix localMatrix;
            localMatrix.setTranslate(tiles[i].offsetX * kPictureSize,
                                     tiles[i].offsetY * kPictureSize);
            localMatrix.postScale(kFillSize / (2 * kPictureSize),
                                  kFillSize / (2 * kPictureSize));

            SkPicture* picturePtr = picture.get();
            SkRect* tilePtr = &tile;

            if (tile == SkRect::MakeWH(kPictureSize, kPictureSize)) {
                // When the tile == picture bounds, exercise the picture + offset path.
                picturePtr = offsetPicture.get();
                tilePtr = NULL;
            }

            fShaders[i].reset(SkShader::CreatePictureShader(picturePtr,
                                                            SkShader::kRepeat_TileMode,
                                                            SkShader::kRepeat_TileMode,
                                                            &localMatrix,
                                                            tilePtr));
        }
    }

    void onDraw(SkCanvas* canvas) SK_OVERRIDE {
        canvas->clear(SK_ColorBLACK);

        SkPaint paint;
        paint.setStyle(SkPaint::kFill_Style);

        for (unsigned i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) {
            paint.setShader(fShaders[i]);

            canvas->save();
            canvas->translate((i % kRowSize) * kFillSize * 1.1f,
                              (i / kRowSize) * kFillSize * 1.1f);
            canvas->drawRect(SkRect::MakeWH(kFillSize, kFillSize), paint);
            canvas->restore();
        }
    }

private:
    SkAutoTUnref<SkShader> fShaders[SK_ARRAY_COUNT(tiles)];

    typedef GM INHERITED;
};

DEF_GM( return SkNEW(PictureShaderTileGM); )
<|endoftext|>