<commit_before>
#include "prelude.hpp"
#include "builtin/exception.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/float.hpp"
#include "builtin/array.hpp"
#include "builtin/string.hpp"

#include "primitives.hpp"
#include "vm/object_utils.hpp"

#include <iostream>

namespace rubinius {

  void Fixnum::init(STATE) {
    GO(fixnum_class).set(state->new_class("Fixnum", G(integer)));
    G(fixnum_class)->instance_type(state, Fixnum::from(FixnumType));

    G(fixnum_class)->set_const(state, "MIN", Fixnum::from(FIXNUM_MIN));
    G(fixnum_class)->set_const(state, "MAX", Fixnum::from(FIXNUM_MAX));
  }

  int Fixnum::to_int() const {
    return (int)STRIP_FIXNUM_TAG(this);
  }

  unsigned int Fixnum::to_uint() const {
    return (unsigned int)STRIP_FIXNUM_TAG(this);
  }

  long Fixnum::to_long() const {
    return (long)STRIP_FIXNUM_TAG(this);
  }

  unsigned long Fixnum::to_ulong() const {
    return (unsigned long)STRIP_FIXNUM_TAG(this);
  }

  long long Fixnum::to_long_long() const {
    return (long long)STRIP_FIXNUM_TAG(this);
  }

  unsigned long long Fixnum::to_ulong_long() const {
    return (unsigned long long)STRIP_FIXNUM_TAG(this);
  }

  Integer* Fixnum::add(STATE, Bignum* other) {
    return other->add(state, this);
  }

  Float* Fixnum::add(STATE, Float* other) {
    return other->add(state, this);
  }

  Integer* Fixnum::sub(STATE, Bignum* other) {
    return as<Bignum>(other->neg(state))->add(state, this);
  }

  Float* Fixnum::sub(STATE, Float* other) {
    return Float::coerce(state, this)->sub(state, other);
  }

#define SQRT_LONG_MAX ((native_int)1<<((sizeof(native_int)*CHAR_BIT-1)/2))
/*tests if N*N would overflow*/
#define FIT_SQRT(n) (((n)<SQRT_LONG_MAX)&&((n)>-SQRT_LONG_MAX))

  Integer* Fixnum::mul(STATE, Fixnum* other) {
    native_int a  = to_native();
    native_int b  = other->to_native();

    if(a == 0 || b == 0) return Fixnum::from(0);

    // Adapted from the logic in 1.9
    if(FIT_SQRT(a) & FIT_SQRT(b)) {
      return Fixnum::from(a * b);
    }

    return Bignum::from(state, a)->mul(state, other);
  }

  Integer* Fixnum::mul(STATE, Bignum* other) {
    return other->mul(state, this);
  }

  Float* Fixnum::mul(STATE, Float* other) {
    return other->mul(state, this);
  }

  Integer* Fixnum::div(STATE, Fixnum* other) {
    if(other->to_native() == 0) {
      Exception::zero_division_error(state, "divided by 0");
    }
    native_int numerator = to_native();
    native_int denominator = other->to_native();
    native_int quotient;

    if(denominator < 0) {
      if(numerator < 0) {
        quotient = -numerator / -denominator;
      } else {
        quotient = - (numerator / -denominator);
      }
    } else {
      if(numerator < 0) {
        quotient = - (-numerator / denominator);
      } else {
        quotient = numerator / denominator;
      }
    }

    native_int mod = numerator - (quotient * denominator);
    if((mod < 0 && denominator > 0) || (mod > 0 && denominator < 0)) {
      quotient--;
    }

    return Fixnum::from(quotient);
  }

  Integer* Fixnum::div(STATE, Bignum* other) {
    return Bignum::from(state, to_native())->div(state, other);
  }

  Integer* Fixnum::mod(STATE, Fixnum* other) {
    native_int numerator = to_native();
    native_int denominator = other->to_native();
    native_int quotient = div(state, other)->to_native();
    native_int modulo = numerator - denominator * quotient;

    if((modulo < 0 && denominator > 0) || (modulo > 0 && denominator < 0)) {
      return Fixnum::from(modulo + denominator);
    } else {
      return Fixnum::from(modulo);
    }
  }

  Integer* Fixnum::mod(STATE, Bignum* other) {
    return Bignum::from(state, to_native())->mod(state, other);
  }

  Float* Fixnum::mod(STATE, Float* other) {
    return Float::create(state, to_native())->mod(state, other);
  }

  Array* Fixnum::divmod(STATE, Fixnum* other) {
    if(other->to_native() == 0) {
      Exception::zero_division_error(state, "divided by 0");
    }
    native_int numerator = to_native();
    native_int denominator = other->to_native();
    native_int fraction = div(state, other)->to_native();
    Array* ary = Array::create(state, 2);
    ary->set(state, 0, Fixnum::from(fraction));
    ary->set(state, 1, Fixnum::from(numerator - denominator * fraction));
    return ary;
  }

  Array* Fixnum::divmod(STATE, Bignum* other) {
    return Bignum::from(state, to_native())->divmod(state, other);
  }

  Array* Fixnum::divmod(STATE, Float* other) {
    return Float::create(state, to_native())->divmod(state, other);
  }

  Integer* Fixnum::neg(STATE) {
    return Fixnum::from(-to_native());
  }

  Object* Fixnum::pow(STATE, Fixnum* exponent) {
    native_int i = to_native();
    native_int j = exponent->to_native();

    if(j == 0) return Fixnum::from(1);
    if(j == 1) return this;

    if(i == 0) {
      if(j > 0) return Fixnum::from(0);
      return Float::create(state, INFINITY);
    }

    if(i == 1) return Fixnum::from(1);

    return Bignum::from(state, to_native())->pow(state, exponent);
  }

  Object* Fixnum::pow(STATE, Bignum* exponent) {
    native_int i = to_native();
    if(i == 0 || i == 1) return this;
    return Bignum::from(state, to_native())->pow(state, exponent);
  }

  Float* Fixnum::pow(STATE, Float* exponent) {
    return this->to_f(state)->fpow(state, exponent);
  }

  Object* Fixnum::equal(STATE, Fixnum* other) {
    return to_native() == other->to_native() ? Qtrue : Qfalse;
  }

  Object* Fixnum::equal(STATE, Bignum* other) {
    return other->equal(state, this);
  }

  Object* Fixnum::equal(STATE, Float* other) {
    return (double)to_native() == other->val ? Qtrue : Qfalse;
  }

  Object* Fixnum::compare(STATE, Fixnum* other) {
    native_int left  = to_native();
    native_int right = other->to_native();
    if(left == right) {
      return Fixnum::from(0);
    } else if(left < right) {
      return Fixnum::from(-1);
    } else {
      return Fixnum::from(1);
    }
  }

  Object* Fixnum::compare(STATE, Bignum* other) {
    native_int res = as<Fixnum>(other->compare(state, this))->to_native();
    if(res == 0) {
      return Fixnum::from(0);
    } else if(res < 0) {
      return Fixnum::from(1);
    } else {
      return Fixnum::from(-1);
    }
  }

  Object* Fixnum::compare(STATE, Float* other) {
    double left  = (double)to_native();
    double right = other->val;
    if(left == right) {
      return Fixnum::from(0);
    } else if(left < right) {
      return Fixnum::from(-1);
    } else {
      return Fixnum::from(1);
    }
  }

  Object* Fixnum::gt(STATE, Bignum* other) {
    return other->lt(state, this);
  }

  Object* Fixnum::gt(STATE, Float* other) {
    return (double) to_native() > other->val ? Qtrue : Qfalse;
  }

  Object* Fixnum::ge(STATE, Fixnum* other) {
    return to_native() >= other->to_native() ? Qtrue : Qfalse;
  }

  Object* Fixnum::ge(STATE, Bignum* other) {
    return other->le(state, this);
  }

  Object* Fixnum::ge(STATE, Float* other) {
    return (double) to_native() >= other->val ? Qtrue : Qfalse;
  }

  Object* Fixnum::lt(STATE, Bignum* other) {
    return other->gt(state, this);
  }

  Object* Fixnum::lt(STATE, Float* other) {
    return (double) to_native() < other->val ? Qtrue : Qfalse;
  }

  Object* Fixnum::le(STATE, Fixnum* other) {
    return to_native() <= other->to_native() ? Qtrue : Qfalse;
  }

  Object* Fixnum::le(STATE, Bignum* other) {
    return other->ge(state, this);
  }

  Object* Fixnum::le(STATE, Float* other) {
    return (double) to_native() <= other->val ? Qtrue : Qfalse;
  }

  Integer* Fixnum::left_shift(STATE, Fixnum* bits) {
    native_int shift = bits->to_native();
    if(shift < 0) {
      return right_shift(state, Fixnum::from(-shift));
    }

    native_int self = to_native();

    if(shift >= (native_int)FIXNUM_WIDTH
        || self >> ((native_int)FIXNUM_WIDTH - shift) > 0) {
      return Bignum::from(state, self)->left_shift(state, bits);
    }

    return Fixnum::from(self << shift);
  }

  Integer* Fixnum::right_shift(STATE, Fixnum* bits) {
    native_int shift = bits->to_native();
    if(shift < 0) {
      return left_shift(state, Fixnum::from(-shift));
    }

    // boundary case. Don't overflow the bits back to their original
    // value like C does, just say it's 0.
    if(shift >= (native_int)((sizeof(native_int)*CHAR_BIT)-1)) {
      return Fixnum::from(0);
    }

    return Fixnum::from(to_native() >> shift);
  }

  Integer* Fixnum::size(STATE) {
    return Fixnum::from(sizeof(native_int));
  }

  Integer* Fixnum::bit_and(STATE, Fixnum* other) {
    return Fixnum::from(to_native() & other->to_native());
  }

  Integer* Fixnum::bit_and(STATE, Bignum* other) {
    return other->bit_and(state, this);
  }

  Integer* Fixnum::bit_and(STATE, Float* other) {
    return Fixnum::from(to_native() & (native_int)other->val);
  }

  Integer* Fixnum::bit_or(STATE, Fixnum* other) {
    return Fixnum::from(to_native() | other->to_native());
  }

  Integer* Fixnum::bit_or(STATE, Bignum* other) {
    return other->bit_or(state, this);
  }

  Integer* Fixnum::bit_or(STATE, Float* other) {
    return Fixnum::from(to_native() | (native_int)other->val);
  }

  Integer* Fixnum::bit_xor(STATE, Fixnum* other) {
    return Fixnum::from(to_native() ^ other->to_native());
  }

  Integer* Fixnum::bit_xor(STATE, Bignum* other) {
    return other->bit_xor(state, this);
  }

  Integer* Fixnum::bit_xor(STATE, Float* other) {
    return Fixnum::from(to_native() ^ (native_int)other->val);
  }

  Integer* Fixnum::invert(STATE) {
    return Fixnum::from(~to_native());
  }

  Float* Fixnum::to_f(STATE) {
    return Float::create(state, (double)to_native());
  }

  String* Fixnum::to_s(STATE) {
    return to_s(state, Fixnum::from(10));
  }

  String* Fixnum::to_s(STATE, Fixnum* base) {
    // algorithm adapted from shotgun
    static const char digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
    char buf[100];
    char *b = buf + sizeof(buf);
    native_int j, k, m;

    j = base->to_native();
    k = to_native();

    if(j < 2 || j > 36) {
      Exception::argument_error(state, "base must be between 2 and 36");
    }

    /* Algorithm taken from 1.8.4 rb_fix2str */
    if(k == 0) return String::create(state, "0");

    m = 0;
    if(k < 0) {
      k = -k;
      m = 1;
    }
    *--b = 0;
    do {
      *--b = digitmap[(int)(k % j)];
    } while(k /= j);

    if(m) {
      *--b = '-';
    }

    return String::create(state, b);
  }

  Array* Fixnum::coerce(STATE, Bignum* other) {
    Array* ary = Array::create(state, 2);

    if(Fixnum* fix = try_as<Fixnum>(Bignum::normalize(state, other))) {
      ary->set(state, 0, fix);
      ary->set(state, 1, this);
    } else {
      ary->set(state, 0, other);
      ary->set(state, 1, Bignum::create(state, this));
    }

    return ary;
  }

  Array* Fixnum::coerce(STATE, Fixnum* other) {
    Array* ary = Array::create(state, 2);

    ary->set(state, 0, other);
    ary->set(state, 1, this);

    return ary;
  }

  void Fixnum::Info::show(STATE, Object* self, int level) {
    Fixnum* f = as<Fixnum>(self);
    std::cout << f->to_native() << std::endl;
  }

