<commit_before>#include <bts/blockchain/balance_operations.hpp>
#include <bts/blockchain/operation_factory.hpp>
#include <bts/blockchain/pending_chain_state.hpp>
#include <bts/blockchain/transaction_evaluation_state.hpp>
#include <bts/blockchain/fork_blocks.hpp>

namespace bts { namespace blockchain {

   bool transaction_evaluation_state::verify_authority( const multisig_meta_info& siginfo )
   { try {
      uint32_t sig_count = 0;
      ilog("@n verifying authority");
      for( const auto item : siginfo.owners )
      {
         sig_count += check_signature( item );
         ilog("@n sig_count: ${s}", ("s", sig_count));
      }
      ilog("@n required: ${s}", ("s", siginfo.required));
      return sig_count >= siginfo.required;
   } FC_CAPTURE_AND_RETHROW( (siginfo) ) }

   bool transaction_evaluation_state::check_signature( const address& a )const
   { try {
      return _skip_signature_check || signed_addresses.find( a ) != signed_addresses.end();
   } FC_CAPTURE_AND_RETHROW( (a) ) }

   bool transaction_evaluation_state::check_multisig( const multisig_condition& condition )const
   { try {
      auto valid = 0;
      for( auto addr : condition.owners )
          if( check_signature( addr ) )
              valid++;
      return valid >= condition.required;
   } FC_CAPTURE_AND_RETHROW( (condition) ) }

   bool transaction_evaluation_state::any_parent_has_signed( const string& account_name )const
   { try {
       for( optional<string> parent_name = pending_state()->get_parent_account_name( account_name );
            parent_name.valid();
            parent_name = pending_state()->get_parent_account_name( *parent_name ) )
       {
           const oaccount_record parent_record = pending_state()->get_account_record( *parent_name );
           if( !parent_record.valid() )
               continue;

           if( parent_record->is_retracted() )
               continue;

           if( check_signature( parent_record->active_key() ) )
               return true;

           if( check_signature( parent_record->owner_key ) )
               return true;
       }
       return false;
   } FC_CAPTURE_AND_RETHROW( (account_name) ) }

   bool transaction_evaluation_state::account_or_any_parent_has_signed( const account_record& record )const
   { try {
       if( !record.is_retracted() )
       {
           if( check_signature( record.active_key() ) )
               return true;

           if( check_signature( record.owner_key ) )
               return true;
       }
       return any_parent_has_signed( record.name );
   } FC_CAPTURE_AND_RETHROW( (record) ) }

   void transaction_evaluation_state::update_delegate_votes()
   { try {
      for( const auto& item : delegate_vote_deltas )
      {
          const account_id_type id = item.first;
          oaccount_record delegate_record = pending_state()->get_account_record( id );
          FC_ASSERT( delegate_record.valid() && delegate_record->is_delegate() );

          const share_type amount = item.second;
          delegate_record->adjust_votes_for( amount );
          pending_state()->store_account_record( *delegate_record );
      }
   } FC_CAPTURE_AND_RETHROW() }

   void transaction_evaluation_state::update_rp_values()
   { try {
        if ( rp_account_id.valid() )
        {
            oaccount_record account_rec = pending_state()->get_account_record( *rp_account_id );
            FC_ASSERT( account_rec.valid() );

            account_rec->stats_info.rp += total_base_equivalent_fees_paid;
            pending_state()->store_account_record( *account_rec );
        }
   } FC_CAPTURE_AND_RETHROW() }

   void transaction_evaluation_state::validate_fees()
   { try {
       for( const auto& item : fees_paid )
       {
           const asset fee( item.second, item.first );
           if( fee.amount < 0 )
               FC_CAPTURE_AND_THROW( negative_fee, (fee) );

           auto iter = min_fees.find( fee.asset_id );
           if( iter != min_fees.end() )
           {
               if( fee.amount < iter->second )
                   FC_CAPTURE_AND_THROW( insufficient_fee, (fee)(min_fees) );
           }

           iter = max_fees.find( fee.asset_id );
           if( iter != max_fees.end() )
           {
               if( fee.amount > iter->second )
                   FC_CAPTURE_AND_THROW( fee_greater_than_max, (fee)(max_fees) );
           }

           if( fee.amount != 0 )
           {
               oasset_record asset_record = pending_state()->get_asset_record( fee.asset_id );
               if( !asset_record.valid() )
                   FC_CAPTURE_AND_THROW( unknown_asset_id, (fee) );

               asset_record->collected_fees += fee.amount;
               pending_state()->store_asset_record( *asset_record );
           }
       }
   } FC_CAPTURE_AND_RETHROW() }

   void transaction_evaluation_state::evaluate( const signed_transaction& trx_arg )
   { try {
      trx = trx_arg;
      try {
        if( pending_state()->now() >= trx_arg.expiration )
        {
           const auto expired_by_sec = (pending_state()->now() - trx_arg.expiration).to_seconds();
           FC_CAPTURE_AND_THROW( expired_transaction, (trx_arg)(pending_state()->now())(expired_by_sec) );
        }
        if( (pending_state()->now() + BTS_BLOCKCHAIN_MAX_TRANSACTION_EXPIRATION_SEC) < trx_arg.expiration )
           FC_CAPTURE_AND_THROW( invalid_transaction_expiration, (trx_arg)(pending_state()->now()) );

        if( pending_state()->is_known_transaction( trx_arg ) )
           FC_CAPTURE_AND_THROW( duplicate_transaction, (trx.id()) );

        if( !_skip_signature_check )
        {
           const auto trx_digest = trx_arg.digest( pending_state()->get_chain_id() );
           for( const auto& sig : trx_arg.signatures )
           {
              const auto key = fc::ecc::public_key( sig, trx_digest, _enforce_canonical_signatures ).serialize();
              signed_addresses.insert( address( key ) );
              signed_addresses.insert( address( pts_address( key, false, 56 ) ) );
              signed_addresses.insert( address( pts_address( key, true, 56 ) ) );
              signed_addresses.insert( address( pts_address( key, false, 0 ) ) );
              signed_addresses.insert( address( pts_address( key, true, 0 ) ) );
           }
        }

        _current_op_index = 0;
        for( const auto& op : trx_arg.operations )
        {
           evaluate_operation( op );
           ++_current_op_index;
        }

        if ( pending_state()->get_head_block_num() > PLS_V0_4_3_FORK_BLOCK_NUM  && _current_op_index > 1000 )
        {
            FC_CAPTURE_AND_THROW( invalid_transaction_expiration, (trx.id())(_current_op_index) );
        }

        validate_fees();
        calculate_base_equivalent_fees();
        update_delegate_votes();

        update_rp_values();

        pending_state()->store_transaction( trx.id(), transaction_record( transaction_location(), *this ) );
      }
      catch ( const fc::exception& e )
      {
         validation_error = e;
         throw;
      }
   } FC_CAPTURE_AND_RETHROW( (trx_arg) ) }

   void transaction_evaluation_state::evaluate_operation( const operation& op )
   { try {
      operation_factory::instance().evaluate( *this, op );
   } FC_CAPTURE_AND_RETHROW( (op) ) }

   void transaction_evaluation_state::adjust_vote( const slate_id_type slate_id, const share_type amount )
   { try {
       if( slate_id == 0 || _skip_vote_adjustment )
           return;

       const oslate_record slate_record = pending_state()->get_slate_record( slate_id );
       if( !slate_record.valid() )
           FC_CAPTURE_AND_THROW( unknown_delegate_slate, (slate_id) );

       for( const account_id_type id : slate_record->slate )
       {
           if( id >= 0 )
               delegate_vote_deltas[ id ] += amount;
       }
   } FC_CAPTURE_AND_RETHROW( (slate_id)(amount) ) }

   void transaction_evaluation_state::calculate_base_equivalent_fees()
   { try {
       total_base_equivalent_fees_paid = 0;

       for( const auto& item : fees_paid )
       {
           const asset fee( item.second, item.first );
           if( fee.asset_id == 0 )
           {
               total_base_equivalent_fees_paid += fee.amount;
           }
           else
           {
               const oasset_record asset_record = pending_state()->get_asset_record( fee.asset_id );
               FC_ASSERT( asset_record.valid() );

               // Tally BitAsset fees using feed price discounted by 33%
               if( asset_record->is_market_issued() )
               {
                   const oprice feed_price = pending_state()->get_active_feed_price( fee.asset_id );
                   if( feed_price.valid() )
                       total_base_equivalent_fees_paid += (asset( fee.amount * 2, fee.asset_id ) * *feed_price).amount / 3;
               }
           }
       }
   } FC_CAPTURE_AND_RETHROW() }

   void transaction_evaluation_state::sub_balance( const asset& amount )
   { try {
      fees_paid[ amount.asset_id ] -= amount.amount;
      op_deltas[ _current_op_index ][ amount.asset_id ] += amount.amount;
   } FC_CAPTURE_AND_RETHROW( (amount) ) }

   void transaction_evaluation_state::add_balance( const asset& amount )
   { try {
      fees_paid[ amount.asset_id ] += amount.amount;
      op_deltas[ _current_op_index ][ amount.asset_id ] -= amount.amount;
   } FC_CAPTURE_AND_RETHROW( (amount) ) }

   bool transaction_evaluation_state::scan_op_deltas( const uint32_t op_index, const function<bool( const asset& )> callback )const
   { try {
       bool ret = false;
       for( const auto& item : op_deltas )
       {
           const uint32_t index = item.first;
           if( index != op_index ) continue;
           for( const auto& delta_item : item.second )
           {
               const asset delta_amount( delta_item.second, delta_item.first );
               ret |= callback( delta_amount );
           }
       }
       return ret;
   } FC_CAPTURE_AND_RETHROW( (op_index) ) }

