1<?php
2/*
3 * Copyright 2008-2010 GuardTime AS
4 *
5 * This file is part of the GuardTime PHP SDK.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *     http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20/**
21 * @package asn1
22 * @subpackage tsp
23 */
24
25/**
26 * TSP Accuracy implementation.
27 *
28 * <pre>
29 * Accuracy ::= SEQUENCE {
30 *  seconds        INTEGER              OPTIONAL,
31 *  millis     [0] INTEGER  (1..999)    OPTIONAL,
32 *  micros     [1] INTEGER  (1..999)    OPTIONAL
33 * }
34 * </pre>
35 *
36 * @package asn1
37 * @subpackage tsp
38 *
39 * @link http://tools.ietf.org/html/rfc3161#section-2.4.2 RFC 3161: Time-Stamp Protocol
40 */
41class TSPAccuracy implements ASN1DEREncodable {
42
43    private $seconds;
44    private $millis;
45    private $micros;
46
47    /**
48     * Constructs a new isntance of TSPAccuracy.
49     */
50    public function __construct() {
51    }
52
53    /**
54     * Decodes the given ASN1Sequence as TSPAccuracy.
55     *
56     * @throws GTException
57     * @param  ASN1Sequence $object TSPAccuracy encoded as ASN1Sequence
58     * @return void
59     */
60    public function decode($object) {
61
62        if (!$object instanceof ASN1Sequence) {
63            throw new GTException("Expecting an ASN1Sequence");
64        }
65
66        if ($object->getObjectCount() < 1 || $object->getObjectCount() > 3) {
67            throw new GTException("Invalid number of elements in sequence");
68        }
69
70        for ($i = 0; $i < $object->getObjectCount(); $i++) {
71
72            $item = $object->getObjectAt($i);
73
74            if ($item instanceof ASN1Integer) {
75
76                if (!is_null($this->seconds)) {
77                    throw new GTException("Unexpected ASN1Integer: {$item->getValue()}");
78                }
79
80                if ($i != 0) {
81                    throw new GTException("Unexpected ASN1Integer: {$item->getValue()}");
82                }
83
84                $this->seconds = $item->getValue();
85
86            } else if ($item instanceof ASN1Tag) {
87
88                switch ($item->getTagValue()) {
89
90                    case 0:
91
92                        // millis
93
94                        if (!is_null($this->millis)) {
95                            throw new GTException("Unexpected TAG value: 0");
96                        }
97
98                        $millis = $item->getObjectAs(ASN1_TAG_INTEGER);
99
100                        if (!$millis instanceof ASN1Integer) {
101                            throw new GTException("Expecting an ASN1Integer");
102                        }
103
104                        if ((int) $millis->getValue() < 1) {
105                            throw new GTException("Invalid value for millis: {$millis->getValue()}");
106                        }
107
108                        if ((int) $millis->getValue() > 999) {
109                            throw new GTException("Invalid value for millis: {$millis->getValue()}");
110                        }
111
112                        $this->millis = $millis->getValue();
113
114                        break;
115
116                    case 1:
117
118                        // micros
119
120                        if (!is_null($this->micros)) {
121                            throw new GTException("Unexpected TAG value: 1");
122                        }
123
124                        $micros = $item->getObjectAs(ASN1_TAG_INTEGER);
125
126                        if (!$micros instanceof ASN1Integer) {
127                            throw new GTException("Expecting an ASN1Integer");
128                        }
129
130                        if ((int) $micros->getValue() < 1) {
131                            throw new GTException("Invalid value for micros: {$micros->getValue()}");
132                        }
133
134                        if ((int) $micros->getValue() > 999) {
135                            throw new GTException("Invalid value for micros: {$micros->getValue()}");
136                        }
137
138                        $this->micros = $micros->getValue();
139
140                    default:
141                        throw new GTException("Unexpected TAG value: {$item->getTagValue()}");
142
143                }
144
145            } else {
146                throw new GTException("Unexpected ASN1 type: " . get_class($item));
147
148            }
149
150        }
151
152    }
153
154    /**
155     * Encodes this TSPAccuracy using DER.
156     *
157     * @return array byte array that contains the DER encoding of this TSPAccuracy
158     */
159    public function encodeDER() {
160
161        $sequence = new ASN1Sequence();
162
163        if ($this->seconds != null) {
164            $sequence->add(new ASN1Integer($this->seconds));
165        }
166
167        if ($this->millis != null) {
168            $tag = new ASN1Tag();
169            $tag->setExplicit(true);
170            $tag->setTagClass(ASN1_TAG_CONTEXT);
171            $tag->setTagType(ASN1_TAG_CONSTRUCTED);
172            $tag->setTagValue(0);
173            $tag->setObject(new ASN1Integer($this->millis));
174
175            $sequence->add($tag);
176        }
177
178        if ($this->micros != null) {
179            $tag = new ASN1Tag();
180            $tag->setExplicit(true);
181            $tag->setTagClass(ASN1_TAG_CONTEXT);
182            $tag->setTagType(ASN1_TAG_CONSTRUCTED);
183            $tag->setTagValue(1);
184            $tag->setObject(new ASN1Integer($this->micros));
185
186            $sequence->add($tag);
187        }
188
189        return $sequence->encodeDER();
190
191    }
192
193    /**
194     * Gets this TSPAccuracy formatted as string.
195     *
196     * @return string formatted TSPAccuracy
197     */
198    public function getFormatted() {
199
200        $accuracy = new GTBigInteger(0);
201
202        if (!is_null($this->seconds)) {
203            $accuracy = $accuracy->add(new GTBigInteger($this->seconds));
204        }
205
206        $accuracy = $accuracy->mul(new GTBigInteger(1000));
207
208        if (!is_null($this->millis)) {
209            $accuracy = $accuracy->add(new GTBigInteger($this->millis));
210        }
211
212        $accuracy = $accuracy->mul(new GTBigInteger(1000));
213
214        if (!is_null($this->micros)) {
215            $accuracy = $accuracy->add(new GTBigInteger($this->micros));
216        }
217
218        $zero = new GTBigInteger(0);
219
220        if ($accuracy->mod(1000000)->comp($zero) == 0) {
221            return "{$accuracy->div(new GTBigInteger(1000000))->getValue()}s";
222
223        } else if ($accuracy->mod(1000)->comp($zero) == 0) {
224            return "{$accuracy->div(new GTBigInteger(1000))->getValue()}ms";
225
226        } else {
227            return "{$accuracy->getValue()}us";
228
229        }
230    }
231
232}
233
234?>
235