  void Fixnum::Info::show_simple(STATE, Object* self, int level) {
    show(state, self, level);
  }

  void Fixnum::Info::mark(Object* t, ObjectMark& mark) { }
}
<commit_msg>Fix left shifting for fixnums<commit_after>
#include "prelude.hpp"
#include "builtin/exception.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/float.hpp"
#include "builtin/array.hpp"
#include "builtin/string.hpp"

#include "primitives.hpp"
#include "vm/object_utils.hpp"

#include <iostream>

namespace rubinius {

  void Fixnum::init(STATE) {
    GO(fixnum_class).set(state->new_class("Fixnum", G(integer)));
    G(fixnum_class)->instance_type(state, Fixnum::from(FixnumType));

    G(fixnum_class)->set_const(state, "MIN", Fixnum::from(FIXNUM_MIN));
    G(fixnum_class)->set_const(state, "MAX", Fixnum::from(FIXNUM_MAX));
  }

  int Fixnum::to_int() const {
    return (int)STRIP_FIXNUM_TAG(this);
  }

  unsigned int Fixnum::to_uint() const {
    return (unsigned int)STRIP_FIXNUM_TAG(this);
  }

  long Fixnum::to_long() const {
    return (long)STRIP_FIXNUM_TAG(this);
  }

  unsigned long Fixnum::to_ulong() const {
    return (unsigned long)STRIP_FIXNUM_TAG(this);
  }

  long long Fixnum::to_long_long() const {
    return (long long)STRIP_FIXNUM_TAG(this);
  }

  unsigned long long Fixnum::to_ulong_long() const {
    return (unsigned long long)STRIP_FIXNUM_TAG(this);
  }

  Integer* Fixnum::add(STATE, Bignum* other) {
    return other->add(state, this);
  }

  Float* Fixnum::add(STATE, Float* other) {
    return other->add(state, this);
  }

  Integer* Fixnum::sub(STATE, Bignum* other) {
    return as<Bignum>(other->neg(state))->add(state, this);
  }

  Float* Fixnum::sub(STATE, Float* other) {
    return Float::coerce(state, this)->sub(state, other);
  }

#define SQRT_LONG_MAX ((native_int)1<<((sizeof(native_int)*CHAR_BIT-1)/2))
/*tests if N*N would overflow*/
#define FIT_SQRT(n) (((n)<SQRT_LONG_MAX)&&((n)>-SQRT_LONG_MAX))

  Integer* Fixnum::mul(STATE, Fixnum* other) {
    native_int a  = to_native();
    native_int b  = other->to_native();

    if(a == 0 || b == 0) return Fixnum::from(0);

    // Adapted from the logic in 1.9
    if(FIT_SQRT(a) & FIT_SQRT(b)) {
      return Fixnum::from(a * b);
    }

    return Bignum::from(state, a)->mul(state, other);
  }

  Integer* Fixnum::mul(STATE, Bignum* other) {
    return other->mul(state, this);
  }

  Float* Fixnum::mul(STATE, Float* other) {
    return other->mul(state, this);
  }

  Integer* Fixnum::div(STATE, Fixnum* other) {
    if(other->to_native() == 0) {
      Exception::zero_division_error(state, "divided by 0");
    }
    native_int numerator = to_native();
    native_int denominator = other->to_native();
    native_int quotient;

    if(denominator < 0) {
      if(numerator < 0) {
        quotient = -numerator / -denominator;
      } else {
        quotient = - (numerator / -denominator);
      }
    } else {
      if(numerator < 0) {
        quotient = - (-numerator / denominator);
      } else {
        quotient = numerator / denominator;
      }
    }

    native_int mod = numerator - (quotient * denominator);
    if((mod < 0 && denominator > 0) || (mod > 0 && denominator < 0)) {
      quotient--;
    }

    return Fixnum::from(quotient);
  }

  Integer* Fixnum::div(STATE, Bignum* other) {
    return Bignum::from(state, to_native())->div(state, other);
  }

  Integer* Fixnum::mod(STATE, Fixnum* other) {
    native_int numerator = to_native();
    native_int denominator = other->to_native();
    native_int quotient = div(state, other)->to_native();
    native_int modulo = numerator - denominator * quotient;

    if((modulo < 0 && denominator > 0) || (modulo > 0 && denominator < 0)) {
      return Fixnum::from(modulo + denominator);
    } else {
      return Fixnum::from(modulo);
    }
  }

  Integer* Fixnum::mod(STATE, Bignum* other) {
    return Bignum::from(state, to_native())->mod(state, other);
  }

  Float* Fixnum::mod(STATE, Float* other) {
    return Float::create(state, to_native())->mod(state, other);
  }

  Array* Fixnum::divmod(STATE, Fixnum* other) {
    if(other->to_native() == 0) {
      Exception::zero_division_error(state, "divided by 0");
    }
    native_int numerator = to_native();
    native_int denominator = other->to_native();
    native_int fraction = div(state, other)->to_native();
    Array* ary = Array::create(state, 2);
    ary->set(state, 0, Fixnum::from(fraction));
    ary->set(state, 1, Fixnum::from(numerator - denominator * fraction));
    return ary;
  }

  Array* Fixnum::divmod(STATE, Bignum* other) {
    return Bignum::from(state, to_native())->divmod(state, other);
  }

  Array* Fixnum::divmod(STATE, Float* other) {
    return Float::create(state, to_native())->divmod(state, other);
  }

  Integer* Fixnum::neg(STATE) {
    return Fixnum::from(-to_native());
  }

  Object* Fixnum::pow(STATE, Fixnum* exponent) {
    native_int i = to_native();
    native_int j = exponent->to_native();

    if(j == 0) return Fixnum::from(1);
    if(j == 1) return this;

    if(i == 0) {
      if(j > 0) return Fixnum::from(0);
      return Float::create(state, INFINITY);
    }

    if(i == 1) return Fixnum::from(1);

    return Bignum::from(state, to_native())->pow(state, exponent);
  }

  Object* Fixnum::pow(STATE, Bignum* exponent) {
    native_int i = to_native();
    if(i == 0 || i == 1) return this;
    return Bignum::from(state, to_native())->pow(state, exponent);
  }

  Float* Fixnum::pow(STATE, Float* exponent) {
    return this->to_f(state)->fpow(state, exponent);
  }

  Object* Fixnum::equal(STATE, Fixnum* other) {
    return to_native() == other->to_native() ? Qtrue : Qfalse;
  }

  Object* Fixnum::equal(STATE, Bignum* other) {
    return other->equal(state, this);
  }

  Object* Fixnum::equal(STATE, Float* other) {
    return (double)to_native() == other->val ? Qtrue : Qfalse;
  }

  Object* Fixnum::compare(STATE, Fixnum* other) {
    native_int left  = to_native();
    native_int right = other->to_native();
    if(left == right) {
      return Fixnum::from(0);
    } else if(left < right) {
      return Fixnum::from(-1);
    } else {
      return Fixnum::from(1);
    }
  }

  Object* Fixnum::compare(STATE, Bignum* other) {
    native_int res = as<Fixnum>(other->compare(state, this))->to_native();
    if(res == 0) {
      return Fixnum::from(0);
    } else if(res < 0) {
      return Fixnum::from(1);
    } else {
      return Fixnum::from(-1);
    }
  }

  Object* Fixnum::compare(STATE, Float* other) {
    double left  = (double)to_native();
    double right = other->val;
    if(left == right) {
      return Fixnum::from(0);
    } else if(left < right) {
      return Fixnum::from(-1);
    } else {
      return Fixnum::from(1);
    }
  }

  Object* Fixnum::gt(STATE, Bignum* other) {
    return other->lt(state, this);
  }

  Object* Fixnum::gt(STATE, Float* other) {
    return (double) to_native() > other->val ? Qtrue : Qfalse;
  }

  Object* Fixnum::ge(STATE, Fixnum* other) {
    return to_native() >= other->to_native() ? Qtrue : Qfalse;
  }

  Object* Fixnum::ge(STATE, Bignum* other) {
    return other->le(state, this);
  }

  Object* Fixnum::ge(STATE, Float* other) {
    return (double) to_native() >= other->val ? Qtrue : Qfalse;
  }

  Object* Fixnum::lt(STATE, Bignum* other) {
    return other->gt(state, this);
  }

  Object* Fixnum::lt(STATE, Float* other) {
    return (double) to_native() < other->val ? Qtrue : Qfalse;
  }

  Object* Fixnum::le(STATE, Fixnum* other) {
    return to_native() <= other->to_native() ? Qtrue : Qfalse;
  }

  Object* Fixnum::le(STATE, Bignum* other) {
    return other->ge(state, this);
  }

  Object* Fixnum::le(STATE, Float* other) {
    return (double) to_native() <= other->val ? Qtrue : Qfalse;
  }

  Integer* Fixnum::left_shift(STATE, Fixnum* bits) {
    native_int shift = bits->to_native();
    if(shift < 0) {
      return right_shift(state, Fixnum::from(-shift));
    }

    native_int self = to_native();
    native_int check = self < 0 ? -self : self;

    if(shift >= (native_int)FIXNUM_WIDTH
        || check >> ((native_int)FIXNUM_WIDTH - shift) > 0) {
      return Bignum::from(state, self)->left_shift(state, bits);
    }

    return Fixnum::from(self << shift);
  }

  Integer* Fixnum::right_shift(STATE, Fixnum* bits) {
    native_int shift = bits->to_native();
    if(shift < 0) {
      return left_shift(state, Fixnum::from(-shift));
    }

    // boundary case. Don't overflow the bits back to their original
    // value like C does, just say it's 0.
    if(shift >= (native_int)((sizeof(native_int)*CHAR_BIT)-1)) {
      return Fixnum::from(0);
    }

    return Fixnum::from(to_native() >> shift);
  }

  Integer* Fixnum::size(STATE) {
    return Fixnum::from(sizeof(native_int));
  }

  Integer* Fixnum::bit_and(STATE, Fixnum* other) {
    return Fixnum::from(to_native() & other->to_native());
  }

  Integer* Fixnum::bit_and(STATE, Bignum* other) {
    return other->bit_and(state, this);
  }

  Integer* Fixnum::bit_and(STATE, Float* other) {
    return Fixnum::from(to_native() & (native_int)other->val);
  }

  Integer* Fixnum::bit_or(STATE, Fixnum* other) {
    return Fixnum::from(to_native() | other->to_native());
  }

  Integer* Fixnum::bit_or(STATE, Bignum* other) {
    return other->bit_or(state, this);
  }

  Integer* Fixnum::bit_or(STATE, Float* other) {
    return Fixnum::from(to_native() | (native_int)other->val);
  }

  Integer* Fixnum::bit_xor(STATE, Fixnum* other) {
    return Fixnum::from(to_native() ^ other->to_native());
  }

  Integer* Fixnum::bit_xor(STATE, Bignum* other) {
    return other->bit_xor(state, this);
  }

  Integer* Fixnum::bit_xor(STATE, Float* other) {
    return Fixnum::from(to_native() ^ (native_int)other->val);
  }

  Integer* Fixnum::invert(STATE) {
    return Fixnum::from(~to_native());
  }

  Float* Fixnum::to_f(STATE) {
    return Float::create(state, (double)to_native());
  }

  String* Fixnum::to_s(STATE) {
    return to_s(state, Fixnum::from(10));
  }

  String* Fixnum::to_s(STATE, Fixnum* base) {
    // algorithm adapted from shotgun
    static const char digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
    char buf[100];
    char *b = buf + sizeof(buf);
    native_int j, k, m;

    j = base->to_native();
    k = to_native();

    if(j < 2 || j > 36) {
      Exception::argument_error(state, "base must be between 2 and 36");
    }

    /* Algorithm taken from 1.8.4 rb_fix2str */
    if(k == 0) return String::create(state, "0");

    m = 0;
    if(k < 0) {
      k = -k;
      m = 1;
    }
    *--b = 0;
    do {
      *--b = digitmap[(int)(k % j)];
    } while(k /= j);

    if(m) {
      *--b = '-';
    }

    return String::create(state, b);
  }

  Array* Fixnum::coerce(STATE, Bignum* other) {
    Array* ary = Array::create(state, 2);

    if(Fixnum* fix = try_as<Fixnum>(Bignum::normalize(state, other))) {
      ary->set(state, 0, fix);
      ary->set(state, 1, this);
    } else {
      ary->set(state, 0, other);
      ary->set(state, 1, Bignum::create(state, this));
    }

    return ary;
  }

  Array* Fixnum::coerce(STATE, Fixnum* other) {
    Array* ary = Array::create(state, 2);

    ary->set(state, 0, other);
    ary->set(state, 1, this);

    return ary;
  }