   void transaction_evaluation_state::scan_addresses( const chain_interface& chain,
                                                      const function<void( const address& )> callback )const
   { try {
       for( const operation& op : trx.operations )
       {
           switch( operation_type_enum( op.type ) )
           {
               case withdraw_op_type:
               {
                   const obalance_record balance_record = chain.get_balance_record( op.as<withdraw_operation>().balance_id );
                   if( balance_record.valid() )
                   {
                       const set<address>& owners = balance_record->owners();
                       for( const address& addr : owners )
                           callback( addr );
                   }
                   break;
               }
               case deposit_op_type:
               {
                   const set<address>& owners = op.as<deposit_operation>().condition.owners();
                   for( const address& addr : owners )
                       callback( addr );
                   break;
               }
               default:
               {
                   break;
               }
           }
       }
   } FC_CAPTURE_AND_RETHROW() }

} } // bts::blockchain
<commit_msg>avoid potential overflow attack<commit_after>#include <bts/blockchain/balance_operations.hpp>
#include <bts/blockchain/operation_factory.hpp>
#include <bts/blockchain/pending_chain_state.hpp>
#include <bts/blockchain/transaction_evaluation_state.hpp>
#include <bts/blockchain/fork_blocks.hpp>

namespace bts { namespace blockchain {

   bool transaction_evaluation_state::verify_authority( const multisig_meta_info& siginfo )
   { try {
      uint32_t sig_count = 0;
      ilog("@n verifying authority");
      for( const auto item : siginfo.owners )
      {
         sig_count += check_signature( item );
         ilog("@n sig_count: ${s}", ("s", sig_count));
      }
      ilog("@n required: ${s}", ("s", siginfo.required));
      return sig_count >= siginfo.required;
   } FC_CAPTURE_AND_RETHROW( (siginfo) ) }

   bool transaction_evaluation_state::check_signature( const address& a )const
   { try {
      return _skip_signature_check || signed_addresses.find( a ) != signed_addresses.end();
   } FC_CAPTURE_AND_RETHROW( (a) ) }

   bool transaction_evaluation_state::check_multisig( const multisig_condition& condition )const
   { try {
      auto valid = 0;
      for( auto addr : condition.owners )
          if( check_signature( addr ) )
              valid++;
      return valid >= condition.required;
   } FC_CAPTURE_AND_RETHROW( (condition) ) }

   bool transaction_evaluation_state::any_parent_has_signed( const string& account_name )const
   { try {
       for( optional<string> parent_name = pending_state()->get_parent_account_name( account_name );
            parent_name.valid();
            parent_name = pending_state()->get_parent_account_name( *parent_name ) )
       {
           const oaccount_record parent_record = pending_state()->get_account_record( *parent_name );
           if( !parent_record.valid() )
               continue;

           if( parent_record->is_retracted() )
               continue;

           if( check_signature( parent_record->active_key() ) )
               return true;

           if( check_signature( parent_record->owner_key ) )
               return true;
       }
       return false;
   } FC_CAPTURE_AND_RETHROW( (account_name) ) }

   bool transaction_evaluation_state::account_or_any_parent_has_signed( const account_record& record )const
   { try {
       if( !record.is_retracted() )
       {
           if( check_signature( record.active_key() ) )
               return true;

           if( check_signature( record.owner_key ) )
               return true;
       }
       return any_parent_has_signed( record.name );
   } FC_CAPTURE_AND_RETHROW( (record) ) }

   void transaction_evaluation_state::update_delegate_votes()
   { try {
      for( const auto& item : delegate_vote_deltas )
      {
          const account_id_type id = item.first;
          oaccount_record delegate_record = pending_state()->get_account_record( id );
          FC_ASSERT( delegate_record.valid() && delegate_record->is_delegate() );

          const share_type amount = item.second;
          delegate_record->adjust_votes_for( amount );
          pending_state()->store_account_record( *delegate_record );
      }
   } FC_CAPTURE_AND_RETHROW() }

   void transaction_evaluation_state::update_rp_values()
   { try {
        if ( rp_account_id.valid() )
        {
            oaccount_record account_rec = pending_state()->get_account_record( *rp_account_id );
            FC_ASSERT( account_rec.valid() );

            account_rec->stats_info.rp += total_base_equivalent_fees_paid;
            pending_state()->store_account_record( *account_rec );
        }
   } FC_CAPTURE_AND_RETHROW() }

   void transaction_evaluation_state::validate_fees()
   { try {
       for( const auto& item : fees_paid )
       {
           const asset fee( item.second, item.first );
           if( fee.amount < 0 )
               FC_CAPTURE_AND_THROW( negative_fee, (fee) );

           auto iter = min_fees.find( fee.asset_id );
           if( iter != min_fees.end() )
           {
               if( fee.amount < iter->second )
                   FC_CAPTURE_AND_THROW( insufficient_fee, (fee)(min_fees) );
           }

           iter = max_fees.find( fee.asset_id );
           if( iter != max_fees.end() )
           {
               if( fee.amount > iter->second )
                   FC_CAPTURE_AND_THROW( fee_greater_than_max, (fee)(max_fees) );
           }

           if( fee.amount != 0 )
           {
               oasset_record asset_record = pending_state()->get_asset_record( fee.asset_id );
               if( !asset_record.valid() )
                   FC_CAPTURE_AND_THROW( unknown_asset_id, (fee) );

               asset_record->collected_fees += fee.amount;
               pending_state()->store_asset_record( *asset_record );
           }
       }
   } FC_CAPTURE_AND_RETHROW() }

   void transaction_evaluation_state::evaluate( const signed_transaction& trx_arg )
   { try {
      trx = trx_arg;
      try {
        if( pending_state()->now() >= trx_arg.expiration )
        {
           const auto expired_by_sec = (pending_state()->now() - trx_arg.expiration).to_seconds();
           FC_CAPTURE_AND_THROW( expired_transaction, (trx_arg)(pending_state()->now())(expired_by_sec) );
        }
        if( (pending_state()->now() + BTS_BLOCKCHAIN_MAX_TRANSACTION_EXPIRATION_SEC) < trx_arg.expiration )
           FC_CAPTURE_AND_THROW( invalid_transaction_expiration, (trx_arg)(pending_state()->now()) );

        if( pending_state()->is_known_transaction( trx_arg ) )
           FC_CAPTURE_AND_THROW( duplicate_transaction, (trx.id()) );

        if( !_skip_signature_check )
        {
           const auto trx_digest = trx_arg.digest( pending_state()->get_chain_id() );
           for( const auto& sig : trx_arg.signatures )
           {
              const auto key = fc::ecc::public_key( sig, trx_digest, _enforce_canonical_signatures ).serialize();
              signed_addresses.insert( address( key ) );
              signed_addresses.insert( address( pts_address( key, false, 56 ) ) );
              signed_addresses.insert( address( pts_address( key, true, 56 ) ) );
              signed_addresses.insert( address( pts_address( key, false, 0 ) ) );
              signed_addresses.insert( address( pts_address( key, true, 0 ) ) );
           }
        }

        _current_op_index = 0;
        for( const auto& op : trx_arg.operations )
        {
           evaluate_operation( op );
           ++_current_op_index;
        }

        if ( pending_state()->get_head_block_num() > PLS_V0_4_3_FORK_BLOCK_NUM  && _current_op_index > 1000 )
        {
            FC_CAPTURE_AND_THROW( invalid_transaction_expiration, (trx.id())(_current_op_index) );
        }

        validate_fees();
        calculate_base_equivalent_fees();
        update_delegate_votes();

        update_rp_values();

        pending_state()->store_transaction( trx.id(), transaction_record( transaction_location(), *this ) );
      }
      catch ( const fc::exception& e )
      {
         validation_error = e;
         throw;
      }
   } FC_CAPTURE_AND_RETHROW( (trx_arg) ) }

   void transaction_evaluation_state::evaluate_operation( const operation& op )
   { try {
      operation_factory::instance().evaluate( *this, op );
   } FC_CAPTURE_AND_RETHROW( (op) ) }

   void transaction_evaluation_state::adjust_vote( const slate_id_type slate_id, const share_type amount )
   { try {
       if( slate_id == 0 || _skip_vote_adjustment )
           return;

       const oslate_record slate_record = pending_state()->get_slate_record( slate_id );
       if( !slate_record.valid() )
           FC_CAPTURE_AND_THROW( unknown_delegate_slate, (slate_id) );

       for( const account_id_type id : slate_record->slate )
       {
           if( id >= 0 )
               delegate_vote_deltas[ id ] += amount;
       }
   } FC_CAPTURE_AND_RETHROW( (slate_id)(amount) ) }

   void transaction_evaluation_state::calculate_base_equivalent_fees()
   { try {
       total_base_equivalent_fees_paid = 0;

       for( const auto& item : fees_paid )
       {
           const asset fee( item.second, item.first );
           if( fee.asset_id == 0 )
           {
               total_base_equivalent_fees_paid += fee.amount;
           }
           else
           {
               const oasset_record asset_record = pending_state()->get_asset_record( fee.asset_id );
               FC_ASSERT( asset_record.valid() );

               // Tally BitAsset fees using feed price discounted by 33%
               if( asset_record->is_market_issued() )
               {
                   const oprice feed_price = pending_state()->get_active_feed_price( fee.asset_id );
                   if( feed_price.valid() )
                       total_base_equivalent_fees_paid += (asset( fee.amount * 2, fee.asset_id ) * *feed_price).amount / 3;
               }
           }
       }
   } FC_CAPTURE_AND_RETHROW() }

