Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.location.cts.asn1.base;
     18 
     19 import com.google.common.collect.ImmutableList;
     20 
     21 import java.nio.ByteBuffer;
     22 import java.text.DecimalFormat;
     23 import java.util.Collection;
     24 
     25 /**
     26  * A UTCTime is a string representation for a UTC timestamp
     27  *
     28  * <p>Implements ASN.1 functionality.
     29  *
     30  */
     31 public class Asn1UTCTime extends Asn1Object {
     32   private static final Collection<Asn1Tag> possibleFirstTags =
     33       ImmutableList.of(Asn1Tag.UTC_TIME);
     34 
     35   private int year;
     36   private int month;
     37   private int day;
     38   private int hour;
     39   private int minute;
     40   private int second;
     41   private DecimalFormat twoDigit = new DecimalFormat("00");
     42   private DecimalFormat fourDigit = new DecimalFormat("0000");
     43 
     44   public Asn1UTCTime() {
     45   }
     46 
     47   public static Collection<Asn1Tag> getPossibleFirstTags() {
     48     return possibleFirstTags;
     49   }
     50 
     51   public void assignTo(Asn1UTCTime other) {
     52     year = other.year;
     53     month = other.month;
     54     day = other.day;
     55     hour = other.hour;
     56     minute = other.minute;
     57     second = other.second;
     58   }
     59 
     60   public int getYear() {
     61     return year;
     62   }
     63 
     64   public void setYear(int newYear) {
     65     year = newYear;
     66   }
     67 
     68   public int getMonth() {
     69     return month;
     70   }
     71 
     72   public void setMonth(int newMonth) {
     73     month = newMonth;
     74   }
     75 
     76   public int getDay() {
     77     return day;
     78   }
     79 
     80   public void setDay(int newDay) {
     81     day = newDay;
     82   }
     83 
     84   public int getHour() {
     85     return hour;
     86   }
     87 
     88   public void setHour(int newHour) {
     89     hour = newHour;
     90   }
     91 
     92   public int getMinute() {
     93     return minute;
     94   }
     95 
     96   public void setMinute(int newMinute) {
     97     minute = newMinute;
     98   }
     99 
    100   public int getSecond() {
    101     return second;
    102   }
    103 
    104   public void setSecond(int newSecond) {
    105     second = newSecond;
    106   }
    107 
    108   private Asn1IA5String encodeToIA5String() {
    109     StringBuilder builder = new StringBuilder();
    110     builder.append(twoDigit.format(year % 100));
    111     builder.append(twoDigit.format(month));
    112     builder.append(twoDigit.format(day));
    113     builder.append(twoDigit.format(hour % 100));
    114     builder.append(twoDigit.format(minute));
    115     builder.append(twoDigit.format(second));
    116     builder.append("Z");
    117     Asn1IA5String result = new Asn1IA5String();
    118     result.setMaxSize(255);
    119     result.setValue(builder.toString());
    120     return result;
    121   }
    122 
    123   public String toHumanReadableString() {
    124     StringBuilder builder = new StringBuilder();
    125     builder.append(fourDigit.format(year));
    126     builder.append('-');
    127     builder.append(twoDigit.format(month));
    128     builder.append('-');
    129     builder.append(twoDigit.format(day));
    130     builder.append(' ');
    131     builder.append(twoDigit.format(hour));
    132     builder.append(':');
    133     builder.append(twoDigit.format(minute));
    134     builder.append(':');
    135     builder.append(twoDigit.format(second));
    136     return builder.toString();
    137   }
    138 
    139   @Override Asn1Tag getDefaultTag() {
    140     return Asn1Tag.UTC_TIME;
    141   }
    142 
    143   @Override int getBerValueLength() {
    144     return encodeToIA5String().getBerValueLength();
    145   }
    146 
    147   @Override void encodeBerValue(ByteBuffer buf) {
    148     encodeToIA5String().encodeBerValue(buf);
    149   }
    150 
    151   @Override public void decodeBerValue(ByteBuffer buf) {
    152     Asn1IA5String result = new Asn1IA5String();
    153     result.setMaxSize(255);
    154     result.decodeBerValue(buf);
    155     retrieveResult(result);
    156   }
    157 
    158   @Override
    159   public Iterable<BitStream> encodePerAligned() {
    160     Asn1IA5String result = encodeToIA5String();
    161     return result.encodePerAligned();
    162   }
    163 
    164   @Override
    165   public Iterable<BitStream> encodePerUnaligned() {
    166     Asn1IA5String result = encodeToIA5String();
    167     return result.encodePerUnaligned();
    168   }
    169 
    170   // The format definition of UTCTime:
    171   //
    172   // http://www.obj-sys.com/asn1tutorial/node15.html
    173   // http://www.obj-sys.com/asn1tutorial/node14.html
    174   //
    175   // We currently only support "[YY]YYMMDDHHMM[SS[Z]]"
    176   private void retrieveResult(Asn1IA5String str) {
    177     String result = str.getValue();
    178     int yearLength = 0;
    179     // If the result has trailing 'Z', remove it.
    180     if (result.charAt(result.length() - 1) == 'Z') {
    181       result = result.substring(0, result.length() - 1);
    182     }
    183     boolean hasSecond = true;
    184     switch (result.length()) {
    185       case 10:
    186         hasSecond = false;
    187         // Fall-through
    188       case 12:
    189         yearLength = 2;
    190         break;
    191       case 14:
    192         yearLength = 4;
    193         break;
    194       default:
    195         throw new IllegalArgumentException("malformed UTCTime format: " + result);
    196     }
    197     year = Integer.parseInt(result.substring(0, yearLength));
    198     // Two-digit year's range is from 1954 to 2053.
    199     if (yearLength == 2) {
    200       if (year > 53) {
    201         year += 1900;
    202       } else {
    203         year += 2000;
    204       }
    205     }
    206     month = Integer.parseInt(result.substring(yearLength, yearLength + 2));
    207     day = Integer.parseInt(result.substring(yearLength + 2, yearLength + 4));
    208     hour = Integer.parseInt(result.substring(yearLength + 4, yearLength + 6));
    209     minute = Integer.parseInt(result.substring(yearLength + 6, yearLength + 8));
    210     if (hasSecond) {
    211       second = Integer.parseInt(result.substring(yearLength + 8, yearLength + 10));
    212     } else {
    213       second = 0;
    214     }
    215   }
    216 
    217   @Override
    218   public void decodePerAligned(BitStreamReader reader) {
    219     Asn1IA5String result = new Asn1IA5String();
    220     result.setMaxSize(255);
    221     result.decodePerAligned(reader);
    222     retrieveResult(result);
    223   }
    224 
    225   @Override
    226   public void decodePerUnaligned(BitStreamReader reader) {
    227     Asn1IA5String result = new Asn1IA5String();
    228     result.setMaxSize(255);
    229     result.decodePerUnaligned(reader);
    230     retrieveResult(result);
    231   }
    232 }
    233