  void Fixnum::Info::show(STATE, Object* self, int level) {
    Fixnum* f = as<Fixnum>(self);
    std::cout << f->to_native() << std::endl;
  }

  void Fixnum::Info::show_simple(STATE, Object* self, int level) {
    show(state, self, level);
  }

  void Fixnum::Info::mark(Object* t, ObjectMark& mark) { }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Marios Kogias <marioskogias@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 *   1. Redistributions of source code must retain the above
 *      copyright notice, this list of conditions and the following
 *      disclaimer.
 *   2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``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.
 */
#ifndef ZTRACER_H

#define ZTRACER_H

#include <sstream>

extern "C" {
#include <zipkin_c.h>
}

namespace ZTracer {
	using std::string;

	static inline int ztrace_init() { return blkin_init(); }

	class Endpoint : private blkin_endpoint {
		private:
			string _ip; // storage for blkin_endpoint.ip, see copy_ip()
			string _name; // storage for blkin_endpoint.name, see copy_name()

			friend class Trace;
		public:
			Endpoint(const char *ip, int port, const char *name)
			{
				blkin_init_endpoint(this, ip, port, name);
			}

      // copy constructor and operator need to account for ip/name storage
      Endpoint(const Endpoint &rhs) : _ip(rhs._ip), _name(rhs._name)
      {
        blkin_init_endpoint(this, _ip.size() ? _ip.c_str() : rhs.ip,
                            rhs.port, _name.size() ? _name.c_str() : rhs.name);
      }
      const Endpoint& operator=(const Endpoint &rhs)
      {
        _ip.assign(rhs._ip);
        _name.assign(rhs._name);
        blkin_init_endpoint(this, _ip.size() ? _ip.c_str() : rhs.ip,
                            rhs.port, _name.size() ? _name.c_str() : rhs.name);
        return *this;
      }

      // Endpoint assumes that ip and name will be string literals, and
      // avoids making a copy and freeing on destruction.  if you need to
      // initialize Endpoint with a temporary string, copy_ip/copy_name()
      // will store it in a std::string and assign from that
      void copy_ip(const string &newip)
      {
        _ip.assign(newip);
        ip = _ip.c_str();
      }
      void copy_name(const string &newname)
      {
        _name.assign(newname);
        name = _name.c_str();
      }

      void set_port(int p) { port = p; }
	};

	class Trace : private blkin_trace {
    private:
      string _name; // storage for blkin_trace.name, see copy_name()

		public:
      // default constructor zero-initializes blkin_trace
      // valid() will return false on a default-constructed Trace until init()
      Trace()
      {
        // zero-initialize so valid() returns false
        name = NULL;
        info.trace_id = 0;
        info.span_id = 0;
        info.parent_span_id = 0;
        endpoint = NULL;
      }

      // construct a Trace with an optional parent
			Trace(const char *name, const Endpoint *ep, const Trace *parent = NULL)
      {
        if (parent && parent->valid()) {
          blkin_init_child(this, parent, ep ? : parent->endpoint, name);
        } else {
				  blkin_init_new_trace(this, name, ep);
        }
      }

      // construct a Trace from blkin_trace_info
			Trace(const char *name, const Endpoint *ep,
            const blkin_trace_info *i, bool child=false)
			{
				if (child)
					blkin_init_child_info(this, i, ep, name);
				else {
					blkin_init_new_trace(this, name, ep);
					set_info(i);
				}
			}

      // copy constructor and operator need to account for name storage
      Trace(const Trace &rhs) : _name(rhs._name)
      {
        name = _name.size() ? _name.c_str() : rhs.name;
        info = rhs.info;
        endpoint = rhs.endpoint;
      }
      const Trace& operator=(const Trace &rhs)
      {
        _name.assign(rhs._name);
        name = _name.size() ? _name.c_str() : rhs.name;
        info = rhs.info;
        endpoint = rhs.endpoint;
        return *this;
      }

      // return true if the Trace has been initialized
      bool valid() const { return info.trace_id != 0; }
      operator bool() const { return valid(); }

      // (re)initialize a Trace with an optional parent
			int init(const char *name, const Endpoint *ep, const Trace *parent = NULL)
      {
        if (parent && parent->valid())
          return blkin_init_child(this, parent, ep ? : parent->endpoint, name);

        return blkin_init_new_trace(this, name, ep);
      }

      // (re)initialize a Trace from blkin_trace_info
			int init(const char *name, const Endpoint *ep,
               const blkin_trace_info *i, bool child=false)
      {
				if (child)
					return blkin_init_child_info(this, i, ep, _name.c_str());

        int r = blkin_init_new_trace(this, _name.c_str(), ep);
        if (r == 0)
          set_info(i);
        return r;
      }

      // Trace assumes that name will be a string literal, and avoids
      // making a copy and freeing on destruction.  if you need to
      // initialize Trace with a temporary string, copy_name() will store
      // it in a std::string and assign from that
      void copy_name(const string &newname)
      {
        _name.assign(newname);
        name = _name.c_str();
      }

      const blkin_trace_info* get_info() const { return &info; }
      void set_info(const blkin_trace_info *i) { info = *i; }

      // record key-value annotations
			void keyval(const char *key, const char *val)
			{
        if (valid())
          BLKIN_KEYVAL_STRING(this, endpoint, key, val);
			}
			void keyval(const char *key, int64_t val)
			{
        if (valid())
          BLKIN_KEYVAL_INTEGER(this, endpoint, key, val);
			}
			void keyval(const char *key, const char *val, const Endpoint *ep)
			{
        if (valid())
          BLKIN_KEYVAL_STRING(this, ep, key, val);
			}
			void keyval(const char *key, int64_t val, const Endpoint *ep)
			{
        if (valid())
          BLKIN_KEYVAL_INTEGER(this, ep, key, val);
			}

      // record timestamp annotations
			void event(const char *event)
			{
        if (valid())
          BLKIN_TIMESTAMP(this, endpoint, event);
			}
			void event(const char *event, const Endpoint *ep)
			{
        if (valid())
          BLKIN_TIMESTAMP(this, ep, event);
			}
	};

}
#endif /* end of include guard: ZTRACER_H */
<commit_msg>ztrace: Endpoint constructor with default address<commit_after>/*
 * Copyright 2014 Marios Kogias <marioskogias@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 *   1. Redistributions of source code must retain the above
 *      copyright notice, this list of conditions and the following
 *      disclaimer.
 *   2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS ``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.
 */
#ifndef ZTRACER_H

#define ZTRACER_H

#include <sstream>

extern "C" {
#include <zipkin_c.h>
}

namespace ZTracer {
	using std::string;

	static inline int ztrace_init() { return blkin_init(); }

	class Endpoint : private blkin_endpoint {
		private:
			string _ip; // storage for blkin_endpoint.ip, see copy_ip()
			string _name; // storage for blkin_endpoint.name, see copy_name()

			friend class Trace;
		public:
			Endpoint(const char *name)
      {
				blkin_init_endpoint(this, "0.0.0.0", 0, name);
      }
			Endpoint(const char *ip, int port, const char *name)
			{
				blkin_init_endpoint(this, ip, port, name);
			}

      // copy constructor and operator need to account for ip/name storage
      Endpoint(const Endpoint &rhs) : _ip(rhs._ip), _name(rhs._name)
      {
        blkin_init_endpoint(this, _ip.size() ? _ip.c_str() : rhs.ip,
                            rhs.port, _name.size() ? _name.c_str() : rhs.name);
      }
      const Endpoint& operator=(const Endpoint &rhs)
      {
        _ip.assign(rhs._ip);
        _name.assign(rhs._name);
        blkin_init_endpoint(this, _ip.size() ? _ip.c_str() : rhs.ip,
                            rhs.port, _name.size() ? _name.c_str() : rhs.name);
        return *this;
      }

      // Endpoint assumes that ip and name will be string literals, and
      // avoids making a copy and freeing on destruction.  if you need to
      // initialize Endpoint with a temporary string, copy_ip/copy_name()
      // will store it in a std::string and assign from that
      void copy_ip(const string &newip)
      {
        _ip.assign(newip);
        ip = _ip.c_str();
      }
      void copy_name(const string &newname)
      {
        _name.assign(newname);
        name = _name.c_str();
      }

      void set_port(int p) { port = p; }
	};

	class Trace : private blkin_trace {
    private:
      string _name; // storage for blkin_trace.name, see copy_name()

		public:
      // default constructor zero-initializes blkin_trace
      // valid() will return false on a default-constructed Trace until init()
      Trace()
      {
        // zero-initialize so valid() returns false
        name = NULL;
        info.trace_id = 0;
        info.span_id = 0;
        info.parent_span_id = 0;
        endpoint = NULL;
      }

      // construct a Trace with an optional parent
			Trace(const char *name, const Endpoint *ep, const Trace *parent = NULL)
      {
        if (parent && parent->valid()) {
          blkin_init_child(this, parent, ep ? : parent->endpoint, name);
        } else {
				  blkin_init_new_trace(this, name, ep);
        }
      }

      // construct a Trace from blkin_trace_info
			Trace(const char *name, const Endpoint *ep,
            const blkin_trace_info *i, bool child=false)
			{
				if (child)
					blkin_init_child_info(this, i, ep, name);
				else {
					blkin_init_new_trace(this, name, ep);
					set_info(i);
				}
			}

      // copy constructor and operator need to account for name storage
      Trace(const Trace &rhs) : _name(rhs._name)
      {
        name = _name.size() ? _name.c_str() : rhs.name;
        info = rhs.info;
        endpoint = rhs.endpoint;
      }
      const Trace& operator=(const Trace &rhs)
      {
        _name.assign(rhs._name);
        name = _name.size() ? _name.c_str() : rhs.name;
        info = rhs.info;
        endpoint = rhs.endpoint;
        return *this;
      }

      // return true if the Trace has been initialized
      bool valid() const { return info.trace_id != 0; }
      operator bool() const { return valid(); }

      // (re)initialize a Trace with an optional parent
			int init(const char *name, const Endpoint *ep, const Trace *parent = NULL)
      {
        if (parent && parent->valid())
          return blkin_init_child(this, parent, ep ? : parent->endpoint, name);

        return blkin_init_new_trace(this, name, ep);
      }

      // (re)initialize a Trace from blkin_trace_info
			int init(const char *name, const Endpoint *ep,
               const blkin_trace_info *i, bool child=false)
      {
				if (child)
					return blkin_init_child_info(this, i, ep, _name.c_str());

        int r = blkin_init_new_trace(this, _name.c_str(), ep);
        if (r == 0)
          set_info(i);
        return r;
      }

      // Trace assumes that name will be a string literal, and avoids
      // making a copy and freeing on destruction.  if you need to
      // initialize Trace with a temporary string, copy_name() will store
      // it in a std::string and assign from that
      void copy_name(const string &newname)
      {
        _name.assign(newname);
        name = _name.c_str();
      }

      const blkin_trace_info* get_info() const { return &info; }
      void set_info(const blkin_trace_info *i) { info = *i; }

      // record key-value annotations
			void keyval(const char *key, const char *val)
			{
        if (valid())
          BLKIN_KEYVAL_STRING(this, endpoint, key, val);
			}
			void keyval(const char *key, int64_t val)
			{
        if (valid())
          BLKIN_KEYVAL_INTEGER(this, endpoint, key, val);
			}
			void keyval(const char *key, const char *val, const Endpoint *ep)
			{
        if (valid())
          BLKIN_KEYVAL_STRING(this, ep, key, val);
			}
			void keyval(const char *key, int64_t val, const Endpoint *ep)
			{
        if (valid())
          BLKIN_KEYVAL_INTEGER(this, ep, key, val);
			}