   void transaction_evaluation_state::sub_balance( const asset& amount )
   { try {
      // avoid overflow attack
      FC_ASSERT( amount.amount < INT64_MAX / 2 );
      FC_ASSERT( amount.amount > INT64_MIN / 2 );
      FC_ASSERT( fees_paid[ amount.asset_id ] < INT64_MAX / 2 );
      FC_ASSERT( fees_paid[ amount.asset_id ] > INT64_MIN / 2 );
      fees_paid[ amount.asset_id ] -= amount.amount;
      op_deltas[ _current_op_index ][ amount.asset_id ] += amount.amount;
   } FC_CAPTURE_AND_RETHROW( (amount) ) }

   void transaction_evaluation_state::add_balance( const asset& amount )
   { try {
      // avoid overflow attack
      FC_ASSERT( amount.amount < INT64_MAX / 2 );
      FC_ASSERT( amount.amount > INT64_MIN / 2 );
      FC_ASSERT( fees_paid[ amount.asset_id ] < INT64_MAX / 2 );
      FC_ASSERT( fees_paid[ amount.asset_id ] > INT64_MIN / 2 );
      fees_paid[ amount.asset_id ] += amount.amount;
      op_deltas[ _current_op_index ][ amount.asset_id ] -= amount.amount;
   } FC_CAPTURE_AND_RETHROW( (amount) ) }

   bool transaction_evaluation_state::scan_op_deltas( const uint32_t op_index, const function<bool( const asset& )> callback )const
   { try {
       bool ret = false;
       for( const auto& item : op_deltas )
       {
           const uint32_t index = item.first;
           if( index != op_index ) continue;
           for( const auto& delta_item : item.second )
           {
               const asset delta_amount( delta_item.second, delta_item.first );
               ret |= callback( delta_amount );
           }
       }
       return ret;
   } FC_CAPTURE_AND_RETHROW( (op_index) ) }

   void transaction_evaluation_state::scan_addresses( const chain_interface& chain,
                                                      const function<void( const address& )> callback )const
   { try {
       for( const operation& op : trx.operations )
       {
           switch( operation_type_enum( op.type ) )
           {
               case withdraw_op_type:
               {
                   const obalance_record balance_record = chain.get_balance_record( op.as<withdraw_operation>().balance_id );
                   if( balance_record.valid() )
                   {
                       const set<address>& owners = balance_record->owners();
                       for( const address& addr : owners )
                           callback( addr );
                   }
                   break;
               }
               case deposit_op_type:
               {
                   const set<address>& owners = op.as<deposit_operation>().condition.owners();
                   for( const address& addr : owners )
                       callback( addr );
                   break;
               }
               default:
               {
                   break;
               }
           }
       }
   } FC_CAPTURE_AND_RETHROW() }

} } // bts::blockchain
<|endoftext|>


<commit_before>#include "command.hh"
#include "common-args.hh"
#include "store-api.hh"
#include "archive.hh"

using namespace nix;

struct CmdAddToStore : MixDryRun, StoreCommand
{
    Path path;
    std::optional<std::string> namePart;

    CmdAddToStore()
    {
        expectArg("path", &path);

        addFlag({
            .longName = "name",
            .shortName = 'n',
            .description = "name component of the store path",
            .labels = {"name"},
            .handler = {&namePart},
        });
    }

    std::string description() override
    {
        return "add a path to the Nix store";
    }

    Examples examples() override
    {
        return {
        };
    }

    Category category() override { return catUtility; }

    void run(ref<Store> store) override
    {
        if (!namePart) namePart = baseNameOf(path);

        StringSink sink;
        dumpPath(path, sink);

        auto narHash = hashString(HashType::SHA256, *sink.s);

        ValidPathInfo info(store->makeFixedOutputPath(FileIngestionMethod::Recursive, narHash, *namePart));
        info.narHash = narHash;
        info.narSize = sink.s->size();
        *info.ca = FileSystemHash {
            FileIngestionMethod::Recursive,
            info.narHash,
        };

        if (!dryRun) {
            auto source = StringSource { *sink.s };
            store->addToStore(info, source);
        }

        logger->stdout("%s", store->printStorePath(info.path));
    }
};

static auto r1 = registerCommand<CmdAddToStore>("add-to-store");
<commit_msg>Make sure info.ca tag bit is set in `nix add-to-store`<commit_after>#include "command.hh"
#include "common-args.hh"
#include "store-api.hh"
#include "archive.hh"

using namespace nix;

struct CmdAddToStore : MixDryRun, StoreCommand
{
    Path path;
    std::optional<std::string> namePart;

    CmdAddToStore()
    {
        expectArg("path", &path);

        addFlag({
            .longName = "name",
            .shortName = 'n',
            .description = "name component of the store path",
            .labels = {"name"},
            .handler = {&namePart},
        });
    }

    std::string description() override
    {
        return "add a path to the Nix store";
    }

    Examples examples() override
    {
        return {
        };
    }

    Category category() override { return catUtility; }

    void run(ref<Store> store) override
    {
        if (!namePart) namePart = baseNameOf(path);

        StringSink sink;
        dumpPath(path, sink);

        auto narHash = hashString(HashType::SHA256, *sink.s);

        ValidPathInfo info(store->makeFixedOutputPath(FileIngestionMethod::Recursive, narHash, *namePart));
        info.narHash = narHash;
        info.narSize = sink.s->size();
        info.ca = std::optional { FileSystemHash {
            FileIngestionMethod::Recursive,
            info.narHash,
        } };

        if (!dryRun) {
            auto source = StringSource { *sink.s };
            store->addToStore(info, source);
        }

        logger->stdout("%s", store->printStorePath(info.path));
    }
};

static auto r1 = registerCommand<CmdAddToStore>("add-to-store");
<|endoftext|>


<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SkDevice.h"
#include "SkDraw.h"
#include "SkMetaData.h"
#include "SkRect.h"

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

SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
    fOrigin.setZero();
    fMetaData = NULL;
}

SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
    fOrigin.setZero();
    fMetaData = NULL;

    fBitmap.setConfig(config, width, height);
    fBitmap.allocPixels();
    fBitmap.setIsOpaque(isOpaque);
    if (!isOpaque) {
        fBitmap.eraseColor(0);
    }
}

SkDevice::~SkDevice() {
    delete fMetaData;
}

SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config,
                                           int width, int height,
                                           bool isOpaque) {
    return this->onCreateCompatibleDevice(config, width, height,
                                          isOpaque, kGeneral_Usage);
}

SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
                                                       int width, int height,
                                                       bool isOpaque) {
    return this->onCreateCompatibleDevice(config, width, height,
                                          isOpaque, kSaveLayer_Usage);
}

SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config,
                                             int width, int height,
                                             bool isOpaque,
                                             Usage usage) {
    return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque));
}

SkMetaData& SkDevice::getMetaData() {
    // metadata users are rare, so we lazily allocate it. If that changes we
    // can decide to just make it a field in the device (rather than a ptr)
    if (NULL == fMetaData) {
        fMetaData = new SkMetaData;
    }
    return *fMetaData;
}

void SkDevice::lockPixels() {
    if (fBitmap.lockPixelsAreWritable()) {
        fBitmap.lockPixels();
    }
}

void SkDevice::unlockPixels() {
    if (fBitmap.lockPixelsAreWritable()) {
        fBitmap.unlockPixels();
    }
}

const SkBitmap& SkDevice::accessBitmap(bool changePixels) {
    this->onAccessBitmap(&fBitmap);
    if (changePixels) {
        fBitmap.notifyPixelsChanged();
    }
    return fBitmap;
}

void SkDevice::getGlobalBounds(SkIRect* bounds) const {
    if (bounds) {
        bounds->setXYWH(fOrigin.x(), fOrigin.y(),
                        fBitmap.width(), fBitmap.height());
    }
}

void SkDevice::clear(SkColor color) {
    fBitmap.eraseColor(color);
}

void SkDevice::onAccessBitmap(SkBitmap* bitmap) {}

void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region,
                             const SkClipStack& clipStack) {
}

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

bool SkDevice::readPixels(SkBitmap* bitmap, int x, int y,
                          SkCanvas::Config8888 config8888) {
    if (SkBitmap::kARGB_8888_Config != bitmap->config() ||
        NULL != bitmap->getTexture()) {
        return false;
    }

    const SkBitmap& src = this->accessBitmap(false);

    SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(),
                                              bitmap->height());
    SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height());
    if (!srcRect.intersect(devbounds)) {
        return false;
    }

    SkBitmap tmp;
    SkBitmap* bmp;
    if (bitmap->isNull()) {
        tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(),
                                                   bitmap->height());
        if (!tmp.allocPixels()) {
            return false;
        }
        bmp = &tmp;
    } else {
        bmp = bitmap;
    }

    SkIRect subrect = srcRect;
    subrect.offset(-x, -y);
    SkBitmap bmpSubset;
    bmp->extractSubset(&bmpSubset, subrect);

    bool result = this->onReadPixels(bmpSubset,
                                     srcRect.fLeft,
                                     srcRect.fTop,
                                     config8888);
    if (result && bmp == &tmp) {
        tmp.swap(*bitmap);
    }
    return result;
}

#ifdef SK_CPU_LENDIAN
    #if   24 == SK_A32_SHIFT && 16 == SK_R32_SHIFT && \
           8 == SK_G32_SHIFT &&  0 == SK_B32_SHIFT
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            SkCanvas::kBGRA_Premul_Config8888;
    #elif 24 == SK_A32_SHIFT &&  0 == SK_R32_SHIFT && \
           8 == SK_G32_SHIFT && 16 == SK_B32_SHIFT
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            SkCanvas::kRGBA_Premul_Config8888;
    #else
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            (SkCanvas::Config8888) -1;
    #endif
#else
    #if    0 == SK_A32_SHIFT &&   8 == SK_R32_SHIFT && \
          16 == SK_G32_SHIFT &&  24 == SK_B32_SHIFT
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            SkCanvas::kBGRA_Premul_Config8888;
    #elif  0 == SK_A32_SHIFT &&  24 == SK_R32_SHIFT && \
          16 == SK_G32_SHIFT &&   8 == SK_B32_SHIFT
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            SkCanvas::kRGBA_Premul_Config8888;
    #else
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            (SkCanvas::Config8888) -1;
    #endif
