Below is the file 'src/asn1_eac_tm.cpp' from this revision. You can also download the file.

/*************************************************
* X.509 Time Types Source File                   *
* (C) 1999-2007 The Botan Project                *
*************************************************/

#include <botan/asn1_obj.h>
#include <botan/der_enc.h>
#include <botan/ber_dec.h>
#include <botan/charset.h>
#include <botan/parsing.h>
#include <botan/config.h>
#include <ctime>
#include <sstream>

namespace Botan
  {

    namespace
      {

        /*************************************************
                * Convert a time_t to a struct tm                *
        *************************************************/
        std::tm get_tm(u64bit timer)
        {
          std::time_t time_val = static_cast<std::time_t>(timer);

          std::tm* tm_p = std::gmtime(&time_val);
          if (tm_p == 0)
            throw Encoding_Error("EAC_Time: gmtime could not encode " +
                                 to_string(timer));
          return (*tm_p);
        }
        SecureVector<byte> enc_two_digit(u32bit in)
        {
          SecureVector<byte> result;
          in %= 100;
          if (in < 10)
            {
              result.append(0x00);
            }
          else
            {
              u32bit y_first_pos = (in - (in%10))/10;
              result.append(static_cast<byte>(y_first_pos));
            }
          u32bit y_sec_pos = in%10;
          result.append(static_cast<byte>(y_sec_pos));
          return result;
        }
        u32bit dec_two_digit(byte b1, byte b2)
        {
          u32bit upper = (u32bit)b1;
          u32bit lower = (u32bit)b2;
          if (upper > 9 || lower > 9)
            {
              throw Invalid_Argument("u32bit dec_two_digit(byte b1, byte b2): value too large");
            }
          return upper*10 + lower;

        }
      }

    /*************************************************
        * Create an EAC_Time                            *
    *************************************************/
    EAC_Time::EAC_Time(u64bit timer, ASN1_Tag t)
        :tag(t)
    {
      std::tm time_info = get_tm(timer);

      year   = time_info.tm_year + 1900;
      month  = time_info.tm_mon + 1;
      day    = time_info.tm_mday;

    }

    /*************************************************
    * Create an EAC_Time                             *
    *************************************************/
    EAC_Time::EAC_Time(const std::string& t_spec, ASN1_Tag t)
        :tag(t)
    {
      set_to(t_spec);
    }
    /*************************************************
    * Create an EAC_Time                             *
    *************************************************/
    EAC_Time::EAC_Time(u32bit y, u32bit m, u32bit d, ASN1_Tag t)
    : year(y),
    month(m),
    day(d),
    tag(t)
    {
    }

    /*************************************************
        * Set the time with a human readable string      *
    *************************************************/
    void EAC_Time::set_to(const std::string& time_str)
    {
      if (time_str == "")
        {
          year = month = day = 0;
          return;
        }

      std::vector<std::string> params;
      std::string current;

      for (u32bit j = 0; j != time_str.size(); ++j)
        {
          if (Charset::is_digit(time_str[j]))
            current += time_str[j];
          else
            {
              if (current != "")
                params.push_back(current);
              current.clear();
            }
        }
      if (current != "")
        params.push_back(current);

      if (params.size() != 3)
        throw Invalid_Argument("Invalid time specification " + time_str);

      year   = to_u32bit(params[0]);
      month  = to_u32bit(params[1]);
      day    = to_u32bit(params[2]);

      if (!passes_sanity_check())
        throw Invalid_Argument("Invalid time specification " + time_str);
    }


    /*************************************************
        * DER encode a EAC_Time                         *
    *************************************************/
    void EAC_Time::encode_into(DER_Encoder& der) const
      {
        der.add_object(tag, APPLICATION,
                       encoded_eac_time());
      }

    /*************************************************
        * Return a string representation of the time     *
    *************************************************/
    std::string EAC_Time::as_string() const
      {
        if (time_is_set() == false)
          throw Invalid_State("EAC_Time::as_string: No time set");

        std::string asn1rep;
        asn1rep = to_string(year, 2);

        asn1rep += to_string(month, 2) + to_string(day, 2);

        return asn1rep;
      }

    /*************************************************
        * Return if the time has been set somehow        *
    *************************************************/
    bool EAC_Time::time_is_set() const
      {
        return (year != 0);
      }

    /*************************************************
        * Return a human readable string representation  *
    *************************************************/
    std::string EAC_Time::readable_string() const
      {
        if (time_is_set() == false)
          throw Invalid_State("EAC_Time::readable_string: No time set");

        std::string readable;
        readable += to_string(year,     2) + "/";
        readable += to_string(month,    2) + "/";
        readable += to_string(day,      2) + " ";

        return readable;
      }

    /*************************************************
        * Do a general sanity check on the time          *
    *************************************************/
    bool EAC_Time::passes_sanity_check() const
      {
        if (year < 2000 || year > 2099)
          return false;
        if (month == 0 || month > 12)
          return false;
        if (day == 0 || day > 31)
          return false;

        return true;
      }

    /******************************************
    * modification functions                  *
    ******************************************/

    void EAC_Time::add_years(u32bit years)
    {
      year += years;
    }
    void EAC_Time::add_months(u32bit months)
    {
      year += months/12;
      month += months % 12;
      if(month > 12)
      {
       year += 1;
       month -= 12;
      }
    }


    /*************************************************
        * Compare this time against another              *
    *************************************************/
    s32bit EAC_Time::cmp(const EAC_Time& other) const
      {
        if (time_is_set() == false)
          throw Invalid_State("EAC_Time::cmp: No time set");

        const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0;

        if (year < other.year)     return EARLIER;
        if (year > other.year)     return LATER;
        if (month < other.month)   return EARLIER;
        if (month > other.month)   return LATER;
        if (day < other.day)       return EARLIER;
        if (day > other.day)       return LATER;

        return SAME_TIME;
      }

    /*************************************************
        * Compare two EAC_Times for in various ways     *
    *************************************************/
    bool operator==(const EAC_Time& t1, const EAC_Time& t2)
    {
      return (t1.cmp(t2) == 0);
    }
    bool operator!=(const EAC_Time& t1, const EAC_Time& t2)
    {
      return (t1.cmp(t2) != 0);
    }
    bool operator<=(const EAC_Time& t1, const EAC_Time& t2)
    {
      return (t1.cmp(t2) <= 0);
    }
    bool operator>=(const EAC_Time& t1, const EAC_Time& t2)
    {
      return (t1.cmp(t2) >= 0);
    }
    bool operator>(const EAC_Time& t1, const EAC_Time& t2)
    {
      return (t1.cmp(t2) > 0);
    }
    bool operator<(const EAC_Time& t1, const EAC_Time& t2)
    {
      return (t1.cmp(t2) < 0);
    }

    /*************************************************
        * Do a validity check                            *
    *************************************************/
    s32bit validity_check(const EAC_Time& start, const EAC_Time& end,
                          u64bit current_time)
    {

      const s32bit NOT_YET_VALID = -1, VALID_TIME = 0, EXPIRED = 1;

      if (start.cmp(current_time) > 0)
        return NOT_YET_VALID;
      if (end.cmp(current_time) < 0)
        return EXPIRED;
      return VALID_TIME;
    }

    /*************************************************
    * Decode a BER encoded EAC_Time                 *
    *************************************************/
    void EAC_Time::decode_from(BER_Decoder& source)
    {
      BER_Object obj = source.get_next_object();
      if (obj.type_tag != this->tag)
        {
          std::string message("decoding type mismatch for EAC_Time, tag is ");
          std::stringstream ss;
          std::string str_is;
          ss << std::hex << obj.type_tag;
          ss >> str_is;
          message.append(str_is);
          message.append(", while it should be ");
          std::stringstream ss2;
          std::string str_should;
          ss2 << std::hex << this->tag;
          ss2 >> str_should;
          message.append(str_should);
          throw Decoding_Error(message);

        }
      if (obj.value.size() != 6)
        {
          throw Decoding_Error("EAC_Time decoding failed");
        }
      try
        {
          u32bit tmp_year = dec_two_digit(obj.value[0], obj.value[1]);
          u32bit tmp_mon = dec_two_digit(obj.value[2], obj.value[3]);
          u32bit tmp_day = dec_two_digit(obj.value[4], obj.value[5]);
          year = tmp_year + 2000;
          month = tmp_mon;
          day = tmp_day;
        }
      catch (Invalid_Argument)
        {
          throw Decoding_Error("EAC_Time decoding failed");
        }

    }

    u32bit EAC_Time::get_year() const
      {
        return year;
      }
    u32bit EAC_Time::get_month() const
      {
        return month;
      }
    u32bit EAC_Time::get_day() const
      {
        return day;
      }

    /*************************************************
    * make the value an octet string for encoding    *
    *************************************************/
    SecureVector<byte> EAC_Time::encoded_eac_time() const
      {
        SecureVector<byte> result;
        result.append(enc_two_digit(year));
        result.append(enc_two_digit(month));
        result.append(enc_two_digit(day));
        return result;
      }

    ASN1_Ced::ASN1_Ced(std::string const& str)
        : EAC_Time(str, ASN1_Tag(37))
    {}

    ASN1_Ced::ASN1_Ced(u64bit val)
        : EAC_Time(val, ASN1_Tag(37))
    {}

    ASN1_Ced::ASN1_Ced(EAC_Time const& other)
        : EAC_Time(other.get_year(), other.get_month(), other.get_day(), ASN1_Tag(37))
    {}

    ASN1_Cex::ASN1_Cex(std::string const& str)
        : EAC_Time(str, ASN1_Tag(36))
    {}

    ASN1_Cex::ASN1_Cex(u64bit val)
        : EAC_Time(val, ASN1_Tag(36))
    {}

    ASN1_Cex::ASN1_Cex(EAC_Time const& other)
        : EAC_Time(other.get_year(), other.get_month(), other.get_day(), ASN1_Tag(36))
    {}
  }