      // record timestamp annotations
			void event(const char *event)
			{
        if (valid())
          BLKIN_TIMESTAMP(this, endpoint, event);
			}
			void event(const char *event, const Endpoint *ep)
			{
        if (valid())
          BLKIN_TIMESTAMP(this, ep, event);
			}
	};

}
#endif /* end of include guard: ZTRACER_H */
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

#include <string>

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <shellapi.h>

#include <osquery/core.h>
#include <osquery/dispatcher.h>
#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/system.h>

#include "osquery/main/main.h"

DECLARE_string(flagfile);

namespace osquery {

static const std::string kDefaultFlagsFile{OSQUERY_HOME "\\osquery.flags"};
static const std::string kServiceName{"osqueryd"};
static const std::string kServiceDisplayName{"osquery daemon service"};

static SERVICE_STATUS_HANDLE kStatusHandle = nullptr;
static SERVICE_STATUS kServiceStatus = {0};

/*
 * This event is set when a SERVICE_CONTROL_STOP or SERVICE_CONTROL_SHUTDOWN
 * message is received in the ServiceControlHandler
 */
static const std::string kStopEventName{"osqueryd-service-stop-event"};

/// Logging for when we need to debug this service
#define SLOG(s) ::osquery::DebugPrintf(s)

void DebugPrintf(const std::string& s) {
  auto dbgString = "[osqueryd] " + s;
  if (IsDebuggerPresent()) {
    ::OutputDebugStringA(dbgString.c_str());
  }
  LOG(ERROR) << s;
}

// A helper function to return a HANDLE to the named Stop Event for child
// processes
HANDLE getStopEvent() {
  auto stopEvent = ::OpenEventA(
      SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, osquery::kStopEventName.c_str());

  if (stopEvent == nullptr) {
    return stopEvent;
  }

  auto ret = WaitForSingleObject(stopEvent, 0);

  // The object has already been signaled
  if (ret == WAIT_OBJECT_0) {
    return nullptr;
  }

  // ERROR_FILE_NOT_FOUND indicates the event was never created.
  // Likely the process running as the daemon at the command line.
  if (stopEvent == nullptr && GetLastError() != ERROR_FILE_NOT_FOUND) {
    SLOG("OpenEventA failed for event name " + osquery::kStopEventName +
         " (lasterror=" + std::to_string(GetLastError()) + ")");
  }
  return stopEvent;
}

static void UpdateServiceStatus(DWORD controls,
                                DWORD state,
                                DWORD exit_code,
                                DWORD checkpoint) {
  kServiceStatus.dwControlsAccepted = controls;
  kServiceStatus.dwCurrentState = state;
  kServiceStatus.dwWin32ExitCode = exit_code;
  kServiceStatus.dwCheckPoint = checkpoint;

  if (!::SetServiceStatus(kStatusHandle, &kServiceStatus)) {
    SLOG("SetServiceStatus failed (lasterror=" +
         std::to_string(GetLastError()) + ")");
  }
}

static auto kShutdownCallable = ([]() {
  // To prevent invalid access to the stop event, we return if running as shell
  if (Initializer::isShell()) {
    return;
  }
  // The event only gets initialized in the entry point of the service. Child
  // processes and those run from the commandline will not have a stop event.
  auto stopEvent = osquery::getStopEvent();
  if (stopEvent != nullptr) {
    // Wait forever, until the service handler signals us
    ::WaitForSingleObject(stopEvent, INFINITE);
    // Interup the worker service threads before joining
    Dispatcher::stopServices();
    auto ret = ::CloseHandle(stopEvent);
    if (ret != TRUE) {
      SLOG("kShutdownCallable failed to call CloseHandle with (" +
           std::to_string(GetLastError()) + ")");
    }
  }
});

/*
 * Parses arguments for the Windows service. Arguments to the Windows service
 * can be passed in two ways: via sc.exe (manual start) or via binPath
 * (automated start). Unfortunately, both use different methods of getting the
 * command line arguments. Manual start uses the argc and argv provided by
 * ServiceMain whereas automated start requires manual parsing of
 * GetCommandLine()
 */
class ServiceArgumentParser {
 public:
  ServiceArgumentParser(DWORD argc, const LPSTR* argv) {
    if (argc > 1) {
      for (DWORD i = 0; i < argc; i++) {
        args_.push_back(argv[i]);
      }
      owns_argv_ptrs_ = false;
    } else {
      int wargc = 0;
      LPWSTR* wargv = ::CommandLineToArgvW(::GetCommandLineW(), &wargc);

      if (wargv != nullptr) {
        for (int i = 0; i < wargc; i++) {
          LPSTR arg = toMBString(wargv[i]);

          // On error, bail out and clean up the vector
          if (arg == nullptr) {
            cleanArgs();
            ::LocalFree(wargv);
            break;
          }
          args_.push_back(arg);
        }
        owns_argv_ptrs_ = true;
        ::LocalFree(wargv);
      }
    }
  }

  ~ServiceArgumentParser() {
    cleanArgs();
  }

  DWORD count() const {
    return static_cast<DWORD>(args_.size());
  }
  LPSTR* arguments() {
    return args_.data();
  }

 private:
  LPSTR toMBString(const LPWSTR src) const {
    if (src == nullptr) {
      return nullptr;
    }

    size_t converted = 0;

    // Allocate the same amount for multi-byte
    size_t mbsbuf_size = wcslen(src) * 2;
    LPSTR mbsbuf = static_cast<LPSTR>(new char[mbsbuf_size]);
    if (mbsbuf == nullptr) {
      return nullptr;
    }

    if (wcstombs_s(&converted, mbsbuf, mbsbuf_size, src, mbsbuf_size) != 0) {
      delete[] mbsbuf;
      return nullptr;
    }

    return mbsbuf;
  }

  void cleanArgs() {
    if (owns_argv_ptrs_) {
      for (size_t i = 0; i < args_.size(); i++) {
        if (args_[i] != nullptr) {
          delete[] args_[i];
          args_[i] = nullptr;
        }
      }
    }
    args_.clear();
  }

  bool owns_argv_ptrs_{false};
  std::vector<LPSTR> args_;
};

/// Install osqueryd as a service given the path to the binary
Status installService(const char* const binPath) {
  SC_HANDLE schSCManager = OpenSCManager(
      nullptr, nullptr, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);

  if (schSCManager == nullptr) {
    return Status(1);
  }

  SC_HANDLE schService =
      OpenService(schSCManager, kServiceName.c_str(), SERVICE_ALL_ACCESS);

  if (schService != nullptr) {
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
    return Status(1);
  }

  HANDLE flagsFilePtr = nullptr;
  std::string binPathWithFlagFile = std::string(binPath) + " --flagfile=";
  std::string flagsFile =
      FLAGS_flagfile.empty() ? kDefaultFlagsFile : FLAGS_flagfile;
  binPathWithFlagFile += flagsFile;
  flagsFilePtr = CreateFile(flagsFile.c_str(),
                            GENERIC_READ,
                            FILE_SHARE_READ,
                            nullptr,
                            OPEN_ALWAYS,
                            0,
                            nullptr);
  CloseHandle(flagsFilePtr);

  schService = CreateService(schSCManager,
                             kServiceName.c_str(),
                             kServiceDisplayName.c_str(),
                             SERVICE_ALL_ACCESS,
                             SERVICE_WIN32_OWN_PROCESS,
                             SERVICE_AUTO_START,
                             SERVICE_ERROR_NORMAL,
                             binPathWithFlagFile.c_str(),
                             nullptr,
                             nullptr,
                             nullptr,
                             nullptr, // User Account. nullptr => LOCAL SYSTEM
                             nullptr);

  CloseServiceHandle(schSCManager);
  CloseServiceHandle(schService);
  return Status(schService ? 0 : 1);
}

Status uninstallService() {
  SC_HANDLE schSCManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT);
  if (schSCManager == nullptr) {
    return Status(1);
  }

  SC_HANDLE schService =
      OpenService(schSCManager,
                  kServiceName.c_str(),
                  SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE);

  if (schService == nullptr) {
    CloseServiceHandle(schService);
    return Status(1);
  }

  SERVICE_STATUS_PROCESS ssStatus;
  DWORD dwBytesNeeded;
  if (!QueryServiceStatusEx(schService,
                            SC_STATUS_PROCESS_INFO,
                            reinterpret_cast<LPBYTE>(&ssStatus),
                            sizeof(SERVICE_STATUS_PROCESS),
                            &dwBytesNeeded)) {
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
    return Status(1);
  }

  SERVICE_STATUS ssSvcStatus = {};
  if (ssStatus.dwCurrentState != SERVICE_STOPPED) {
    ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus);
    // Wait 3 seconds to give the service an opportunity to stop.
    Sleep(3000);
    QueryServiceStatus(schService, &ssSvcStatus);
    if (ssSvcStatus.dwCurrentState != SERVICE_STOPPED) {
      CloseServiceHandle(schSCManager);
      CloseServiceHandle(schService);
      return Status(1);
    }
  }

  auto s = DeleteService(schService);
  CloseServiceHandle(schSCManager);
  CloseServiceHandle(schService);
  return Status(s ? 0 : 1);
}

void WINAPI ServiceControlHandler(DWORD control_code) {
  switch (control_code) {
  case SERVICE_CONTROL_STOP:
  case SERVICE_CONTROL_SHUTDOWN:
    if (kServiceStatus.dwCurrentState != SERVICE_RUNNING) {
      break;
    }

    UpdateServiceStatus(0, SERVICE_STOP_PENDING, 0, 3);
    {
      auto stopEvent = osquery::getStopEvent();
      if (stopEvent != nullptr) {
        auto ret = SetEvent(stopEvent);
        if (ret != TRUE) {
          SLOG("SetEvent failed (lasterror=" + std::to_string(GetLastError()) +
               ")");
        }
        CloseHandle(stopEvent);
      }
    }

    break;
  default:
    break;
  }
}

void WINAPI ServiceMain(DWORD argc, LPSTR* argv) {
  kStatusHandle = ::RegisterServiceCtrlHandlerA(kServiceName.c_str(),
                                                ServiceControlHandler);
  if (kStatusHandle != nullptr) {
    ::ZeroMemory(&kServiceStatus, sizeof(kServiceStatus));
    kServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    kServiceStatus.dwServiceSpecificExitCode = 0;
    UpdateServiceStatus(0, SERVICE_START_PENDING, 0, 0);

    auto stopEvent =
        ::CreateEventA(nullptr, TRUE, FALSE, kStopEventName.c_str());
    if (stopEvent != nullptr) {
      UpdateServiceStatus(
          SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, SERVICE_RUNNING, 0, 0);

      ServiceArgumentParser parser(argc, argv);
      if (parser.count() == 0) {
        SLOG("ServiceArgumentParser failed (cmdline=" +
             std::string(GetCommandLineA()) + ")");
      } else {
        osquery::startOsquery(
            parser.count(), parser.arguments(), kShutdownCallable);
      }

      ::CloseHandle(stopEvent);
    } else {
      SLOG("CreateEventA failed (lasterror=" + std::to_string(GetLastError()) +
           ")");
    }
  } else {
    SLOG("RegisterServiceCtrlHandlerA failed (lasterror=" +
         std::to_string(GetLastError()) + ")");
  }

  UpdateServiceStatus(0, SERVICE_STOPPED, 0, 4);
}
} // namespace osquery