#endif

#include <SkConfig8888.h>

bool SkDevice::onReadPixels(const SkBitmap& bitmap,
                            int x, int y,
                            SkCanvas::Config8888 config8888) {
    SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
    SkASSERT(!bitmap.isNull());
    SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));

    SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(),
                                              bitmap.height());
    const SkBitmap& src = this->accessBitmap(false);

    SkBitmap subset;
    if (!src.extractSubset(&subset, srcRect)) {
        return false;
    }
    if (SkBitmap::kARGB_8888_Config != subset.config()) {
        // It'd be preferable to do this directly to bitmap.
        subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
    }
    SkAutoLockPixels alp(bitmap);
    uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
    if ((SkCanvas::kNative_Premul_Config8888 == config8888 ||
         kPMColorAlias == config8888)) {
        SkCopyARGB8888BitmapTo(bmpPixels, bitmap.rowBytes(), subset);
    } else {
        SkCopyBitmapToConfig8888(bmpPixels,
                                 bitmap.rowBytes(),
                                 config8888,
                                 subset);
    }
    return true;
}

void SkDevice::writePixels(const SkBitmap& bitmap,
                           int x, int y,
                           SkCanvas::Config8888 config8888) {
    if (bitmap.isNull() || bitmap.getTexture()) {
        return;
    }
    const SkBitmap* sprite = &bitmap;
    // check whether we have to handle a config8888 that doesn't match SkPMColor
    if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
        SkCanvas::kNative_Premul_Config8888 != config8888 &&
        kPMColorAlias != config8888) {

        // We're going to have to convert from a config8888 to the native config
        // First we clip to the device bounds.
        SkBitmap dstBmp = this->accessBitmap(true);
        SkIRect spriteRect = SkIRect::MakeXYWH(x, y,
                                               bitmap.width(), bitmap.height());
        SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height());
        if (!spriteRect.intersect(devRect)) {
            return;
        }

        // write directly to the device if it has pixels and is SkPMColor
        bool drawSprite;
        if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) {
            // we can write directly to the dst when doing the conversion
            dstBmp.extractSubset(&dstBmp, spriteRect);
            drawSprite = false;
        } else {
            // we convert to a temporary bitmap and draw that as a sprite
            dstBmp.setConfig(SkBitmap::kARGB_8888_Config,
                             spriteRect.width(),
                             spriteRect.height());
            if (!dstBmp.allocPixels()) {
                return;
            }
            drawSprite = true;
        }

        // copy pixels to dstBmp and convert from config8888 to native config.
        SkAutoLockPixels alp(bitmap);
        uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x,
                                               spriteRect.fTop - y);
        SkCopyConfig8888ToBitmap(dstBmp,
                                 srcPixels,
                                 bitmap.rowBytes(),
                                 config8888);

        if (drawSprite) {
            // we've clipped the sprite when we made a copy
            x = spriteRect.fLeft;
            y = spriteRect.fTop;
            sprite = &dstBmp;
        } else {
            return;
        }
    }

    SkPaint paint;
    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    SkCanvas canvas(this);
    canvas.drawSprite(*sprite, x, y, &paint);
}

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

void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
    draw.drawPaint(paint);
}

void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
                              const SkPoint pts[], const SkPaint& paint) {
    draw.drawPoints(mode, count, pts, paint);
}

void SkDevice::drawRect(const SkDraw& draw, const SkRect& r,
                            const SkPaint& paint) {
    draw.drawRect(r, paint);
}

void SkDevice::drawPath(const SkDraw& draw, const SkPath& path,
                        const SkPaint& paint, const SkMatrix* prePathMatrix,
                        bool pathIsMutable) {
    draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
}

void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
                          const SkIRect* srcRect,
                          const SkMatrix& matrix, const SkPaint& paint) {
    SkBitmap        tmp;    // storage if we need a subset of bitmap
    const SkBitmap* bitmapPtr = &bitmap;

    if (srcRect) {
        if (!bitmap.extractSubset(&tmp, *srcRect)) {
            return;     // extraction failed
        }
        bitmapPtr = &tmp;
    }
    draw.drawBitmap(*bitmapPtr, matrix, paint);
}

void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
                              int x, int y, const SkPaint& paint) {
    draw.drawSprite(bitmap, x, y, paint);
}

void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len,
                            SkScalar x, SkScalar y, const SkPaint& paint) {
    draw.drawText((const char*)text, len, x, y, paint);
}

void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
                               const SkScalar xpos[], SkScalar y,
                               int scalarsPerPos, const SkPaint& paint) {
    draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
}

void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text,
                                  size_t len, const SkPath& path,
                                  const SkMatrix* matrix,
                                  const SkPaint& paint) {
    draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
}

#ifdef SK_BUILD_FOR_ANDROID
void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
                                     const SkPoint pos[], const SkPaint& paint,
                                     const SkPath& path, const SkMatrix* matrix) {
    draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
}
#endif

void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
                                int vertexCount,
                                const SkPoint verts[], const SkPoint textures[],
                                const SkColor colors[], SkXfermode* xmode,
                                const uint16_t indices[], int indexCount,
                                const SkPaint& paint) {
    draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
                      indices, indexCount, paint);
}

void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
                              int x, int y, const SkPaint& paint) {
    draw.drawSprite(device->accessBitmap(false), x, y, paint);
}

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

static bool isSrcOver(SkXfermode* xfer) {
    if (NULL == xfer) {
        return true;
    }
    SkXfermode::Mode mode;
    return xfer->asMode(&mode) && (SkXfermode::kSrcOver_Mode == mode);
}

bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
    if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
        // we're cool with the paint as is
        return false;
    }

    if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
        !isSrcOver(paint.getXfermode()) ||
        paint.getRasterizer() ||
        paint.getPathEffect() ||
        paint.isFakeBoldText() ||
        paint.getStyle() != SkPaint::kFill_Style) {
        // turn off lcd
        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
        flags->fHinting = paint.getHinting();
        return true;
    }
    // we're cool with the paint as is
    return false;
}

<commit_msg>disable reduced checks if we're not enabling fast shadermask<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SkDevice.h"
#include "SkDraw.h"
#include "SkMetaData.h"
#include "SkRect.h"

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

SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
    fOrigin.setZero();
    fMetaData = NULL;
}

SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
    fOrigin.setZero();
    fMetaData = NULL;

    fBitmap.setConfig(config, width, height);
    fBitmap.allocPixels();
    fBitmap.setIsOpaque(isOpaque);
    if (!isOpaque) {
        fBitmap.eraseColor(0);
    }
}

SkDevice::~SkDevice() {
    delete fMetaData;
}

SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config,
                                           int width, int height,
                                           bool isOpaque) {
    return this->onCreateCompatibleDevice(config, width, height,
                                          isOpaque, kGeneral_Usage);
}

SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
                                                       int width, int height,
                                                       bool isOpaque) {
    return this->onCreateCompatibleDevice(config, width, height,
                                          isOpaque, kSaveLayer_Usage);
}

SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config,
                                             int width, int height,
                                             bool isOpaque,
                                             Usage usage) {
    return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque));
}

SkMetaData& SkDevice::getMetaData() {
    // metadata users are rare, so we lazily allocate it. If that changes we
    // can decide to just make it a field in the device (rather than a ptr)
    if (NULL == fMetaData) {
        fMetaData = new SkMetaData;
    }
    return *fMetaData;
}

void SkDevice::lockPixels() {
    if (fBitmap.lockPixelsAreWritable()) {
        fBitmap.lockPixels();
    }
}

void SkDevice::unlockPixels() {
    if (fBitmap.lockPixelsAreWritable()) {
        fBitmap.unlockPixels();
    }
}

const SkBitmap& SkDevice::accessBitmap(bool changePixels) {
    this->onAccessBitmap(&fBitmap);
    if (changePixels) {
        fBitmap.notifyPixelsChanged();
    }
    return fBitmap;
}

void SkDevice::getGlobalBounds(SkIRect* bounds) const {
    if (bounds) {
        bounds->setXYWH(fOrigin.x(), fOrigin.y(),
                        fBitmap.width(), fBitmap.height());
    }
}

void SkDevice::clear(SkColor color) {
    fBitmap.eraseColor(color);
}

void SkDevice::onAccessBitmap(SkBitmap* bitmap) {}

void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region,
                             const SkClipStack& clipStack) {
}

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

bool SkDevice::readPixels(SkBitmap* bitmap, int x, int y,
                          SkCanvas::Config8888 config8888) {
    if (SkBitmap::kARGB_8888_Config != bitmap->config() ||
        NULL != bitmap->getTexture()) {
        return false;
    }

    const SkBitmap& src = this->accessBitmap(false);

    SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(),
                                              bitmap->height());
    SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height());
    if (!srcRect.intersect(devbounds)) {
        return false;
    }

    SkBitmap tmp;
    SkBitmap* bmp;
    if (bitmap->isNull()) {
        tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(),
                                                   bitmap->height());
        if (!tmp.allocPixels()) {
            return false;
        }
        bmp = &tmp;
    } else {
        bmp = bitmap;
    }

    SkIRect subrect = srcRect;
    subrect.offset(-x, -y);
    SkBitmap bmpSubset;
    bmp->extractSubset(&bmpSubset, subrect);

    bool result = this->onReadPixels(bmpSubset,
                                     srcRect.fLeft,
                                     srcRect.fTop,
                                     config8888);
    if (result && bmp == &tmp) {
        tmp.swap(*bitmap);
    }
    return result;
}

