~ubuntu-branches/ubuntu/karmic/libxerces2-java/karmic

« back to all changes in this revision

Viewing changes to src/org/apache/xerces/impl/dv/xs/DurationDV.java

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2006-12-04 17:37:55 UTC
  • mfrom: (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20061204173755-hb6ybrrrk097zhx7
Tags: 2.8.1-1ubuntu1
* Merge with Debian unstable; remaining changes:
  - Build -gcj package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * The Apache Software License, Version 1.1
3
 
 *
4
 
 *
5
 
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
6
 
 * reserved.
7
 
 *
8
 
 * Redistribution and use in source and binary forms, with or without
9
 
 * modification, are permitted provided that the following conditions
10
 
 * are met:
11
 
 *
12
 
 * 1. Redistributions of source code must retain the above copyright
13
 
 *    notice, this list of conditions and the following disclaimer.
14
 
 *
15
 
 * 2. Redistributions in binary form must reproduce the above copyright
16
 
 *    notice, this list of conditions and the following disclaimer in
17
 
 *    the documentation and/or other materials provided with the
18
 
 *    distribution.
19
 
 *
20
 
 * 3. The end-user documentation included with the redistribution,
21
 
 *    if any, must include the following acknowledgment:
22
 
 *       "This product includes software developed by the
23
 
 *        Apache Software Foundation (http://www.apache.org/)."
24
 
 *    Alternately, this acknowledgment may appear in the software itself,
25
 
 *    if and wherever such third-party acknowledgments normally appear.
26
 
 *
27
 
 * 4. The names "Xerces" and "Apache Software Foundation" must
28
 
 *    not be used to endorse or promote products derived from this
29
 
 *    software without prior written permission. For written
30
 
 *    permission, please contact apache@apache.org.
31
 
 *
32
 
 * 5. Products derived from this software may not be called "Apache",
33
 
 *    nor may "Apache" appear in their name, without prior written
34
 
 *    permission of the Apache Software Foundation.
35
 
 *
36
 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37
 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38
 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39
 
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40
 
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41
 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42
 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43
 
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44
 
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45
 
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46
 
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47
 
 * SUCH DAMAGE.
48
 
 * ====================================================================
49
 
 *
50
 
 * This software consists of voluntary contributions made by many
51
 
 * individuals on behalf of the Apache Software Foundation and was
52
 
 * originally based on software copyright (c) 2001, International
53
 
 * Business Machines, Inc., http://www.apache.org.  For more
54
 
 * information on the Apache Software Foundation, please see
55
 
 * <http://www.apache.org/>.
 
2
 * Copyright 1999-2002,2004,2005 The Apache Software Foundation.
 
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.
56
15
 */
57
16
 
58
17
package org.apache.xerces.impl.dv.xs;
59
18
 
 
19
import java.math.BigDecimal;
 
20
import java.math.BigInteger;
 
21
 
 
22
import javax.xml.datatype.DatatypeConstants;
 
23
import javax.xml.datatype.Duration;
 
24
 
60
25
import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
61
26
import org.apache.xerces.impl.dv.ValidationContext;
62
27
 
63
28
/**
64
 
 * Validator for <duration> datatype (W3C Schema Datatypes)
 
29
 * Validator for &lt;duration&gt; datatype (W3C Schema Datatypes)
 
30
 *
 
31
 * @xerces.internal 
65
32
 *
66
33
 * @author Elena Litani
67
34
 * @author Gopal Sharma, SUN Microsystem Inc.
68
 
 * @version $Id: DurationDV.java,v 1.8 2003/12/11 15:08:25 sandygao Exp $
 
35
 * @version $Id: DurationDV.java 320310 2005-05-06 15:31:15Z ankitp $
69
36
 */
70
37
public class DurationDV extends AbstractDateTimeDV {
71
38
 
 
39
        public static final int DURATION_TYPE = 0;
 
40
        public static final int YEARMONTHDURATION_TYPE = 1;
 
41
        public static final int DAYTIMEDURATION_TYPE = 2;
72
42
    // order-relation on duration is a partial order. The dates below are used to
73
43
    // for comparison of 2 durations, based on the fact that
74
44
    // duration x and y is x<=y iff s+x<=s+y
75
45
    // see 3.2.6 duration W3C schema datatype specs
76
46
    //
77
47
    // the dates are in format: {CCYY,MM,DD, H, S, M, MS, timezone}
78
 
    private final static int[][] DATETIMES= {
79
 
        {1696, 9, 1, 0, 0, 0, 0, 'Z'},
80
 
        {1697, 2, 1, 0, 0, 0, 0, 'Z'},
81
 
        {1903, 3, 1, 0, 0, 0, 0, 'Z'},
82
 
        {1903, 7, 1, 0, 0, 0, 0, 'Z'}};
 
48
    private final static DateTimeData[] DATETIMES= {
 
49
        new DateTimeData(1696, 9, 1, 0, 0, 0, 'Z', null, true, null),
 
50
        new DateTimeData(1697, 2, 1, 0, 0, 0, 'Z', null, true, null),
 
51
        new DateTimeData(1903, 3, 1, 0, 0, 0, 'Z', null, true, null),
 
52
        new DateTimeData(1903, 7, 1, 0, 0, 0, 'Z', null, true, null)};
83
53
 
84
54
    public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException{
85
55
        try{
86
 
            return new DateTimeData(parse(content), this);
 
56
            return parse(content, DURATION_TYPE);
87
57
        } catch (Exception ex) {
88
58
            throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "duration"});
89
59
        }
93
63
     * Parses, validates and computes normalized version of duration object
94
64
     *
95
65
     * @param str    The lexical representation of duration object PnYn MnDTnH nMnS
96
 
     * @param date   uninitialized date object
 
66
     * @param durationType
97
67
     * @return normalized date representation
98
68
     * @exception SchemaDateTimeException Invalid lexical representation
99
69
     */
100
 
    protected int[] parse(String str) throws SchemaDateTimeException{
 
70
    protected DateTimeData parse(String str, int durationType) throws SchemaDateTimeException{
101
71
        int len = str.length();
102
 
        int[] date=new int[TOTAL_SIZE];
103
 
 
 
72
        DateTimeData date= new DateTimeData(str, this);
 
73
        
104
74
        int start = 0;
105
75
        char c=str.charAt(start++);
106
76
        if ( c!='P' && c!='-' ) {
107
77
            throw new SchemaDateTimeException();
108
78
        }
109
79
        else {
110
 
            date[utc]=(c=='-')?'-':0;
 
80
            date.utc=(c=='-')?'-':0;
111
81
            if ( c=='-' && str.charAt(start++)!='P' ) {
112
82
                throw new SchemaDateTimeException();
113
83
            }
114
84
        }
115
 
 
 
85
        
116
86
        int negate = 1;
117
87
        //negative duration
118
 
        if ( date[utc]=='-' ) {
 
88
        if ( date.utc=='-' ) {
119
89
            negate = -1;
120
 
 
 
90
            
121
91
        }
122
92
        //at least one number and designator must be seen after P
123
93
        boolean designator = false;
124
 
 
 
94
        
125
95
        int endDate = indexOf (str, start, len, 'T');
126
96
        if ( endDate == -1 ) {
127
97
            endDate = len;
128
98
        }
 
99
        else if (durationType == YEARMONTHDURATION_TYPE) {
 
100
            throw new SchemaDateTimeException();
 
101
        }
 
102
        
129
103
        //find 'Y'
130
104
        int end = indexOf (str, start, endDate, 'Y');
131
105
        if ( end!=-1 ) {
 
106
            
 
107
            if (durationType == DAYTIMEDURATION_TYPE) {
 
108
                throw new SchemaDateTimeException();
 
109
            }
 
110
            
132
111
            //scan year
133
 
            date[CY]=negate * parseInt(str,start,end);
 
112
            date.year=negate * parseInt(str,start,end);
134
113
            start = end+1;
135
114
            designator = true;
136
115
        }
137
 
 
 
116
        
138
117
        end = indexOf (str, start, endDate, 'M');
139
118
        if ( end!=-1 ) {
 
119
            
 
120
            if (durationType == DAYTIMEDURATION_TYPE) {
 
121
                throw new SchemaDateTimeException();
 
122
            }
 
123
            
140
124
            //scan month
141
 
            date[M]=negate * parseInt(str,start,end);
 
125
            date.month=negate * parseInt(str,start,end);
142
126
            start = end+1;
143
127
            designator = true;
144
128
        }
145
 
 
 
129
        
146
130
        end = indexOf (str, start, endDate, 'D');
147
131
        if ( end!=-1 ) {
 
132
            
 
133
            if(durationType == YEARMONTHDURATION_TYPE) {
 
134
                throw new SchemaDateTimeException();
 
135
            }
 
136
            
148
137
            //scan day
149
 
            date[D]=negate * parseInt(str,start,end);
 
138
            date.day=negate * parseInt(str,start,end);
150
139
            start = end+1;
151
140
            designator = true;
152
141
        }
153
 
 
 
142
        
154
143
        if ( len == endDate && start!=len ) {
155
144
            throw new SchemaDateTimeException();
156
145
        }
157
146
        if ( len !=endDate ) {
158
 
 
 
147
            
159
148
            //scan hours, minutes, seconds
160
149
            //REVISIT: can any item include a decimal fraction or only seconds?
161
150
            //
162
 
 
 
151
            
163
152
            end = indexOf (str, ++start, len, 'H');
164
153
            if ( end!=-1 ) {
165
154
                //scan hours
166
 
                date[h]=negate * parseInt(str,start,end);
 
155
                date.hour=negate * parseInt(str,start,end);
167
156
                start=end+1;
168
157
                designator = true;
169
158
            }
170
 
 
 
159
            
171
160
            end = indexOf (str, start, len, 'M');
172
161
            if ( end!=-1 ) {
173
162
                //scan min
174
 
                date[m]=negate * parseInt(str,start,end);
 
163
                date.minute=negate * parseInt(str,start,end);
175
164
                start=end+1;
176
165
                designator = true;
177
166
            }
178
 
 
 
167
            
179
168
            end = indexOf (str, start, len, 'S');
180
169
            if ( end!=-1 ) {
181
170
                //scan seconds
182
 
                int mlsec = indexOf (str, start, end, '.');
183
 
                if ( mlsec >0 ) {
184
 
                    date[s]  = negate * parseInt (str, start, mlsec);
185
 
                    date[ms] = negate * parseInt (str, mlsec+1, end);
186
 
                }
187
 
                else {
188
 
                    date[s]=negate * parseInt(str, start,end);
189
 
                }
 
171
                date.second = negate * parseSecond(str, start, end);
190
172
                start=end+1;
191
173
                designator = true;
192
174
            }
196
178
                throw new SchemaDateTimeException();
197
179
            }
198
180
        }
199
 
 
 
181
        
200
182
        if ( !designator ) {
201
183
            throw new SchemaDateTimeException();
202
184
        }
203
 
 
 
185
        
204
186
        return date;
205
187
    }
206
188
 
211
193
     * @param date2  Unnormalized duration
212
194
     * @param strict (min/max)Exclusive strict == true ( LESS_THAN ) or ( GREATER_THAN )
213
195
     *               (min/max)Inclusive strict == false (LESS_EQUAL) or (GREATER_EQUAL)
214
 
     * @return INDETERMINATE if the order relationship between date1 and date2 is indeterminate. 
215
 
     * EQUAL if the order relation between date1 and date2 is EQUAL.  
 
196
     * @return INDETERMINATE if the order relationship between date1 and date2 is indeterminate.
 
197
     * EQUAL if the order relation between date1 and date2 is EQUAL.
216
198
     * If the strict parameter is true, return LESS_THAN if date1 is less than date2 and
217
 
     * return GREATER_THAN if date1 is greater than date2. 
 
199
     * return GREATER_THAN if date1 is greater than date2.
218
200
     * If the strict parameter is false, return LESS_THAN if date1 is less than OR equal to date2 and
219
 
     * return GREATER_THAN if date1 is greater than OR equal to date2 
 
201
     * return GREATER_THAN if date1 is greater than OR equal to date2
220
202
     */
221
 
    protected  short compareDates(int[] date1, int[] date2, boolean strict) {
 
203
    protected  short compareDates(DateTimeData date1, DateTimeData date2, boolean strict) {
222
204
 
223
205
        //REVISIT: this is unoptimazed vs of comparing 2 durations
224
206
        //         Algorithm is described in 3.2.6.2 W3C Schema Datatype specs
226
208
 
227
209
        //add constA to both durations
228
210
        short resultA, resultB= INDETERMINATE;
229
 
 
230
211
        //try and see if the objects are equal
231
212
        resultA = compareOrder (date1, date2);
232
213
        if ( resultA == 0 ) {
233
214
            return 0;
234
215
        }
235
216
 
236
 
        int[][] result = new int[2][TOTAL_SIZE];
 
217
        DateTimeData[] result = new DateTimeData[2];
 
218
        result[0] = new DateTimeData(null, this);
 
219
        result[1] = new DateTimeData(null, this);
237
220
 
238
221
        //long comparison algorithm is required
239
 
        int[] tempA = addDuration (date1, DATETIMES[0], result[0]);
240
 
        int[] tempB = addDuration (date2, DATETIMES[0], result[1]);
 
222
        DateTimeData tempA = addDuration (date1, DATETIMES[0], result[0]);
 
223
        DateTimeData tempB = addDuration (date2, DATETIMES[0], result[1]);
241
224
        resultA =  compareOrder(tempA, tempB);
242
225
        if ( resultA == INDETERMINATE ) {
243
226
            return INDETERMINATE;
286
269
        return resultA;
287
270
    }
288
271
 
289
 
    private int[] addDuration(int[] date, int[] addto, int[] duration) {
 
272
    private DateTimeData addDuration(DateTimeData date, DateTimeData addto, DateTimeData duration) {
290
273
 
291
274
        //REVISIT: some code could be shared between normalize() and this method,
292
275
        //         however is it worth moving it? The structures are different...
294
277
 
295
278
        resetDateObj(duration);
296
279
        //add months (may be modified additionaly below)
297
 
        int temp = addto[M] + date[M];
298
 
        duration[M] = modulo (temp, 1, 13);
 
280
        int temp = addto.month + date.month;
 
281
        duration.month = modulo (temp, 1, 13);
299
282
        int carry = fQuotient (temp, 1, 13);
300
283
 
301
284
        //add years (may be modified additionaly below)
302
 
        duration[CY]=addto[CY] + date[CY] + carry;
303
 
        
 
285
        duration.year=addto.year + date.year + carry;
 
286
 
304
287
        //add seconds
305
 
        temp = addto[s] + date[s];
306
 
        carry = fQuotient (temp, 60);
307
 
        duration[s] =  mod(temp, 60, carry);
 
288
        double dtemp = addto.second + date.second;
 
289
        carry = (int)Math.floor(dtemp/60);
 
290
        duration.second = dtemp - carry*60;
308
291
 
309
292
        //add minutes
310
 
        temp = addto[m] +date[m] + carry;
 
293
        temp = addto.minute +date.minute + carry;
311
294
        carry = fQuotient (temp, 60);
312
 
        duration[m]= mod(temp, 60, carry);
 
295
        duration.minute= mod(temp, 60, carry);
313
296
 
314
297
        //add hours
315
 
        temp = addto[h] + date[h] + carry;
 
298
        temp = addto.hour + date.hour + carry;
316
299
        carry = fQuotient(temp, 24);
317
 
        duration[h] = mod(temp, 24, carry);
318
 
 
319
 
 
320
 
        duration[D]=addto[D] + date[D] + carry;
 
300
        duration.hour = mod(temp, 24, carry);
 
301
 
 
302
 
 
303
        duration.day=addto.day + date.day + carry;
321
304
 
322
305
        while ( true ) {
323
306
 
324
 
            temp=maxDayInMonthFor(duration[CY], duration[M]);
325
 
            if ( duration[D] < 1 ) { //original duration was negative
326
 
                duration[D] = duration[D] + maxDayInMonthFor(duration[CY], duration[M]-1);
 
307
            temp=maxDayInMonthFor(duration.year, duration.month);
 
308
            if ( duration.day < 1 ) { //original duration was negative
 
309
                duration.day = duration.day + maxDayInMonthFor(duration.year, duration.month-1);
327
310
                carry=-1;
328
311
            }
329
 
            else if ( duration[D] > temp ) {
330
 
                duration[D] = duration[D] - temp;
 
312
            else if ( duration.day > temp ) {
 
313
                duration.day = duration.day - temp;
331
314
                carry=1;
332
315
            }
333
316
            else {
334
317
                break;
335
318
            }
336
 
            temp = duration[M]+carry;
337
 
            duration[M] = modulo(temp, 1, 13);
338
 
            duration[CY] = duration[CY]+fQuotient(temp, 1, 13);
 
319
            temp = duration.month+carry;
 
320
            duration.month = modulo(temp, 1, 13);
 
321
            duration.year = duration.year+fQuotient(temp, 1, 13);
339
322
        }
340
323
 
341
 
        duration[utc]='Z';
 
324
        duration.utc='Z';
342
325
        return duration;
343
326
    }
344
327
 
345
 
    protected String dateToString(int[] date) {
 
328
    protected double parseSecond(String buffer, int start, int end)
 
329
        throws NumberFormatException {
 
330
        int dot = -1;
 
331
        for (int i = start; i < end; i++) {
 
332
            char ch = buffer.charAt(i);
 
333
            if (ch == '.')
 
334
                dot = i;
 
335
            else if (ch > '9' || ch < '0')
 
336
                throw new NumberFormatException("'" + buffer + "' has wrong format");
 
337
        }
 
338
        if (dot+1 == end) {
 
339
            throw new NumberFormatException("'" + buffer + "' has wrong format");
 
340
        }
 
341
        return Double.parseDouble(buffer.substring(start, end));
 
342
    }
 
343
 
 
344
    protected String dateToString(DateTimeData date) {
346
345
        StringBuffer message = new StringBuffer(30);
347
 
        int negate = 1;
348
 
        if ( date[CY]<0 ) {
 
346
        if ( date.year<0 || date.month<0 || date.day<0
 
347
                || date.hour<0 || date.minute<0 || date.second<0) {
349
348
            message.append('-');
350
 
            negate=-1;
351
349
        }
352
350
        message.append('P');
353
 
        message.append(negate * date[CY]);
 
351
        message.append((date.year < 0?-1:1) * date.year);
354
352
        message.append('Y');
355
 
        message.append(negate * date[M]);
 
353
        message.append((date.month < 0?-1:1) * date.month);
356
354
        message.append('M');
357
 
        message.append(negate * date[D]);
 
355
        message.append((date.day < 0?-1:1) * date.day);
358
356
        message.append('D');
359
357
        message.append('T');
360
 
        message.append(negate * date[h]);
 
358
        message.append((date.hour < 0?-1:1) * date.hour);
361
359
        message.append('H');
362
 
        message.append(negate * date[m]);
 
360
        message.append((date.minute < 0?-1:1) * date.minute);
363
361
        message.append('M');
364
 
        message.append(negate * date[s]);
365
 
        message.append('.');
366
 
        message.append(negate * date[ms]);
 
362
        message.append((date.second < 0?-1:1) * date.second);
367
363
        message.append('S');
368
364
 
369
365
        return message.toString();
370
366
    }
 
367
    
 
368
    protected Duration getDuration(DateTimeData date) {
 
369
        int sign = 1;
 
370
        if ( date.year<0 || date.month<0 || date.day<0
 
371
                || date.hour<0 || date.minute<0 || date.second<0) {
 
372
            sign = -1;
 
373
        }
 
374
        return factory.newDuration(sign == 1, 
 
375
                date.year != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.year):null, 
 
376
                date.month != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.month):null, 
 
377
                date.day != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.day):null, 
 
378
                date.hour != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.hour):null, 
 
379
                date.minute != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.minute):null, 
 
380
                date.second != DatatypeConstants.FIELD_UNDEFINED?new BigDecimal(String.valueOf(sign*date.second)):null);
 
381
    }
371
382
}