int main(int argc, char* argv[]) {
  SERVICE_TABLE_ENTRYA serviceTable[] = {
      {const_cast<CHAR*>(osquery::kServiceName.c_str()),
       static_cast<LPSERVICE_MAIN_FUNCTION>(osquery::ServiceMain)},
      {nullptr, nullptr}};

  if (!::StartServiceCtrlDispatcherA(serviceTable)) {
    DWORD last_error = ::GetLastError();
    if (last_error == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
      // Failing to start the service control dispatcher with this error
      // usually indicates that the process was not started as a service.
      // Therefore, it must've been started from the commandline or as a child
      // process
      osquery::startOsquery(argc, argv, osquery::kShutdownCallable);
    } else {
      // An actual error has occurred at this point
      SLOG("StartServiceCtrlDispatcherA error (lasterror=" +
           std::to_string(last_error) + ")");
    }
  }
  return 0;
}
<commit_msg>daemon: set service status to SERVICE_STOPPED on exit (#3973)<commit_after>/*
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

#include <string>

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <shellapi.h>

#include <osquery/core.h>
#include <osquery/dispatcher.h>
#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/system.h>

#include "osquery/main/main.h"

DECLARE_string(flagfile);

namespace osquery {

static const std::string kDefaultFlagsFile{OSQUERY_HOME "\\osquery.flags"};
static const std::string kServiceName{"osqueryd"};
static const std::string kServiceDisplayName{"osquery daemon service"};

static SERVICE_STATUS_HANDLE kStatusHandle = nullptr;
static SERVICE_STATUS kServiceStatus = {0};

/*
 * This event is set when a SERVICE_CONTROL_STOP or SERVICE_CONTROL_SHUTDOWN
 * message is received in the ServiceControlHandler
 */
static const std::string kStopEventName{"osqueryd-service-stop-event"};

/// Logging for when we need to debug this service
#define SLOG(s) ::osquery::DebugPrintf(s)

void DebugPrintf(const std::string& s) {
  auto dbgString = "[osqueryd] " + s;
  if (IsDebuggerPresent()) {
    ::OutputDebugStringA(dbgString.c_str());
  }
  LOG(ERROR) << s;
}

// A helper function to return a HANDLE to the named Stop Event for child
// processes
HANDLE getStopEvent() {
  auto stopEvent = ::OpenEventA(
      SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, osquery::kStopEventName.c_str());

  if (stopEvent == nullptr) {
    return stopEvent;
  }

  auto ret = WaitForSingleObject(stopEvent, 0);

  // The object has already been signaled
  if (ret == WAIT_OBJECT_0) {
    return nullptr;
  }

  // ERROR_FILE_NOT_FOUND indicates the event was never created.
  // Likely the process running as the daemon at the command line.
  if (stopEvent == nullptr && GetLastError() != ERROR_FILE_NOT_FOUND) {
    SLOG("OpenEventA failed for event name " + osquery::kStopEventName +
         " (lasterror=" + std::to_string(GetLastError()) + ")");
  }
  return stopEvent;
}

static void UpdateServiceStatus(DWORD controls,
                                DWORD state,
                                DWORD exit_code,
                                DWORD checkpoint) {
  kServiceStatus.dwControlsAccepted = controls;
  kServiceStatus.dwCurrentState = state;
  kServiceStatus.dwWin32ExitCode = exit_code;
  kServiceStatus.dwCheckPoint = checkpoint;

  if (!::SetServiceStatus(kStatusHandle, &kServiceStatus)) {
    SLOG("SetServiceStatus failed (lasterror=" +
         std::to_string(GetLastError()) + ")");
  }
}

static auto kShutdownCallable = ([]() {
  // To prevent invalid access to the stop event, we return if running as shell
  if (Initializer::isShell()) {
    return;
  }
  // The event only gets initialized in the entry point of the service. Child
  // processes and those run from the commandline will not have a stop event.
  auto stopEvent = osquery::getStopEvent();
  if (stopEvent != nullptr) {
    // Wait forever, until the service handler signals us
    ::WaitForSingleObject(stopEvent, INFINITE);
    // Interup the worker service threads before joining
    Dispatcher::stopServices();
    auto ret = ::CloseHandle(stopEvent);
    if (ret != TRUE) {
      SLOG("kShutdownCallable failed to call CloseHandle with (" +
           std::to_string(GetLastError()) + ")");
    }
  }
});

/*
 * Parses arguments for the Windows service. Arguments to the Windows service
 * can be passed in two ways: via sc.exe (manual start) or via binPath
 * (automated start). Unfortunately, both use different methods of getting the
 * command line arguments. Manual start uses the argc and argv provided by
 * ServiceMain whereas automated start requires manual parsing of
 * GetCommandLine()
 */
class ServiceArgumentParser {
 public:
  ServiceArgumentParser(DWORD argc, const LPSTR* argv) {
    if (argc > 1) {
      for (DWORD i = 0; i < argc; i++) {
        args_.push_back(argv[i]);
      }
      owns_argv_ptrs_ = false;
    } else {
      int wargc = 0;
      LPWSTR* wargv = ::CommandLineToArgvW(::GetCommandLineW(), &wargc);

      if (wargv != nullptr) {
        for (int i = 0; i < wargc; i++) {
          LPSTR arg = toMBString(wargv[i]);

          // On error, bail out and clean up the vector
          if (arg == nullptr) {
            cleanArgs();
            ::LocalFree(wargv);
            break;
          }
          args_.push_back(arg);
        }
        owns_argv_ptrs_ = true;
        ::LocalFree(wargv);
      }
    }
  }

  ~ServiceArgumentParser() {
    cleanArgs();
  }

  DWORD count() const {
    return static_cast<DWORD>(args_.size());
  }
  LPSTR* arguments() {
    return args_.data();
  }

 private:
  LPSTR toMBString(const LPWSTR src) const {
    if (src == nullptr) {
      return nullptr;
    }

    size_t converted = 0;

    // Allocate the same amount for multi-byte
    size_t mbsbuf_size = wcslen(src) * 2;
    LPSTR mbsbuf = static_cast<LPSTR>(new char[mbsbuf_size]);
    if (mbsbuf == nullptr) {
      return nullptr;
    }

    if (wcstombs_s(&converted, mbsbuf, mbsbuf_size, src, mbsbuf_size) != 0) {
      delete[] mbsbuf;
      return nullptr;
    }

    return mbsbuf;
  }

  void cleanArgs() {
    if (owns_argv_ptrs_) {
      for (size_t i = 0; i < args_.size(); i++) {
        if (args_[i] != nullptr) {
          delete[] args_[i];
          args_[i] = nullptr;
        }
      }
    }
    args_.clear();
  }

  bool owns_argv_ptrs_{false};
  std::vector<LPSTR> args_;
};

/// Install osqueryd as a service given the path to the binary
Status installService(const char* const binPath) {
  SC_HANDLE schSCManager = OpenSCManager(
      nullptr, nullptr, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);

  if (schSCManager == nullptr) {
    return Status(1);
  }

  SC_HANDLE schService =
      OpenService(schSCManager, kServiceName.c_str(), SERVICE_ALL_ACCESS);

  if (schService != nullptr) {
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
    return Status(1);
  }

  HANDLE flagsFilePtr = nullptr;
  std::string binPathWithFlagFile = std::string(binPath) + " --flagfile=";
  std::string flagsFile =
      FLAGS_flagfile.empty() ? kDefaultFlagsFile : FLAGS_flagfile;
  binPathWithFlagFile += flagsFile;
  flagsFilePtr = CreateFile(flagsFile.c_str(),
                            GENERIC_READ,
                            FILE_SHARE_READ,
                            nullptr,
                            OPEN_ALWAYS,
                            0,
                            nullptr);
  CloseHandle(flagsFilePtr);

  schService = CreateService(schSCManager,
                             kServiceName.c_str(),
                             kServiceDisplayName.c_str(),
                             SERVICE_ALL_ACCESS,
                             SERVICE_WIN32_OWN_PROCESS,
                             SERVICE_AUTO_START,
                             SERVICE_ERROR_NORMAL,
                             binPathWithFlagFile.c_str(),
                             nullptr,
                             nullptr,
                             nullptr,
                             nullptr, // User Account. nullptr => LOCAL SYSTEM
                             nullptr);

  CloseServiceHandle(schSCManager);
  CloseServiceHandle(schService);
  return Status(schService ? 0 : 1);
}

Status uninstallService() {
  SC_HANDLE schSCManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT);
  if (schSCManager == nullptr) {
    return Status(1);
  }

  SC_HANDLE schService =
      OpenService(schSCManager,
                  kServiceName.c_str(),
                  SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE);

  if (schService == nullptr) {
    CloseServiceHandle(schService);
    return Status(1);
  }

  SERVICE_STATUS_PROCESS ssStatus;
  DWORD dwBytesNeeded;
  if (!QueryServiceStatusEx(schService,
                            SC_STATUS_PROCESS_INFO,
                            reinterpret_cast<LPBYTE>(&ssStatus),
                            sizeof(SERVICE_STATUS_PROCESS),
                            &dwBytesNeeded)) {
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
    return Status(1);
  }

  SERVICE_STATUS ssSvcStatus = {};
  if (ssStatus.dwCurrentState != SERVICE_STOPPED) {
    ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus);
    // Wait 3 seconds to give the service an opportunity to stop.
    Sleep(3000);
    QueryServiceStatus(schService, &ssSvcStatus);
    if (ssSvcStatus.dwCurrentState != SERVICE_STOPPED) {
      CloseServiceHandle(schSCManager);
      CloseServiceHandle(schService);
      return Status(1);
    }
  }

  auto s = DeleteService(schService);
  CloseServiceHandle(schSCManager);
  CloseServiceHandle(schService);
  return Status(s ? 0 : 1);
}

void WINAPI ServiceControlHandler(DWORD control_code) {
  switch (control_code) {
  case SERVICE_CONTROL_STOP:
  case SERVICE_CONTROL_SHUTDOWN:
    if (kServiceStatus.dwCurrentState != SERVICE_RUNNING) {
      break;
    }

    UpdateServiceStatus(0, SERVICE_STOP_PENDING, 0, 3);
    {
      auto stopEvent = osquery::getStopEvent();
      if (stopEvent != nullptr) {
        auto ret = SetEvent(stopEvent);
        if (ret != TRUE) {
          SLOG("SetEvent failed (lasterror=" + std::to_string(GetLastError()) +
               ")");
        }
        CloseHandle(stopEvent);
      }
    }
    UpdateServiceStatus(0, SERVICE_STOPPED, 0, 4);

    break;
  default:
    break;
  }
}

void WINAPI ServiceMain(DWORD argc, LPSTR* argv) {
  kStatusHandle = ::RegisterServiceCtrlHandlerA(kServiceName.c_str(),
                                                ServiceControlHandler);
  if (kStatusHandle != nullptr) {
    ::ZeroMemory(&kServiceStatus, sizeof(kServiceStatus));
    kServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    kServiceStatus.dwServiceSpecificExitCode = 0;
    UpdateServiceStatus(0, SERVICE_START_PENDING, 0, 0);

    auto stopEvent =
        ::CreateEventA(nullptr, TRUE, FALSE, kStopEventName.c_str());
    if (stopEvent != nullptr) {
      UpdateServiceStatus(
          SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, SERVICE_RUNNING, 0, 0);

      ServiceArgumentParser parser(argc, argv);
      if (parser.count() == 0) {
        SLOG("ServiceArgumentParser failed (cmdline=" +
             std::string(GetCommandLineA()) + ")");
      } else {
        osquery::startOsquery(
            parser.count(), parser.arguments(), kShutdownCallable);
      }

      ::CloseHandle(stopEvent);
    } else {
      SLOG("CreateEventA failed (lasterror=" + std::to_string(GetLastError()) +
           ")");
    }
  } else {
    SLOG("RegisterServiceCtrlHandlerA failed (lasterror=" +
         std::to_string(GetLastError()) + ")");
  }

  UpdateServiceStatus(0, SERVICE_STOPPED, 0, 4);
}
} // namespace osquery

int main(int argc, char* argv[]) {
  SERVICE_TABLE_ENTRYA serviceTable[] = {
      {const_cast<CHAR*>(osquery::kServiceName.c_str()),
       static_cast<LPSERVICE_MAIN_FUNCTION>(osquery::ServiceMain)},
      {nullptr, nullptr}};

  if (!::StartServiceCtrlDispatcherA(serviceTable)) {
    DWORD last_error = ::GetLastError();
    if (last_error == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
      // Failing to start the service control dispatcher with this error
      // usually indicates that the process was not started as a service.
      // Therefore, it must've been started from the commandline or as a child
      // process
      osquery::startOsquery(argc, argv, osquery::kShutdownCallable);
    } else {
      // An actual error has occurred at this point
      SLOG("StartServiceCtrlDispatcherA error (lasterror=" +
           std::to_string(last_error) + ")");
    }
  }
  return 0;
}
<|endoftext|>


<commit_before>
#ifndef LOAD_DATA_CONDITION_H
#define LOAD_DATA_CONDITION_H

#include <vector>
#include <string>
#include <algorithm>
using namespace std;

#include <wiz/stacks.h>
#include <wiz/load_data_types.h>
#include <wiz/load_data_utility.h>