#ifdef SK_CPU_LENDIAN
    #if   24 == SK_A32_SHIFT && 16 == SK_R32_SHIFT && \
           8 == SK_G32_SHIFT &&  0 == SK_B32_SHIFT
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            SkCanvas::kBGRA_Premul_Config8888;
    #elif 24 == SK_A32_SHIFT &&  0 == SK_R32_SHIFT && \
           8 == SK_G32_SHIFT && 16 == SK_B32_SHIFT
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            SkCanvas::kRGBA_Premul_Config8888;
    #else
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            (SkCanvas::Config8888) -1;
    #endif
#else
    #if    0 == SK_A32_SHIFT &&   8 == SK_R32_SHIFT && \
          16 == SK_G32_SHIFT &&  24 == SK_B32_SHIFT
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            SkCanvas::kBGRA_Premul_Config8888;
    #elif  0 == SK_A32_SHIFT &&  24 == SK_R32_SHIFT && \
          16 == SK_G32_SHIFT &&   8 == SK_B32_SHIFT
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            SkCanvas::kRGBA_Premul_Config8888;
    #else
        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
            (SkCanvas::Config8888) -1;
    #endif
#endif

#include <SkConfig8888.h>

bool SkDevice::onReadPixels(const SkBitmap& bitmap,
                            int x, int y,
                            SkCanvas::Config8888 config8888) {
    SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
    SkASSERT(!bitmap.isNull());
    SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));

    SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(),
                                              bitmap.height());
    const SkBitmap& src = this->accessBitmap(false);

    SkBitmap subset;
    if (!src.extractSubset(&subset, srcRect)) {
        return false;
    }
    if (SkBitmap::kARGB_8888_Config != subset.config()) {
        // It'd be preferable to do this directly to bitmap.
        subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
    }
    SkAutoLockPixels alp(bitmap);
    uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
    if ((SkCanvas::kNative_Premul_Config8888 == config8888 ||
         kPMColorAlias == config8888)) {
        SkCopyARGB8888BitmapTo(bmpPixels, bitmap.rowBytes(), subset);
    } else {
        SkCopyBitmapToConfig8888(bmpPixels,
                                 bitmap.rowBytes(),
                                 config8888,
                                 subset);
    }
    return true;
}

void SkDevice::writePixels(const SkBitmap& bitmap,
                           int x, int y,
                           SkCanvas::Config8888 config8888) {
    if (bitmap.isNull() || bitmap.getTexture()) {
        return;
    }
    const SkBitmap* sprite = &bitmap;
    // check whether we have to handle a config8888 that doesn't match SkPMColor
    if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
        SkCanvas::kNative_Premul_Config8888 != config8888 &&
        kPMColorAlias != config8888) {

        // We're going to have to convert from a config8888 to the native config
        // First we clip to the device bounds.
        SkBitmap dstBmp = this->accessBitmap(true);
        SkIRect spriteRect = SkIRect::MakeXYWH(x, y,
                                               bitmap.width(), bitmap.height());
        SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height());
        if (!spriteRect.intersect(devRect)) {
            return;
        }

        // write directly to the device if it has pixels and is SkPMColor
        bool drawSprite;
        if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) {
            // we can write directly to the dst when doing the conversion
            dstBmp.extractSubset(&dstBmp, spriteRect);
            drawSprite = false;
        } else {
            // we convert to a temporary bitmap and draw that as a sprite
            dstBmp.setConfig(SkBitmap::kARGB_8888_Config,
                             spriteRect.width(),
                             spriteRect.height());
            if (!dstBmp.allocPixels()) {
                return;
            }
            drawSprite = true;
        }

        // copy pixels to dstBmp and convert from config8888 to native config.
        SkAutoLockPixels alp(bitmap);
        uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x,
                                               spriteRect.fTop - y);
        SkCopyConfig8888ToBitmap(dstBmp,
                                 srcPixels,
                                 bitmap.rowBytes(),
                                 config8888);

        if (drawSprite) {
            // we've clipped the sprite when we made a copy
            x = spriteRect.fLeft;
            y = spriteRect.fTop;
            sprite = &dstBmp;
        } else {
            return;
        }
    }

    SkPaint paint;
    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    SkCanvas canvas(this);
    canvas.drawSprite(*sprite, x, y, &paint);
}

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

void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
    draw.drawPaint(paint);
}

void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
                              const SkPoint pts[], const SkPaint& paint) {
    draw.drawPoints(mode, count, pts, paint);
}

void SkDevice::drawRect(const SkDraw& draw, const SkRect& r,
                            const SkPaint& paint) {
    draw.drawRect(r, paint);
}

void SkDevice::drawPath(const SkDraw& draw, const SkPath& path,
                        const SkPaint& paint, const SkMatrix* prePathMatrix,
                        bool pathIsMutable) {
    draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
}

void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
                          const SkIRect* srcRect,
                          const SkMatrix& matrix, const SkPaint& paint) {
    SkBitmap        tmp;    // storage if we need a subset of bitmap
    const SkBitmap* bitmapPtr = &bitmap;

    if (srcRect) {
        if (!bitmap.extractSubset(&tmp, *srcRect)) {
            return;     // extraction failed
        }
        bitmapPtr = &tmp;
    }
    draw.drawBitmap(*bitmapPtr, matrix, paint);
}

void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
                              int x, int y, const SkPaint& paint) {
    draw.drawSprite(bitmap, x, y, paint);
}

void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len,
                            SkScalar x, SkScalar y, const SkPaint& paint) {
    draw.drawText((const char*)text, len, x, y, paint);
}

void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
                               const SkScalar xpos[], SkScalar y,
                               int scalarsPerPos, const SkPaint& paint) {
    draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
}

void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text,
                                  size_t len, const SkPath& path,
                                  const SkMatrix* matrix,
                                  const SkPaint& paint) {
    draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
}

#ifdef SK_BUILD_FOR_ANDROID
void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
                                     const SkPoint pos[], const SkPaint& paint,
                                     const SkPath& path, const SkMatrix* matrix) {
    draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
}
#endif

void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
                                int vertexCount,
                                const SkPoint verts[], const SkPoint textures[],
                                const SkColor colors[], SkXfermode* xmode,
                                const uint16_t indices[], int indexCount,
                                const SkPaint& paint) {
    draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
                      indices, indexCount, paint);
}

void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
                              int x, int y, const SkPaint& paint) {
    draw.drawSprite(device->accessBitmap(false), x, y, paint);
}

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

static bool isSrcOver(SkXfermode* xfer) {
    if (NULL == xfer) {
        return true;
    }
    SkXfermode::Mode mode;
    return xfer->asMode(&mode) && (SkXfermode::kSrcOver_Mode == mode);
}

bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
    if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
        // we're cool with the paint as is
        return false;
    }

    if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
#ifndef SK_ENABLE_FAST_SHADERMASK
        paint.getShader() ||
        paint.getMaskFilter() ||
        paint.getColorFilter() ||
#endif
        !isSrcOver(paint.getXfermode()) ||
        paint.getRasterizer() ||
        paint.getPathEffect() ||
        paint.isFakeBoldText() ||
        paint.getStyle() != SkPaint::kFill_Style) {
        // turn off lcd
        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
        flags->fHinting = paint.getHinting();
        return true;
    }
    // we're cool with the paint as is
    return false;
}

<|endoftext|>


<commit_before>#include "gui_main.h"

//Error reporting will be redirected to the string err_msg.
//If an error values is returned the error message will then be in err_msg,
static QString err_msg;
static void gui_err_reporter(int err, const char* msg);

int main(int argc, char** argv)
{
	set_err_reporter(gui_err_reporter);

	QApplication app(argc, argv);
	win wnd;

	return app.exec();
}

win::win(QWidget* app) :
	QWidget(app),
	grid(this),
	err_lbl(this),
	in_txtbox(this),
	calc_btn("Calculate", this),
	totmm_lbl("Total Molar Mass:", this),
	unit_lbl("g/mol", this),
	totmm_txtbox(this),
	elem_lst(this)
{
	//setup the window
	this->setWindowTitle("chemtool");
	this->resize(350, 250);
	this->setMinimumHeight(250);
	this->setMinimumWidth(250);

	//setup the grid
	grid.setRowMinimumHeight(0, 20);
	grid.setRowMinimumHeight(2, 40);

	//setup the error label
	err_lbl.setAlignment(Qt::AlignLeft | Qt::AlignBottom);
	err_lbl.setWordWrap(true);
	grid.addWidget(&err_lbl, 0, 0, 1, 3);

	//setup the input textbox
	in_txtbox.setAlignment(Qt::AlignLeft | Qt::AlignTop);
	grid.addWidget(&in_txtbox, 1, 0, 1, 3);

	//setup the button which starts the processing
	grid.addWidget(&calc_btn, 2, 0, 1, 3, Qt::AlignCenter);
	connect(&calc_btn, SIGNAL(clicked()), this, SLOT(do_process_input()));

	//setup the output for the total molar mass
	totmm_txtbox.setReadOnly(false);
	totmm_txtbox.setAlignment(Qt::AlignRight);
	grid.addWidget(&totmm_txtbox, 3, 1, 1, 1);
	grid.addWidget(&totmm_lbl, 3, 0, 1, 1);
	grid.addWidget(&unit_lbl, 3, 2, 1, 1);

	//setup the element list
	elem_lst.setFont(QFont("monospace", 10));
	grid.addWidget(&elem_lst, 4, 0, 1, 3);

	this->show();
}