namespace wiz {
	namespace load_data {
		class Condition {
		private:
			int braceNum;
			std::vector<string> tokenVec;
			ArrayStack<string> tokenStack;
			string condition;
			int i;
			UserType* position=nullptr; // need set, get ter!!
			UserType* global=nullptr;
			int option;
		public:
			explicit Condition(const string& condition, UserType* position, UserType* global, const int option = 0)
				: braceNum(0), condition(condition), i(0), position(position), option(option), global(global)
			{
				Init(condition);
			}
		private:
			auto Get(const string& var, const string& position, UserType* utPosition, UserType* global) {
				string valTemp = position;
				StringTokenizer tokenizer(position, "/");
				UserType* utTemp;

				if (false == tokenizer.hasMoreTokens()) {
					utTemp = utPosition;
				}
				else {
					if (tokenizer.nextToken() != "root") {
						utTemp = utPosition;
					}
					else {
						valTemp = string(position.c_str() + 5);
						utTemp = global;
					}
				}
				return UserType::Find(utTemp, valTemp);
			}
			string GetValue(const string& op, const string& var, const string& val, UserType* utPosition, UserType* global, const string& option = "0")
			{
				/// ExistItem, ExistUserType
				if (NULL == utPosition) { return "ERROR"; }
				if ("EXISTITEM" == op) { /// option == 1?
					auto x = Get(var, val, utPosition, global);
					if (x.first) {
						//if (x.second.size() > 1) { return "ERROR"; } ///
						for (int i = 0; i < x.second.size(); ++i) {
							if (x.second[i]->GetItem(var).size() > 0)
							{
								return "TRUE";
							}
						}
						return "FALSE";
					}
					return "FALSE";
				}
				else if ("EXISTUSERTYPE" == op) { /// option == 1?
					auto x = Get(var, val, utPosition, global);
					if (x.first) {
						//if (x.second.size() > 1) { return "ERROR"; } ///
						for (int i = 0; i < x.second.size(); ++i) {
							if (x.second[i]->GetUserTypeItem(var).size() > 0)
							{
								return "TRUE";
							}
						}
						return "FALSE";
					}
					return "FALSE";
				}
				else if ("NOTEXISTITEM" == op) { /// option == 2 ?
					auto x = Get(var, val, utPosition, global);
					if (x.first) {
						//if (x.second.size() > 1) { return "ERROR"; } ///

						for (int i = 0; i < x.second.size(); ++i) {
							if (0 < x.second[i]->GetItem(var).size())
							{
								return "FALSE";
							}
						}
						return "TRUE";
					}
					return "FALSE";
				}
				else if ("NOTEXISTUSERTYPE" == op) { /// option == 2 ?
					auto x = Get(var, val, utPosition, global);
					if (x.first) {
						//if (x.second.size() > 1) { return "ERROR"; } ///

						for (int i = 0; i < x.second.size(); ++i) {
							if (0 < x.second[i]->GetUserTypeItem(var).size())
							{
								return "FALSE";
							}
						}
						return "TRUE";
					}
					return "FALSE";
				}

				return "ERROR";
			}
			string GetValue(const string& op, const string& var1, const string& position1, const string& var2, const string& position2,
				UserType* utPosition, UserType* global, const string& option = "0")
			{
				// COMP<, COMP>, EQ, NOTEQ
				if (NULL == utPosition) { return "ERROR"; }

				auto x = Get(var1, position1, utPosition, global);
				auto y = Get(var2, position2, utPosition, global);

				if ("~" != position1 && false == x.first)
				{
					return "ERROR GV1";
				}
				if ("~" != position2 && false == y.first)
				{
					return "ERROR GV2";
				}
				//
				if (((x.first && x.second.size() > 1) || (y.first && y.second.size() > 1))) {
					return "ERROR GV3";
				}

				vector<ItemType<string>> value1;  // Item<string> <-
				vector<ItemType<string>> value2;

				// added..
				if (position1 != "~") {
					value1 = x.second[0]->GetItem(var1);
				}
				if (position2 != "~") {
					value2 = y.second[0]->GetItem(var2);
				}
				//
				if (position1 == "~" ) {
					value1.push_back(ItemType<string>()); // var1
					value1[0].Push(var1);
				}
				if (position2 == "~") {
					value2.push_back(ItemType<string>()); // var2
					value2[0].Push(var2);
				}

				//
				if (value1.size() == 0) {
					return "ERROR GV4";
				}
				if (value2.size() == 0) {
					return "ERROR GV5";
				}

				if (option == "0" && (value1.size() > 1 || value2.size() > 1)) {
					return "ERROR GV6";
				}

				if ("COMP<" == op) {
					if ("0" != option) { // ToDo.. // 0. just 1-1, // 1. for any case // 2. for all case
						for (int i = 0; i < value1.size(); ++i) {
							for (int j = 0; j < value2.size(); ++j) {
								if (Utility::Compare(value1[i].Get(0), value2[j].Get(0)) == "< 0") {
									if ("1" == option) { return "TRUE"; }
								}
								else {
									if ("2" == option) { return "FALSE"; }
								}
							}
						}
						if ("1" == option) { return "FALSE"; }
						else if ("2" == option) {
							return "TRUE";
						}
					}
					else {
						if (Utility::Compare(value1[0].Get(0), value2[0].Get(0)) == "< 0") {
							return "TRUE";
						}
					}
					return "FALSE";
				}
				else if ("COMP<EQ" == op) {
					if ("0" != option) { /// ToDo.. // 0. just 1-1, // 1. for any case // 2. for all case
						for (int i = 0; i < value1.size(); ++i) {
							for (int j = 0; j < value2.size(); ++j) {
								string temp = Utility::Compare(value1[i].Get(0), value2[j].Get(0));
									if (temp == "< 0" || temp == "== 0") {
										if ("1" == option) { return "TRUE"; }
									}
									else {
										if ("2" == option) { return "FALSE"; }
									}
							}
						}
						if ("1" == option) { return "FALSE"; }
						else if ("2" == option) {
							return "TRUE";
						}
					}
					else {
						string temp = Utility::Compare(value1[0].Get(0), value2[0].Get(0));
						if (temp == "< 0" || temp == "== 0") {
							return "TRUE";
						}
					}
					return "FALSE";
				}
				else if ("COMP>" == op) {
					if ("0" != option) { /// ToDo.. // 0. just 1-1, // 1. for any case // 2. for all case
						for (int i = 0; i < value1.size(); ++i) {
							for (int j = 0; j < value2.size(); ++j) {
								if (Utility::Compare(value1[i].Get(0), value2[j].Get(0)) == "> 0") {
									if ("1" == option) { return "TRUE"; }
								}
								else {
									if ("2" == option) { return "FALSE"; }
								}
							}
						}
						if ("1" == option) { return "FALSE"; }
						else if ("2" == option) {
							return "TRUE";
						}
					}
					else {
						if (Utility::Compare(value1[0].Get(0), value2[0].Get(0)) == "> 0") {
							return "TRUE";
						}
					}
					return "FALSE";
				}
				else if ("COMP>EQ" == op) {
					if ("0" != option) { /// ToDo.. // 0. just 1-1, // 1. for any case // 2. for all case
						for (int i = 0; i < value1.size(); ++i) {
							for (int j = 0; j < value2.size(); ++j) {
								string temp = Utility::Compare(value1[i].Get(0), value2[j].Get(0));
								if (temp == "> 0" || temp == "== 0") {
									if ("1" == option) { return "TRUE"; }
								}
								else {
									if ("2" == option) { return "FALSE"; }
								}
							}
						}
						if ("1" == option) { return "FALSE"; }
						else if ("2" == option) {
							return "TRUE";
						}
					}
					else {
						string temp = Utility::Compare(value1[0].Get(0), value2[0].Get(0));
						if (temp == "> 0" || temp == "== 0") {
							return "TRUE";
						}
					}
					return "FALSE";
				}
				else if ("EQ" == op) {
					if ("0" != option) { /// ToDo.. // 0. just 1-1, // 1. for any case // 2. for all case
						for (int i = 0; i < value1.size(); ++i) {
							for (int j = 0; j < value2.size(); ++j) {
								if (Utility::Compare(value1[i].Get(0), value2[j].Get(0)) == "== 0") {
									if ("1" == option) { return "TRUE"; }
								}
								else {
									if ("2" == option) { return "FALSE"; }
								}
							}
						}
						if ("1" == option) { return "FALSE"; }
						else if ("2" == option) {
							return "TRUE";
						}
					}
					else {
						if (Utility::Compare(value1[0].Get(0), value2[0].Get(0)) == "== 0") {
							return "TRUE";
						}
					}
					return "FALSE";
				}
				else if ("NOTEQ" == op) {
					if ("0" != option) { /// ToDo.. // 0. just 1-1, // 1. for any case // 2. for all case
						for (int i = 0; i < value1.size(); ++i) {
							for (int j = 0; j < value2.size(); ++j) {
								if (Utility::Compare(value1[i].Get(0), value2[j].Get(0)) != "== 0") {
									if ("1" == option) { return "TRUE"; }
								}
								else {
									if ("2" == option) { return "FALSE"; }
								}
							}
						}
						if ("1" == option) { return "FALSE"; }
						else if ("2" == option) {
							return "TRUE";
						}
					}
					else {
						if (Utility::Compare(value1[0].Get(0), value2[0].Get(0)) != "== 0") {
							return "TRUE";
						}
					}
					return "FALSE";
				}
				else if ("REGEX" == op) {
					if ("0" != option) { /// ToDo.. // 0. just 1-1, // 1. for any case // 2. for all case
						for (int i = 0; i < value1.size(); ++i) {
							for (int j = 0; j < value2.size(); ++j) {
								std::regex rex(value2[j].Get(0).substr(1, value2[j].Get(0).size() - 2));

								if (std::regex_match(value1[i].Get(0), rex)) {
									if ("1" == option) { return "TRUE"; }
								}
								else {
									if ("2" == option) { return "FALSE"; }
								}
							}
						}
						if ("1" == option) { return "FALSE"; }
						else if ("2" == option) {
							return "TRUE";
						}
					}
					else {
						std::regex rex(value2[0].Get(0).substr(1, value2[0].Get(0).size() - 2));

						if (std::regex_match(value1[0].Get(0), rex)) {
							return "TRUE";
						}
					}
					return "FALSE";
				}

				return "ERROR GV7";
			}

			void Init(const string& condition)
			{
				bool evalue = false;

				string str;
				Utility::AddSpace(condition, str);

				StringTokenizer tokenizer(str, { " ", "\t", "\n", "\r" });

				while (tokenizer.hasMoreTokens()) {
					string temp = tokenizer.nextToken();

					if (temp == "^") { //
						temp = "";
					}
					tokenVec.push_back(temp);
				}
			}
		public:
			bool Next() {
				try {
					if (i >= tokenVec.size()) { return false; }
					if (condition.empty()) {
						return false;
					}
					{
						if ("=" != tokenVec[i]
							&& "{" != tokenVec[i]
							&& "}" != tokenVec[i]) {
							tokenStack.push(tokenVec[i]);
						}

						if ("{" == tokenVec[i]) {
							braceNum++;
						}
						else if ("}" == tokenVec[i]) {
							braceNum--;

							// COMP<, COMP<EQ, COMP>, COMP>EQ, EQ, NOTEQ
							if (tokenStack.size() >= 6 && ("COMP<" == tokenStack[tokenStack.size() - 6]
								|| "COMP<EQ" == tokenStack[tokenStack.size() - 6]
								|| "COMP>" == tokenStack[tokenStack.size() - 6]
								|| "COMP>EQ" == tokenStack[tokenStack.size() - 6]
								|| "EQ" == tokenStack[tokenStack.size() - 6]
								|| "NOTEQ" == tokenStack[tokenStack.size() - 6]
								|| "REGEX" == tokenStack[tokenStack.size() - 6]
								))
							{
								const string op = tokenStack[tokenStack.size() - 6];
								const string var1 = tokenStack[tokenStack.size() - 5];
								const string position1 = tokenStack[tokenStack.size() - 4];
								const string var2 = tokenStack[tokenStack.size() - 3];
								const string position2 = tokenStack[tokenStack.size() - 2];
								const string option = tokenStack[tokenStack.size() - 1];
								tokenStack.pop();
								tokenStack.pop();
								tokenStack.pop();
								tokenStack.pop();
								tokenStack.pop();
								tokenStack.pop();

								tokenStack.push(GetValue(op, var1, position1, var2, position2, position, global, option));
							}
							else if (tokenStack.size() >= 3 && "NOT" != tokenStack[tokenStack.size() - 2]) {
								string op = tokenStack[tokenStack.size() - 3];
								const string operand1 = tokenStack[tokenStack.size() - 2];
								const string operand2 = tokenStack[tokenStack.size() - 1];

								if (op == "AND" || op == "OR") {
									tokenStack.pop();
									tokenStack.pop();
									tokenStack.pop();

									tokenStack.push(Utility::BoolOperation(op, operand1, operand2));
								}
								else { // EXIST, NOTEXIST for ( ITEM or USERTYPE ), regex
									tokenStack.pop();
									tokenStack.pop();
									tokenStack.pop();

									tokenStack.push(GetValue(op, operand1, operand2, position, global));
								}
							}
							else if (tokenStack.size() >= 2 && "NOT" == tokenStack[tokenStack.size() - 2]) {
								const string op = tokenStack[tokenStack.size() - 2];
								const string operand1 = tokenStack[tokenStack.size() - 1];

								tokenStack.pop();
								tokenStack.pop();
								tokenStack.push(Utility::BoolOperation(op, operand1, operand1));
							}
						}
						++i;
					}
				}
				catch (const char* err) { cout << err << endl; return false; }
				catch (Error& e) { cout << e << endl; return false; }
				return true;
			}
		public:
			int NowIndex()const { return i; }
			const ArrayStack<string>& Now()const { return tokenStack; }
			ArrayStack<string>& Now() { return tokenStack; }
			bool IsNowImportant() const { // ??
				return "}" == tokenVec[i] && "NOT" != tokenStack[tokenStack.size() - 2];
			}
		};
	}
}

#endif
<commit_msg>Delete LOAD_DATA_CONDITION.H<commit_after><|endoftext|>


<commit_before>/*
 * Copyright 2012 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBlendImageFilter.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkFlattenableBuffers.h"
#if SK_SUPPORT_GPU
#include "SkGr.h"
#include "SkGrPixelRef.h"
#include "gl/GrGLProgramStage.h"
#endif

namespace {

SkXfermode::Mode modeToXfermode(SkBlendImageFilter::Mode mode)
{
    switch (mode) {
      case SkBlendImageFilter::kNormal_Mode:
        return SkXfermode::kSrcOver_Mode;
      case SkBlendImageFilter::kMultiply_Mode:
        return SkXfermode::kMultiply_Mode;
      case SkBlendImageFilter::kScreen_Mode:
        return SkXfermode::kScreen_Mode;
      case SkBlendImageFilter::kDarken_Mode:
        return SkXfermode::kDarken_Mode;
      case SkBlendImageFilter::kLighten_Mode:
        return SkXfermode::kLighten_Mode;
    }
    SkASSERT(0);
    return SkXfermode::kSrcOver_Mode;
}

SkPMColor multiply_proc(SkPMColor src, SkPMColor dst) {
    int omsa = 255 - SkGetPackedA32(src);
    int sr = SkGetPackedR32(src), sg = SkGetPackedG32(src), sb = SkGetPackedB32(src);
    int omda = 255 - SkGetPackedA32(dst);
    int dr = SkGetPackedR32(dst), dg = SkGetPackedG32(dst), db = SkGetPackedB32(dst);
    int a = 255 - SkMulDiv255Round(omsa, omda);
    int r = SkMulDiv255Round(omsa, dr) + SkMulDiv255Round(omda, sr) + SkMulDiv255Round(sr, dr);
    int g = SkMulDiv255Round(omsa, dg) + SkMulDiv255Round(omda, sg) + SkMulDiv255Round(sg, dg);
    int b = SkMulDiv255Round(omsa, db) + SkMulDiv255Round(omda, sb) + SkMulDiv255Round(sb, db);
    return SkPackARGB32(a, r, g, b);
}

};

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

SkBlendImageFilter::SkBlendImageFilter(SkBlendImageFilter::Mode mode, SkImageFilter* background, SkImageFilter* foreground)
  : fMode(mode)
{
    fBackground = background;
    SkASSERT(background != NULL);
    SkSafeRef(fBackground);
    fForeground = foreground;
    SkSafeRef(fForeground);
}

SkBlendImageFilter::~SkBlendImageFilter() {
    SkSafeUnref(fBackground);
    SkSafeUnref(fForeground);
}

SkBlendImageFilter::SkBlendImageFilter(SkFlattenableReadBuffer& buffer)
  : INHERITED(buffer)
{
    fMode = (SkBlendImageFilter::Mode) buffer.readInt();
    fBackground = buffer.readFlattenableT<SkImageFilter>();
    if (buffer.readBool()) {
        fForeground = buffer.readFlattenableT<SkImageFilter>();
    } else {
        fForeground = NULL;
    }
}

void SkBlendImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writeInt((int) fMode);
    buffer.writeFlattenable(fBackground);
    buffer.writeBool(NULL != fForeground);
    if (NULL != fForeground) {
        buffer.writeFlattenable(fForeground);
    }
}

bool SkBlendImageFilter::onFilterImage(Proxy* proxy,
                                       const SkBitmap& src,
                                       const SkMatrix& ctm,
                                       SkBitmap* dst,
                                       SkIPoint* offset) {
    SkBitmap background, foreground = src;
    SkASSERT(fBackground);
    if (!fBackground->filterImage(proxy, src, ctm, &background, offset)) {
        return false;
    }
    if (fForeground && !fForeground->filterImage(proxy, src, ctm, &foreground, offset)) {
        return false;
    }
    SkAutoLockPixels alp_foreground(foreground), alp_background(background);
    if (!foreground.getPixels() || !background.getPixels()) {
        return false;
    }
    dst->setConfig(background.config(), background.width(), background.height());
    dst->allocPixels();
    SkCanvas canvas(*dst);
    SkPaint paint;
    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    canvas.drawBitmap(background, 0, 0, &paint);
    // FEBlend's multiply mode is (1 - Sa) * Da + (1 - Da) * Sc + Sc * Dc
    // Skia's is just Sc * Dc.  So we use a custom proc to implement FEBlend's
    // version.
    if (fMode == SkBlendImageFilter::kMultiply_Mode) {
        paint.setXfermode(new SkProcXfermode(multiply_proc))->unref();
    } else {
        paint.setXfermodeMode(modeToXfermode(fMode));
    }
    canvas.drawBitmap(foreground, 0, 0, &paint);
    return true;
}

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

#if SK_SUPPORT_GPU
class GrGLBlendEffect  : public GrGLProgramStage {
public:
    GrGLBlendEffect(const GrProgramStageFactory& factory,
                    const GrCustomStage& stage);
    virtual ~GrGLBlendEffect();

    virtual void emitFS(GrGLShaderBuilder* builder,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) SK_OVERRIDE;

    virtual void emitVS(GrGLShaderBuilder* builder,
                        const char* vertexCoords) SK_OVERRIDE {}

    static inline StageKey GenKey(const GrCustomStage& s, const GrGLCaps&);

private:
    typedef GrGLProgramStage INHERITED;
    SkBlendImageFilter::Mode fMode;
};

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

class GrBlendEffect : public GrSingleTextureEffect {
public:
    GrBlendEffect(SkBlendImageFilter::Mode mode, GrTexture* foreground);
    virtual ~GrBlendEffect();

    virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
    const GrProgramStageFactory& getFactory() const;
    SkBlendImageFilter::Mode mode() const { return fMode; }

    typedef GrGLBlendEffect GLProgramStage;
    static const char* Name() { return "Blend"; }

private:
    typedef GrSingleTextureEffect INHERITED;
    SkBlendImageFilter::Mode fMode;
};

// FIXME:  This should be refactored with SkSingleInputImageFilter's version.
static GrTexture* getInputResultAsTexture(SkImageFilter* input,
                                          GrTexture* src,
                                          const SkRect& rect) {
    GrTexture* resultTex;
    if (!input) {
        resultTex = src;
    } else if (input->canFilterImageGPU()) {
        // onFilterImageGPU() already refs the result, so just return it here.
        return input->onFilterImageGPU(src, rect);
    } else {
        SkBitmap srcBitmap, result;
        srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, src->width(), src->height());
        srcBitmap.setPixelRef(new SkGrPixelRef(src))->unref();
        SkIPoint offset;
        if (input->filterImage(NULL, srcBitmap, SkMatrix(), &result, &offset)) {
            if (result.getTexture()) {
                resultTex = (GrTexture*) result.getTexture();
            } else {
                resultTex = GrLockCachedBitmapTexture(src->getContext(), result, NULL);
                SkSafeRef(resultTex);
                GrUnlockCachedBitmapTexture(resultTex);
                return resultTex;
            }
        } else {
            resultTex = src;
        }
    }
    SkSafeRef(resultTex);
    return resultTex;
}

GrTexture* SkBlendImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
    SkAutoTUnref<GrTexture> background(getInputResultAsTexture(fBackground, src, rect));
    SkAutoTUnref<GrTexture> foreground(getInputResultAsTexture(fForeground, src, rect));
    GrContext* context = src->getContext();

    GrTextureDesc desc;
    desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
    desc.fWidth = SkScalarCeilToInt(rect.width());
    desc.fHeight = SkScalarCeilToInt(rect.height());
    desc.fConfig = kRGBA_8888_GrPixelConfig;

    GrAutoScratchTexture ast(context, desc);
    GrTexture* dst = ast.detach();
    GrContext::AutoMatrix avm(context, GrMatrix::I());
    GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
    GrContext::AutoClip ac(context, rect);

    GrMatrix sampleM;
    sampleM.setIDiv(background->width(), background->height());
    GrPaint paint;
    paint.reset();
    paint.textureSampler(0)->reset(sampleM);
    paint.textureSampler(0)->setCustomStage(SkNEW_ARGS(GrSingleTextureEffect, (background.get())))->unref();
    paint.textureSampler(1)->reset(sampleM);
    paint.textureSampler(1)->setCustomStage(SkNEW_ARGS(GrBlendEffect, (fMode, foreground.get())))->unref();
    context->drawRect(paint, rect);
    return dst;
}

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

GrBlendEffect::GrBlendEffect(SkBlendImageFilter::Mode mode, GrTexture* foreground)
    : INHERITED(foreground), fMode(mode) {
}

GrBlendEffect::~GrBlendEffect() {
}

bool GrBlendEffect::isEqual(const GrCustomStage& sBase) const {
    const GrBlendEffect& s = static_cast<const GrBlendEffect&>(sBase);
    return INHERITED::isEqual(sBase) &&
           fMode == s.fMode;
}

const GrProgramStageFactory& GrBlendEffect::getFactory() const {
    return GrTProgramStageFactory<GrBlendEffect>::getInstance();
}

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

GrGLBlendEffect::GrGLBlendEffect(const GrProgramStageFactory& factory,
                                 const GrCustomStage& stage)
    : GrGLProgramStage(factory),
      fMode(static_cast<const GrBlendEffect&>(stage).mode()) {
}

GrGLBlendEffect::~GrGLBlendEffect() {
}

void GrGLBlendEffect::emitFS(GrGLShaderBuilder* builder,
                             const char* outputColor,
                             const char* inputColor,
                             const char* samplerName) {
    SkString* code = &builder->fFSCode;
    const char* bgColor = inputColor;
    const char* fgColor = "fgColor";
    code->appendf("\t\tvec4 %s = ", fgColor);
    builder->emitTextureLookup(samplerName);
    code->appendf(";\n");
    code->appendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - %s.b);\n", outputColor, bgColor, fgColor);
    switch (fMode) {
      case SkBlendImageFilter::kNormal_Mode:
        code->appendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + %s.rgb;\n", outputColor, fgColor, bgColor, fgColor);
        break;
      case SkBlendImageFilter::kMultiply_Mode:
        code->appendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb + %s.rgb * %s.rgb;\n", outputColor, fgColor, bgColor, bgColor, fgColor, fgColor, bgColor);
        break;
      case SkBlendImageFilter::kScreen_Mode:
        code->appendf("\t\t%s.rgb = %s.rgb + %s.rgb - %s.rgb * %s.rgb;\n", outputColor, bgColor, fgColor, fgColor, bgColor);
        break;
      case SkBlendImageFilter::kDarken_Mode:
        code->appendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, (1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bgColor, fgColor, bgColor);
        break;
      case SkBlendImageFilter::kLighten_Mode:
        code->appendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, (1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bgColor, fgColor, bgColor);
        break;
    }
}

GrGLProgramStage::StageKey GrGLBlendEffect::GenKey(const GrCustomStage& s, const GrGLCaps&) {
    return static_cast<const GrBlendEffect&>(s).mode();
}
#endif

SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlendImageFilter)
<commit_msg>Another speculative Android build fix (unreviewed).<commit_after>/*
 * Copyright 2012 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBlendImageFilter.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkFlattenableBuffers.h"
#if SK_SUPPORT_GPU
#include "SkGr.h"
#include "SkGrPixelRef.h"
#include "gl/GrGLProgramStage.h"
#endif

namespace {

SkXfermode::Mode modeToXfermode(SkBlendImageFilter::Mode mode)
{
    switch (mode) {
      case SkBlendImageFilter::kNormal_Mode:
        return SkXfermode::kSrcOver_Mode;
      case SkBlendImageFilter::kMultiply_Mode:
        return SkXfermode::kMultiply_Mode;
      case SkBlendImageFilter::kScreen_Mode:
        return SkXfermode::kScreen_Mode;
      case SkBlendImageFilter::kDarken_Mode:
        return SkXfermode::kDarken_Mode;
      case SkBlendImageFilter::kLighten_Mode:
        return SkXfermode::kLighten_Mode;
    }
    SkASSERT(0);
    return SkXfermode::kSrcOver_Mode;
}

SkPMColor multiply_proc(SkPMColor src, SkPMColor dst) {
    int omsa = 255 - SkGetPackedA32(src);
    int sr = SkGetPackedR32(src), sg = SkGetPackedG32(src), sb = SkGetPackedB32(src);
    int omda = 255 - SkGetPackedA32(dst);
    int dr = SkGetPackedR32(dst), dg = SkGetPackedG32(dst), db = SkGetPackedB32(dst);
    int a = 255 - SkMulDiv255Round(omsa, omda);
    int r = SkMulDiv255Round(omsa, dr) + SkMulDiv255Round(omda, sr) + SkMulDiv255Round(sr, dr);
    int g = SkMulDiv255Round(omsa, dg) + SkMulDiv255Round(omda, sg) + SkMulDiv255Round(sg, dg);
    int b = SkMulDiv255Round(omsa, db) + SkMulDiv255Round(omda, sb) + SkMulDiv255Round(sb, db);
    return SkPackARGB32(a, r, g, b);
}

};

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

SkBlendImageFilter::SkBlendImageFilter(SkBlendImageFilter::Mode mode, SkImageFilter* background, SkImageFilter* foreground)
  : fMode(mode)
{
    fBackground = background;
    SkASSERT(background != NULL);
    SkSafeRef(fBackground);
    fForeground = foreground;
    SkSafeRef(fForeground);
}

SkBlendImageFilter::~SkBlendImageFilter() {
    SkSafeUnref(fBackground);
    SkSafeUnref(fForeground);
}

SkBlendImageFilter::SkBlendImageFilter(SkFlattenableReadBuffer& buffer)
  : INHERITED(buffer)
{
    fMode = (SkBlendImageFilter::Mode) buffer.readInt();
    fBackground = buffer.readFlattenableT<SkImageFilter>();
    if (buffer.readBool()) {
        fForeground = buffer.readFlattenableT<SkImageFilter>();
    } else {
        fForeground = NULL;
    }
}

void SkBlendImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writeInt((int) fMode);
    buffer.writeFlattenable(fBackground);
    buffer.writeBool(NULL != fForeground);
    if (NULL != fForeground) {
        buffer.writeFlattenable(fForeground);
    }
}

bool SkBlendImageFilter::onFilterImage(Proxy* proxy,
                                       const SkBitmap& src,
                                       const SkMatrix& ctm,
                                       SkBitmap* dst,
                                       SkIPoint* offset) {
    SkBitmap background, foreground = src;
    SkASSERT(fBackground);
    if (!fBackground->filterImage(proxy, src, ctm, &background, offset)) {
        return false;
    }
    if (fForeground && !fForeground->filterImage(proxy, src, ctm, &foreground, offset)) {
        return false;
    }
    SkAutoLockPixels alp_foreground(foreground), alp_background(background);
    if (!foreground.getPixels() || !background.getPixels()) {
        return false;
    }
    dst->setConfig(background.config(), background.width(), background.height());
    dst->allocPixels();
    SkCanvas canvas(*dst);
    SkPaint paint;
    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    canvas.drawBitmap(background, 0, 0, &paint);
    // FEBlend's multiply mode is (1 - Sa) * Da + (1 - Da) * Sc + Sc * Dc
    // Skia's is just Sc * Dc.  So we use a custom proc to implement FEBlend's
    // version.
    if (fMode == SkBlendImageFilter::kMultiply_Mode) {
        paint.setXfermode(new SkProcXfermode(multiply_proc))->unref();
    } else {
        paint.setXfermodeMode(modeToXfermode(fMode));
    }
    canvas.drawBitmap(foreground, 0, 0, &paint);
    return true;
}

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

#if SK_SUPPORT_GPU
class GrGLBlendEffect  : public GrGLProgramStage {
public:
    GrGLBlendEffect(const GrProgramStageFactory& factory,
                    const GrCustomStage& stage);
    virtual ~GrGLBlendEffect();

    virtual void emitFS(GrGLShaderBuilder* builder,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) SK_OVERRIDE;

    virtual void emitVS(GrGLShaderBuilder* builder,
                        const char* vertexCoords) SK_OVERRIDE {}

    static inline StageKey GenKey(const GrCustomStage& s, const GrGLCaps&);

private:
    typedef GrGLProgramStage INHERITED;
    SkBlendImageFilter::Mode fMode;
};

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

class GrBlendEffect : public GrSingleTextureEffect {
public:
    GrBlendEffect(SkBlendImageFilter::Mode mode, GrTexture* foreground);
    virtual ~GrBlendEffect();

    virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
    const GrProgramStageFactory& getFactory() const;
    SkBlendImageFilter::Mode mode() const { return fMode; }

    typedef GrGLBlendEffect GLProgramStage;
    static const char* Name() { return "Blend"; }

private:
    typedef GrSingleTextureEffect INHERITED;
    SkBlendImageFilter::Mode fMode;
};

// FIXME:  This should be refactored with SkSingleInputImageFilter's version.
static GrTexture* getInputResultAsTexture(SkImageFilter* input,
                                          GrTexture* src,
                                          const SkRect& rect) {
    GrTexture* resultTex;
    if (!input) {
        resultTex = src;
    } else if (input->canFilterImageGPU()) {
        // onFilterImageGPU() already refs the result, so just return it here.
        return input->onFilterImageGPU(src, rect);
    } else {
        SkBitmap srcBitmap, result;
        srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, src->width(), src->height());
        srcBitmap.setPixelRef(new SkGrPixelRef(src))->unref();
        SkIPoint offset;
        if (input->filterImage(NULL, srcBitmap, SkMatrix(), &result, &offset)) {
            if (result.getTexture()) {
                resultTex = (GrTexture*) result.getTexture();
            } else {
                resultTex = GrLockCachedBitmapTexture(src->getContext(), result, NULL);
                SkSafeRef(resultTex);
                GrUnlockCachedBitmapTexture(resultTex);
                return resultTex;
            }
        } else {
            resultTex = src;
        }
    }
    SkSafeRef(resultTex);
    return resultTex;
}

GrTexture* SkBlendImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
    SkAutoTUnref<GrTexture> background(getInputResultAsTexture(fBackground, src, rect));
    SkAutoTUnref<GrTexture> foreground(getInputResultAsTexture(fForeground, src, rect));
    GrContext* context = src->getContext();

    GrTextureDesc desc;
    desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
    desc.fWidth = SkScalarCeilToInt(rect.width());
    desc.fHeight = SkScalarCeilToInt(rect.height());
    desc.fConfig = kRGBA_8888_GrPixelConfig;

    GrAutoScratchTexture ast(context, desc);
    GrTexture* dst = ast.detach();
    GrContext::AutoMatrix avm(context, GrMatrix::I());
    GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
    GrContext::AutoClip ac(context, rect);

    GrMatrix sampleM;
    sampleM.setIDiv(background->width(), background->height());
    GrPaint paint;
    paint.reset();
    paint.textureSampler(0)->reset(sampleM);
    paint.textureSampler(0)->setCustomStage(SkNEW_ARGS(GrSingleTextureEffect, (background.get())))->unref();
    paint.textureSampler(1)->reset(sampleM);
    paint.textureSampler(1)->setCustomStage(SkNEW_ARGS(GrBlendEffect, (fMode, foreground.get())))->unref();
    context->drawRect(paint, rect);
    return dst;
}

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

GrBlendEffect::GrBlendEffect(SkBlendImageFilter::Mode mode, GrTexture* foreground)
    : INHERITED(foreground), fMode(mode) {
}

GrBlendEffect::~GrBlendEffect() {
}

bool GrBlendEffect::isEqual(const GrCustomStage& sBase) const {
    const GrBlendEffect& s = static_cast<const GrBlendEffect&>(sBase);
    return INHERITED::isEqual(sBase) &&
           fMode == s.fMode;
}

const GrProgramStageFactory& GrBlendEffect::getFactory() const {
    return GrTProgramStageFactory<GrBlendEffect>::getInstance();
}

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

GrGLBlendEffect::GrGLBlendEffect(const GrProgramStageFactory& factory,
                                 const GrCustomStage& stage)
    : GrGLProgramStage(factory),
      fMode(static_cast<const GrBlendEffect&>(stage).mode()) {
}

GrGLBlendEffect::~GrGLBlendEffect() {
}

void GrGLBlendEffect::emitFS(GrGLShaderBuilder* builder,
                             const char* outputColor,
                             const char* inputColor,
                             const char* samplerName) {
    SkString* code = &builder->fFSCode;
    const char* bgColor = inputColor;
    const char* fgColor = "fgColor";
    code->appendf("\t\tvec4 %s = ", fgColor);
    builder->emitTextureLookup(samplerName);
    code->appendf(";\n");
    code->appendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - %s.b);\n", outputColor, bgColor, fgColor);
    switch (fMode) {
      case SkBlendImageFilter::kNormal_Mode:
        code->appendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + %s.rgb;\n", outputColor, fgColor, bgColor, fgColor);
        break;
      case SkBlendImageFilter::kMultiply_Mode:
        code->appendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb + %s.rgb * %s.rgb;\n", outputColor, fgColor, bgColor, bgColor, fgColor, fgColor, bgColor);
        break;
      case SkBlendImageFilter::kScreen_Mode:
        code->appendf("\t\t%s.rgb = %s.rgb + %s.rgb - %s.rgb * %s.rgb;\n", outputColor, bgColor, fgColor, fgColor, bgColor);
        break;
      case SkBlendImageFilter::kDarken_Mode:
        code->appendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, (1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bgColor, fgColor, bgColor);
        break;
      case SkBlendImageFilter::kLighten_Mode:
        code->appendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, (1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bgColor, fgColor, bgColor);
        break;
    }
}

GrGLProgramStage::StageKey GrGLBlendEffect::GenKey(const GrCustomStage& s, const GrGLCaps&) {
    return static_cast<const GrBlendEffect&>(s).mode();
}
#endif

SK_DEFINE_FLATTENABLE_REGISTRAR(SkBlendImageFilter)
<|endoftext|>


<commit_before>//#include <lib/d>
#include <gtest/gtest.h>
#include <gmpxx.h>
#include "../../lib/rsa-attack-lib/rsa-attack-lib.h"
using namespace std;

// TEST(dorothyStub, oneEqualsone) {
//   int one = 1;
//   EXPECT_EQ(1, one);
// }

TEST(factorize, smallSemiPrime) {
  mpz_class small_n = 1767;
  vector<mpz_class> expected_outputs = {31, 57};
  vector<mpz_class> actual = findFactors(small_n);
  EXPECT_EQ(expected_outputs, actual);
}

TEST(factorize, bigSemiPrime) {
  mpz_class big_n = 8884963;
  vector<mpz_class> expected_outputs = {3319, 2677};

  //output won't be the same
  EXPECT_EQ(expected_outputs, findFactors(big_n));
}

TEST(factorize, smallNormalNumber) {
  mpz_class norm_num = 108;
  vector<mpz_class> expected_outputs = {2, 3, 4, 6, 9, 12, 18, 27, 36, 54};

  EXPECT_EQ(expected_outputs, findFactors(norm_num));
}
<commit_msg>Fixed tests to accomodate new function definition<commit_after>//#include <lib/d>
#include <gtest/gtest.h>
#include <gmpxx.h>
#include "../../lib/rsa-attack-lib/rsa-attack-lib.h"
using namespace std;

// TEST(dorothyStub, oneEqualsone) {
//   int one = 1;
//   EXPECT_EQ(1, one);
// }

 TEST(factorize, smallSemiPrime) {
   mpz_class small_n = 1767;
   vector<pair<mpz_class, mpz_class > > expected_outputs = {
     pair<mpz_class, mpz_class >(31, 57)
   };
   EXPECT_EQ(expected_outputs, findFactors(small_n));
 }

 TEST(factorize, bigSemiPrime) {
   mpz_class big_n = 8884963;
   vector<pair<mpz_class, mpz_class > > expected_outputs = {
     pair<mpz_class, mpz_class >(2677, 3319)
   };

   //output won't be the same
   EXPECT_EQ(expected_outputs, findFactors(big_n));
 }

TEST(factorize, smallNormalNumber) {
  mpz_class norm_num = 108;
  vector<pair<mpz_class, mpz_class > > expected_outputs = {
    pair<mpz_class, mpz_class >(2, 54),
    pair<mpz_class, mpz_class >(3, 36),
    pair<mpz_class, mpz_class >(4, 27),
    pair<mpz_class, mpz_class >(6, 18),
    pair<mpz_class, mpz_class >(9, 12)
  };

  EXPECT_EQ(expected_outputs, findFactors(norm_num));
}
<|endoftext|>


<commit_before>/* Copyright 2016 CyberTech Labs Ltd.
 *
 * 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 "powerLevel.h"

using namespace trikGui;

PowerLevel::Level PowerLevel::currentLevel()
{
	return Level::twentyVolt;
}
<commit_msg>Fixed Windows build<commit_after>/* Copyright 2016 CyberTech Labs Ltd.
 *
 * 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 "powerLevel.h"

using namespace trikGui;

PowerLevel::Level PowerLevel::currentLevel()
{
	return Level::twelveVolt;
}
<|endoftext|>