void win::do_process_input()
{
	if (in_txtbox.text().length() < 1)
		return;

	int err = 0;
	double tot_mm = 0.0f;
	char elem_data[BUFSIZ] = {0};

	err_lbl.setText("");
	struct elem_vec* evec = create_elem_vec(
		in_txtbox.text().toUtf8().constData());
	if (!evec){
		report_mem_err();
		goto exit;
	}

	err = process_input(in_txtbox.text().toUtf8().constData(), evec);
	//handle any errors
	if (err){
		switch (err){
		case EOOMEM:
			report_mem_err();
			break;
		case EFOPEN:
		case EDBFMT:
			QMessageBox::critical(this, "Database error", err_msg);
			break;
		case EENAME:
		case EARGFMT:
			err_lbl.setText(
				QString("%1").
				arg(err_msg));
			break;
		}
		goto exit;
	}

	//if no errors occured output all the data
	for (int i = 0; i < evec->size; i++){
		tot_mm += evec->elms[i].weight * evec->elms[i].quant;
		snprintf(elem_data, BUFSIZ, "%s%6i    %10f g/mol    %s",
			evec->elms[i].sname, evec->elms[i].quant,
			evec->elms[i].weight, evec->elms[i].lname);
		elem_lst.addItem(elem_data);
	}
	totmm_txtbox.setText(QString::number(tot_mm));

exit:
	destroy_elem_vec(evec);
}

void win::report_mem_err()
{
	//A memory allocation was unsuccesful. This is critical so inform
	//the user and exit the program.
	QMessageBox::critical(this, "Memory error", err_msg);
	QApplication::quit();
}

static void gui_err_reporter(int err, const char* msg)
{
	err_msg.clear();
	err_msg += get_base_err_msg(err);
	err_msg += msg;
}<commit_msg>"Fixed bug" and made the fields reset on new input<commit_after>#include "gui_main.h"

//Error reporting will be redirected to the string err_msg.
//If an error values is returned the error message will then be in err_msg,
static QString err_msg;
static void gui_err_reporter(int err, const char* msg);

int main(int argc, char** argv)
{
	set_err_reporter(gui_err_reporter);

	QApplication app(argc, argv);
	win wnd;

	return app.exec();
}

win::win(QWidget* app) :
	QWidget(app),
	grid(this),
	err_lbl(this),
	in_txtbox(this),
	calc_btn("Calculate", this),
	totmm_lbl("Total Molar Mass:", this),
	unit_lbl("g/mol", this),
	totmm_txtbox(this),
	elem_lst(this)
{
	//setup the window
	this->setWindowTitle("chemtool");
	this->resize(350, 250);
	this->setMinimumHeight(250);
	this->setMinimumWidth(250);

	//setup the grid
	grid.setRowMinimumHeight(0, 20);
	grid.setRowMinimumHeight(2, 40);

	//setup the error label
	err_lbl.setAlignment(Qt::AlignLeft | Qt::AlignBottom);
	err_lbl.setWordWrap(true);
	grid.addWidget(&err_lbl, 0, 0, 1, 3);

	//setup the input textbox
	in_txtbox.setAlignment(Qt::AlignLeft | Qt::AlignTop);
	grid.addWidget(&in_txtbox, 1, 0, 1, 3);

	//setup the button which starts the processing
	grid.addWidget(&calc_btn, 2, 0, 1, 3, Qt::AlignCenter);
	connect(&calc_btn, SIGNAL(clicked()), this, SLOT(do_process_input()));

	//setup the output for the total molar mass
	totmm_txtbox.setReadOnly(false);
	totmm_txtbox.setAlignment(Qt::AlignRight);
	grid.addWidget(&totmm_txtbox, 3, 1, 1, 1);
	grid.addWidget(&totmm_lbl, 3, 0, 1, 1);
	grid.addWidget(&unit_lbl, 3, 2, 1, 1);

	//setup the element list
	elem_lst.setFont(QFont("monospace", 10));
	grid.addWidget(&elem_lst, 4, 0, 1, 3);

	this->show();
}

void win::do_process_input()
{
	if (in_txtbox.text().length() < 1)
		return;

	int err = 0;
	double tot_mm = 0.0f;
	char elem_data[BUFSIZ] = {0};

	//reset all outputs
	err_lbl.setText("");
	totmm_txtbox.setText("");
	elem_lst.clear();

	struct elem_vec* evec = create_elem_vec(
		in_txtbox.text().toUtf8().constData());
	if (!evec){
		report_mem_err();
		goto exit;
	}

	err = process_input(in_txtbox.text().toUtf8().constData(), evec);
	//handle any errors
	if (err){
		switch (err){
		case EOOMEM:
			report_mem_err();
			break;
		case EFOPEN:
		case EDBFMT:
			QMessageBox::critical(this, "Database error", err_msg);
			break;
		case EENAME:
		case EARGFMT:
			err_lbl.setText(
				QString("*%1").
				arg(err_msg));
			break;
		}
		goto exit;
	}

	//if no errors occured output all the data
	for (int i = 0; i < evec->size; i++){
		tot_mm += evec->elms[i].weight * evec->elms[i].quant;
		snprintf(elem_data, BUFSIZ, "%s%6i    %10f g/mol    %s",
			evec->elms[i].sname, evec->elms[i].quant,
			evec->elms[i].weight, evec->elms[i].lname);
		elem_lst.addItem(elem_data);
	}
	totmm_txtbox.setText(QString::number(tot_mm));

exit:
	destroy_elem_vec(evec);
}

void win::report_mem_err()
{
	//A memory allocation was unsuccesful. This is critical so inform
	//the user and exit the program.
	QMessageBox::critical(this, "Memory error", err_msg);
	QApplication::quit();
}

static void gui_err_reporter(int err, const char* msg)
{
	err_msg.clear();
	err_msg += get_base_err_msg(err);
	err_msg += msg;
}<|endoftext|>


<commit_before>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2013 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "CppImportLogger.h"

namespace CppImport {

CppImportLogger::CppImportLogger(clang::SourceManager* sourceManager) :
	sourceManger_(sourceManager)
{
	initStreams();
}

CppImportLogger::~CppImportLogger()
{
	delete errStream_;
	delete warnStream_;
}

void CppImportLogger::writeOut(QString &inWhichClass, QString &reason, QString &clangType, clang::NamedDecl* decl, CppImportLogger::OUTTYPE outType)
{
	QTextStream* outStream;
	switch(outType)
	{
		case ERROR:
			outStream = errStream_;
			break;
		case WARNING:
			outStream = warnStream_;
			break;
		default:
			return;
	}

	int newCount = countMap_.value(clangType) + 1;
	countMap_.insert(clangType, newCount);

	std::pair<clang::FileID,unsigned> decomposedLoc = sourceManger_->getDecomposedLoc(decl->getLocation());
	(*outStream) << "ERR/WARN: \t In class : " << inWhichClass << " \n\t reason : " << reason
					 << " \n\t in clang node : " << clangType
					 << " \n\t clang node name : " << QString::fromStdString(decl->getNameAsString())
					 << " \n\t in file : " << sourceManger_->getBufferName(decl->getLocation())
					 << " \n\t on line : " << sourceManger_->getLineNumber(decomposedLoc.first,decomposedLoc.second)
					 << "\n";

}

void CppImportLogger::writeOut(QString &inWhichClass, QString &reason, QString &clangType, clang::Stmt* stmt, CppImportLogger::OUTTYPE outType)
{
	QTextStream* outStream;
	switch(outType)
	{
		case ERROR:
			outStream = errStream_;
			break;
		case WARNING:
			outStream = warnStream_;
			break;
		default:
			return;
	}

	int newCount = countMap_.value(clangType) + 1;
	countMap_.insert(clangType, newCount);

	std::pair<clang::FileID,unsigned> decomposedLoc = sourceManger_->getDecomposedLoc(stmt->getLocStart());
	(*outStream) << "ERR/WARN: \t In class : " << inWhichClass << " \n\t reason : " << reason
					 << " \n\t in clang node : " << clangType
						 // TODO maybe output something more useful
					 << " \n\t in stmt class node : " << stmt->getStmtClassName()
					 << " \n\t in file : " << sourceManger_->getBufferName(stmt->getLocStart())
					 << " \n\t on line : " << sourceManger_->getLineNumber(decomposedLoc.first,decomposedLoc.second)
					 << "\n";

}

void CppImportLogger::typeNotSupported(QString typeName)
{
	int newCount = typeCountMap_.value(typeName) + 1;
	typeCountMap_.insert(typeName, newCount);
}

void CppImportLogger::initStreams()
{
	if(writeToFile_)
	{
		std::cout << "LOGGER ERR: NOT YET SUPPORTED TO WRITE TO FILE" << std::endl;
	}
	else
	{
		errStream_ = new QTextStream(stderr);
		warnStream_ = new QTextStream(stdout);
	}
}

void CppImportLogger::outputStatistics()
{
	(*warnStream_) << "\n==========Statistics==========\n"
						<<"\nStatistics of Warnings and Errors:\n";
	if(!countMap_.empty())
		for(auto iter = countMap_.constBegin(); iter != countMap_.constEnd(); ++iter)
			(*warnStream_) << iter.key() << ":\t\t" << iter.value() << "\n";

	(*warnStream_) << "\nTypes not supported by envision:\n";
	if(!typeCountMap_.empty())
		for(auto it = typeCountMap_.constBegin(); it != countMap_.constEnd(); ++it)
			(*warnStream_) << it.key() << ":\t\t" << it.value() << "\n";

	(*warnStream_) << "\n========Statistics End========\n";
}

}
<commit_msg>Fix a bug in logger and enhance output format<commit_after>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2013 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "CppImportLogger.h"

namespace CppImport {

CppImportLogger::CppImportLogger(clang::SourceManager* sourceManager) :
	sourceManger_(sourceManager)
{
	initStreams();
}

CppImportLogger::~CppImportLogger()
{
	delete errStream_;
	delete warnStream_;
}

void CppImportLogger::writeOut(QString &inWhichClass, QString &reason, QString &clangType, clang::NamedDecl* decl, CppImportLogger::OUTTYPE outType)
{
	QTextStream* outStream;
	switch(outType)
	{
		case ERROR:
			outStream = errStream_;
			break;
		case WARNING:
			outStream = warnStream_;
			break;
		default:
			return;
	}

	int newCount = countMap_.value(clangType) + 1;
	countMap_.insert(clangType, newCount);

	std::pair<clang::FileID,unsigned> decomposedLoc = sourceManger_->getDecomposedLoc(decl->getLocation());
	(*outStream) << "ERR/WARN: \t In class : " << inWhichClass << " \n\t reason : " << reason
					 << " \n\t in clang node : " << clangType
					 << " \n\t clang node name : " << QString::fromStdString(decl->getNameAsString())
					 << " \n\t in file : " << sourceManger_->getBufferName(decl->getLocation())
					 << " \n\t on line : " << sourceManger_->getLineNumber(decomposedLoc.first,decomposedLoc.second)
					 << "\n";

}

void CppImportLogger::writeOut(QString &inWhichClass, QString &reason, QString &clangType, clang::Stmt* stmt, CppImportLogger::OUTTYPE outType)
{
	QTextStream* outStream;
	switch(outType)
	{
		case ERROR:
			outStream = errStream_;
			break;
		case WARNING:
			outStream = warnStream_;
			break;
		default:
			return;
	}

	int newCount = countMap_.value(clangType) + 1;
	countMap_.insert(clangType, newCount);

	std::pair<clang::FileID,unsigned> decomposedLoc = sourceManger_->getDecomposedLoc(stmt->getLocStart());
	(*outStream) << "ERR/WARN: \t In class : " << inWhichClass << " \n\t reason : " << reason
					 << " \n\t in clang node : " << clangType
						 // TODO maybe output something more useful
					 << " \n\t in stmt class node : " << stmt->getStmtClassName()
					 << " \n\t in file : " << sourceManger_->getBufferName(stmt->getLocStart())
					 << " \n\t on line : " << sourceManger_->getLineNumber(decomposedLoc.first,decomposedLoc.second)
					 << "\n";

}

void CppImportLogger::typeNotSupported(QString typeName)
{
	int newCount = typeCountMap_.value(typeName) + 1;
	typeCountMap_.insert(typeName, newCount);
}

void CppImportLogger::initStreams()
{
	if(writeToFile_)
	{
		std::cout << "LOGGER ERR: NOT YET SUPPORTED TO WRITE TO FILE" << std::endl;
	}
	else
	{
		errStream_ = new QTextStream(stderr);
		warnStream_ = new QTextStream(stdout);
	}
}

void CppImportLogger::outputStatistics()
{
	(*warnStream_) << endl;
	(*warnStream_) << qSetFieldWidth(36) << center << qSetPadChar('=')
						<< "Statistics of warnings and errors" << reset << endl;

	if(!countMap_.empty())
		for(auto iter = countMap_.constBegin(); iter != countMap_.constEnd(); ++iter)
			(*warnStream_) << left << qSetFieldWidth(30) << iter.key() + ":"
								<< right << qSetFieldWidth(6) << iter.value() << endl;

	(*warnStream_) << "\nTypes not supported by envision:\n";
	if(!typeCountMap_.empty())
		for(auto it = typeCountMap_.constBegin(); it != typeCountMap_.constEnd(); ++it)
			(*warnStream_) << left << qSetFieldWidth(30) << it.key() + ":"
								<< right << qSetFieldWidth(6) << it.value() << endl;

	(*warnStream_) << endl;
	(*warnStream_) << qSetFieldWidth(36) << center << qSetPadChar('=')
						<< "Statistics End" << reset << endl;
}

}
<|endoftext|>


<commit_before>#include "rssparser.h"

#include <cstring>
#include <ctime>
#include <libxml/tree.h>

#include "exception.h"

#include "utils.h"

namespace rsspp {

std::string RssParser::get_content(xmlNode* node)
{
	std::string retval;
	if (node) {
		xmlChar* content = xmlNodeGetContent(node);
		if (content) {
			retval = (const char*)content;
			xmlFree(content);
		}
	}
	return retval;
}

void RssParser::cleanup_namespaces(xmlNodePtr node)
{
	node->ns = nullptr;
	for (auto ptr = node->children; ptr != nullptr; ptr = ptr->next) {
		cleanup_namespaces(ptr);
	}
}

std::string RssParser::get_xml_content(xmlNode* node)
{
	xmlBufferPtr buf = xmlBufferCreate();
	std::string result;

	cleanup_namespaces(node);

	if (node->children) {
		for (xmlNodePtr ptr = node->children; ptr != nullptr;
			ptr = ptr->next) {
			if (xmlNodeDump(buf, doc, ptr, 0, 0) >= 0) {
				result.append(
					(const char*)xmlBufferContent(buf));
				xmlBufferEmpty(buf);
			} else {
				result.append(get_content(ptr));
			}
		}
	} else {
		result = get_content(node); // fallback
	}
	xmlBufferFree(buf);

	return result;
}

std::string RssParser::get_prop(xmlNode* node,
	const std::string& prop,
	const std::string& ns)
{
	std::string retval;
	if (node) {
		xmlChar* value = nullptr;
		if (ns.empty()) {
			value = xmlGetProp(node,
					reinterpret_cast<const xmlChar*>(prop.c_str()));
		} else {
			value = xmlGetNsProp(node,
					reinterpret_cast<const xmlChar*>(prop.c_str()),
					reinterpret_cast<const xmlChar*>(ns.c_str()));
		}
		if (value) {
			retval = reinterpret_cast<const char*>(value);
			xmlFree(value);
		}
	}
	return retval;
}

std::string RssParser::w3cdtf_to_rfc822(const std::string& w3cdtf)
{
	return __w3cdtf_to_rfc822(w3cdtf);
}

std::string RssParser::__w3cdtf_to_rfc822(const std::string& w3cdtf)
{
	if (w3cdtf.empty()) {
		return "";
	}

	struct tm stm;
	memset(&stm, 0, sizeof(stm));
	stm.tm_mday = 1;

	char* ptr = strptime(w3cdtf.c_str(), "%Y", &stm);

	if (ptr != nullptr) {
		ptr = strptime(ptr, "-%m", &stm);
	} else {
		return "";
	}

	if (ptr != nullptr) {
		ptr = strptime(ptr, "-%d", &stm);
	}
	if (ptr != nullptr) {
		ptr = strptime(ptr, "T%H", &stm);
	}
	if (ptr != nullptr) {
		ptr = strptime(ptr, ":%M", &stm);
	}
	if (ptr != nullptr) {
		ptr = strptime(ptr, ":%S", &stm);
	}

	int offs = 0;
	if (ptr != nullptr) {
		if (ptr[0] == '+' || ptr[0] == '-') {
			unsigned int hour, min;
			if (sscanf(ptr + 1, "%02u:%02u", &hour, &min) == 2) {
				offs = 60 * 60 * hour + 60 * min;
				if (ptr[0] == '+') {
					offs = -offs;
				}
				stm.tm_gmtoff = offs;
			}
		} else if (ptr[0] == 'Z') {
			stm.tm_gmtoff = 0;
		}
	}

	// tm_isdst will force mktime to consider DST, like localtime(), but
	// then the offset will be zeroed out, since that was manually added
	// https://github.com/akrennmair/newsbeuter/issues/369
	stm.tm_isdst = -1;
	time_t gmttime = mktime(&stm) + offs;
	return newsboat::utils::mt_strf_localtime("%a, %d %b %Y %H:%M:%S +0000",
			gmttime);
}

bool RssParser::node_is(xmlNode* node, const char* name, const char* ns_uri)
{
	if (!node || !name || !node->name) {
		return false;
	}

	if (strcmp((const char*)node->name, name) == 0) {
		if (!ns_uri && !node->ns) {
			return true;
		}
		if (ns_uri && node->ns && node->ns->href &&
			strcmp((const char*)node->ns->href, ns_uri) == 0) {
			return true;
		}
	}
	return false;
}

} // namespace rsspp
<commit_msg>Check return code of mktime<commit_after>#include "rssparser.h"

#include <cstring>
#include <ctime>
#include <libxml/tree.h>

#include "exception.h"

#include "utils.h"

namespace rsspp {

std::string RssParser::get_content(xmlNode* node)
{
	std::string retval;
	if (node) {
		xmlChar* content = xmlNodeGetContent(node);
		if (content) {
			retval = (const char*)content;
			xmlFree(content);
		}
	}
	return retval;
}

void RssParser::cleanup_namespaces(xmlNodePtr node)
{
	node->ns = nullptr;
	for (auto ptr = node->children; ptr != nullptr; ptr = ptr->next) {
		cleanup_namespaces(ptr);
	}
}

std::string RssParser::get_xml_content(xmlNode* node)
{
	xmlBufferPtr buf = xmlBufferCreate();
	std::string result;

	cleanup_namespaces(node);

	if (node->children) {
		for (xmlNodePtr ptr = node->children; ptr != nullptr;
			ptr = ptr->next) {
			if (xmlNodeDump(buf, doc, ptr, 0, 0) >= 0) {
				result.append(
					(const char*)xmlBufferContent(buf));
				xmlBufferEmpty(buf);
			} else {
				result.append(get_content(ptr));
			}
		}
	} else {
		result = get_content(node); // fallback
	}
	xmlBufferFree(buf);

	return result;
}

std::string RssParser::get_prop(xmlNode* node,
	const std::string& prop,
	const std::string& ns)
{
	std::string retval;
	if (node) {
		xmlChar* value = nullptr;
		if (ns.empty()) {
			value = xmlGetProp(node,
					reinterpret_cast<const xmlChar*>(prop.c_str()));
		} else {
			value = xmlGetNsProp(node,
					reinterpret_cast<const xmlChar*>(prop.c_str()),
					reinterpret_cast<const xmlChar*>(ns.c_str()));
		}
		if (value) {
			retval = reinterpret_cast<const char*>(value);
			xmlFree(value);
		}
	}
	return retval;
}

std::string RssParser::w3cdtf_to_rfc822(const std::string& w3cdtf)
{
	return __w3cdtf_to_rfc822(w3cdtf);
}

std::string RssParser::__w3cdtf_to_rfc822(const std::string& w3cdtf)
{
	if (w3cdtf.empty()) {
		return "";
	}

	struct tm stm;
	memset(&stm, 0, sizeof(stm));
	stm.tm_mday = 1;

	char* ptr = strptime(w3cdtf.c_str(), "%Y", &stm);

	if (ptr != nullptr) {
		ptr = strptime(ptr, "-%m", &stm);
	} else {
		return "";
	}

	if (ptr != nullptr) {
		ptr = strptime(ptr, "-%d", &stm);
	}
	if (ptr != nullptr) {
		ptr = strptime(ptr, "T%H", &stm);
	}
	if (ptr != nullptr) {
		ptr = strptime(ptr, ":%M", &stm);
	}
	if (ptr != nullptr) {
		ptr = strptime(ptr, ":%S", &stm);
	}

	int offs = 0;
	if (ptr != nullptr) {
		if (ptr[0] == '+' || ptr[0] == '-') {
			unsigned int hour, min;
			if (sscanf(ptr + 1, "%02u:%02u", &hour, &min) == 2) {
				offs = 60 * 60 * hour + 60 * min;
				if (ptr[0] == '+') {
					offs = -offs;
				}
				stm.tm_gmtoff = offs;
			}
		} else if (ptr[0] == 'Z') {
			stm.tm_gmtoff = 0;
		}
	}

	// tm_isdst will force mktime to consider DST, like localtime(), but
	// then the offset will be zeroed out, since that was manually added
	// https://github.com/akrennmair/newsbeuter/issues/369
	stm.tm_isdst = -1;

	const time_t local_time = mktime(&stm);
	if (local_time == -1) {
		return "";
	}

	const time_t gmttime = local_time + offs;
	return newsboat::utils::mt_strf_localtime("%a, %d %b %Y %H:%M:%S +0000",
			gmttime);
}

bool RssParser::node_is(xmlNode* node, const char* name, const char* ns_uri)
{
	if (!node || !name || !node->name) {
		return false;
	}

	if (strcmp((const char*)node->name, name) == 0) {
		if (!ns_uri && !node->ns) {
			return true;
		}
		if (ns_uri && node->ns && node->ns->href &&
			strcmp((const char*)node->ns->href, ns_uri) == 0) {
			return true;
		}
	}
	return false;
}

} // namespace rsspp
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: VKey.hxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: hr $ $Date: 2001-10-16 18:04:55 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_SDBCX_KEY_HXX_
#define _CONNECTIVITY_SDBCX_KEY_HXX_

#ifndef COMPHELPER_IDPROPERTYARRAYUSAGEHELPER_HXX
#include <comphelper/IdPropArrayHelper.hxx>
#endif
#ifndef _CONNECTIVITY_COMMONTOOLS_HXX_
#include "connectivity/CommonTools.hxx"
#endif
#ifndef _COMPHELPER_BROADCASTHELPER_HXX_
#include <comphelper/broadcasthelper.hxx>
#endif
#ifndef _CONNECTIVITY_SDBCX_TYPEDEF_HXX_
#include "connectivity/sdbcx/VTypeDef.hxx"
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XNAMED_HPP_
#include <com/sun/star/container/XNamed.hpp>
#endif
#ifndef _CONNECTIVITY_SDBCX_IREFRESHABLE_HXX_
#include "connectivity/sdbcx/IRefreshable.hxx"
#endif
#ifndef _CONNECTIVITY_SDBCX_DESCRIPTOR_HXX_
#include "connectivity/sdbcx/VDescriptor.hxx"
#endif
#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _COM_SUN_STAR_SDBCX_XDATADESCRIPTORFACTORY_HPP_
#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
#endif

namespace connectivity
{
    namespace sdbcx
    {

        typedef ::cppu::ImplHelper1< ::com::sun::star::sdbcx::XDataDescriptorFactory > OKey_BASE;
        class OCollection;

        class OKey :            public comphelper::OBaseMutex,
                                public ODescriptor_BASE,
                                public IRefreshableColumns,
                                public ::comphelper::OIdPropertyArrayUsageHelper<OKey>,
                                public ODescriptor,
                                public OKey_BASE
        {
        protected:
            ::rtl::OUString m_ReferencedTable;
            sal_Int32       m_Type;
            sal_Int32       m_UpdateRule;
            sal_Int32       m_DeleteRule;

            OCollection*    m_pColumns;

            using ODescriptor_BASE::rBHelper;
            // OPropertyArrayUsageHelper
            virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const;
            // OPropertySetHelper
            virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper();
        public:
            OKey(sal_Bool _bCase);
            OKey(   const ::rtl::OUString& _Name,
                    const ::rtl::OUString& _ReferencedTable,
                    sal_Int32       _Type,
                    sal_Int32       _UpdateRule,
                    sal_Int32       _DeleteRule,
                    sal_Bool _bCase);

            virtual ~OKey( );

            DECLARE_SERVICE_INFO();
            //XInterface
            virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL acquire() throw();
            virtual void SAL_CALL release() throw();
            //XTypeProvider
            virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes(  ) throw(::com::sun::star::uno::RuntimeException);
            // ODescriptor
            virtual void construct();

            // ::cppu::OComponentHelper
            virtual void SAL_CALL disposing();
            // XPropertySet
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo(  ) throw(::com::sun::star::uno::RuntimeException);
            // XColumnsSupplier
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getColumns(  ) throw(::com::sun::star::uno::RuntimeException);

            // XNamed
            virtual ::rtl::OUString SAL_CALL getName(  ) throw(::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setName( const ::rtl::OUString& aName ) throw(::com::sun::star::uno::RuntimeException);
            // XDataDescriptorFactory
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > SAL_CALL createDataDescriptor(  ) throw(::com::sun::star::uno::RuntimeException);
        };
    }
}

#endif // _CONNECTIVITY_SDBCX_KEY_HXX_

<commit_msg>INTEGRATION: CWS ooo19126 (1.9.342); FILE MERGED 2005/09/05 17:22:43 rt 1.9.342.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: VKey.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 05:05:04 $
 *
 *  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
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_SDBCX_KEY_HXX_
#define _CONNECTIVITY_SDBCX_KEY_HXX_

#ifndef COMPHELPER_IDPROPERTYARRAYUSAGEHELPER_HXX
#include <comphelper/IdPropArrayHelper.hxx>
#endif
#ifndef _CONNECTIVITY_COMMONTOOLS_HXX_
#include "connectivity/CommonTools.hxx"
#endif
#ifndef _COMPHELPER_BROADCASTHELPER_HXX_
#include <comphelper/broadcasthelper.hxx>
#endif
#ifndef _CONNECTIVITY_SDBCX_TYPEDEF_HXX_
#include "connectivity/sdbcx/VTypeDef.hxx"
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XNAMED_HPP_
#include <com/sun/star/container/XNamed.hpp>
#endif
#ifndef _CONNECTIVITY_SDBCX_IREFRESHABLE_HXX_
#include "connectivity/sdbcx/IRefreshable.hxx"
#endif
#ifndef _CONNECTIVITY_SDBCX_DESCRIPTOR_HXX_
#include "connectivity/sdbcx/VDescriptor.hxx"
#endif
#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _COM_SUN_STAR_SDBCX_XDATADESCRIPTORFACTORY_HPP_
#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
#endif

namespace connectivity
{
    namespace sdbcx
    {

        typedef ::cppu::ImplHelper1< ::com::sun::star::sdbcx::XDataDescriptorFactory > OKey_BASE;
        class OCollection;

        class OKey :            public comphelper::OBaseMutex,
                                public ODescriptor_BASE,
                                public IRefreshableColumns,
                                public ::comphelper::OIdPropertyArrayUsageHelper<OKey>,
                                public ODescriptor,
                                public OKey_BASE
        {
        protected:
            ::rtl::OUString m_ReferencedTable;
            sal_Int32       m_Type;
            sal_Int32       m_UpdateRule;
            sal_Int32       m_DeleteRule;

            OCollection*    m_pColumns;

            using ODescriptor_BASE::rBHelper;
            // OPropertyArrayUsageHelper
            virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const;
            // OPropertySetHelper
            virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper();
        public:
            OKey(sal_Bool _bCase);
            OKey(   const ::rtl::OUString& _Name,
                    const ::rtl::OUString& _ReferencedTable,
                    sal_Int32       _Type,
                    sal_Int32       _UpdateRule,
                    sal_Int32       _DeleteRule,
                    sal_Bool _bCase);

            virtual ~OKey( );

            DECLARE_SERVICE_INFO();
            //XInterface
            virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL acquire() throw();
            virtual void SAL_CALL release() throw();
            //XTypeProvider
            virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes(  ) throw(::com::sun::star::uno::RuntimeException);
            // ODescriptor
            virtual void construct();

            // ::cppu::OComponentHelper
            virtual void SAL_CALL disposing();
            // XPropertySet
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo(  ) throw(::com::sun::star::uno::RuntimeException);
            // XColumnsSupplier
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getColumns(  ) throw(::com::sun::star::uno::RuntimeException);

            // XNamed
            virtual ::rtl::OUString SAL_CALL getName(  ) throw(::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL setName( const ::rtl::OUString& aName ) throw(::com::sun::star::uno::RuntimeException);
            // XDataDescriptorFactory
            virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > SAL_CALL createDataDescriptor(  ) throw(::com::sun::star::uno::RuntimeException);
        };
    }
}

#endif // _CONNECTIVITY_SDBCX_KEY_HXX_

<|endoftext|>