• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *  * Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  *  * Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  *  * Neither the name of JSR-310 nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.threeten.bp.zone;
33 
34 import java.io.DataInput;
35 import java.io.DataOutput;
36 import java.io.Externalizable;
37 import java.io.IOException;
38 import java.io.InvalidClassException;
39 import java.io.ObjectInput;
40 import java.io.ObjectOutput;
41 import java.io.StreamCorruptedException;
42 
43 import org.threeten.bp.ZoneOffset;
44 
45 /**
46  * The shared serialization delegate for this package.
47  *
48  * <h4>Implementation notes</h4>
49  * This class is mutable and should be created once per serialization.
50  *
51  * @serial include
52  */
53 final class Ser implements Externalizable {
54 
55     /**
56      * Serialization version.
57      */
58     private static final long serialVersionUID = -8885321777449118786L;
59 
60     /** Type for StandardZoneRules. */
61     static final byte SZR = 1;
62     /** Type for ZoneOffsetTransition. */
63     static final byte ZOT = 2;
64     /** Type for ZoneOffsetTransition. */
65     static final byte ZOTRULE = 3;
66 
67     /** The type being serialized. */
68     private byte type;
69     /** The object being serialized. */
70     private Object object;
71 
72     /**
73      * Constructor for deserialization.
74      */
Ser()75     public Ser() {
76     }
77 
78     /**
79      * Creates an instance for serialization.
80      *
81      * @param type  the type
82      * @param object  the object
83      */
Ser(byte type, Object object)84     Ser(byte type, Object object) {
85         this.type = type;
86         this.object = object;
87     }
88 
89     //-----------------------------------------------------------------------
90     /**
91      * Implements the {@code Externalizable} interface to write the object.
92      *
93      * @param out  the data stream to write to, not null
94      */
writeExternal(ObjectOutput out)95     public void writeExternal(ObjectOutput out) throws IOException {
96         writeInternal(type, object, out);
97     }
98 
write(Object object, DataOutput out)99     static void write(Object object, DataOutput out) throws IOException {
100         writeInternal(SZR, object, out);
101     }
102 
writeInternal(byte type, Object object, DataOutput out)103     private static void writeInternal(byte type, Object object, DataOutput out) throws IOException {
104         out.writeByte(type);
105         switch (type) {
106             case SZR:
107                 ((StandardZoneRules) object).writeExternal(out);
108                 break;
109             case ZOT:
110                 ((ZoneOffsetTransition) object).writeExternal(out);
111                 break;
112             case ZOTRULE:
113                 ((ZoneOffsetTransitionRule) object).writeExternal(out);
114                 break;
115             default:
116                 throw new InvalidClassException("Unknown serialized type");
117         }
118     }
119 
120     //-----------------------------------------------------------------------
121     /**
122      * Implements the {@code Externalizable} interface to read the object.
123      *
124      * @param in  the data to read, not null
125      */
readExternal(ObjectInput in)126     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
127         type = in.readByte();
128         object = readInternal(type, in);
129     }
130 
read(DataInput in)131     static Object read(DataInput in) throws IOException, ClassNotFoundException {
132         byte type = in.readByte();
133         return readInternal(type, in);
134     }
135 
readInternal(byte type, DataInput in)136     private static Object readInternal(byte type, DataInput in) throws IOException, ClassNotFoundException {
137         switch (type) {
138             case SZR:
139                 return StandardZoneRules.readExternal(in);
140             case ZOT:
141                 return ZoneOffsetTransition.readExternal(in);
142             case ZOTRULE:
143                 return ZoneOffsetTransitionRule.readExternal(in);
144             default:
145                 throw new StreamCorruptedException("Unknown serialized type");
146         }
147     }
148 
149     /**
150      * Returns the object that will replace this one.
151      *
152      * @return the read object, should never be null
153      */
readResolve()154     private Object readResolve() {
155          return object;
156     }
157 
158     //-----------------------------------------------------------------------
159     /**
160      * Writes the state to the stream.
161      *
162      * @param offset  the offset, not null
163      * @param out  the output stream, not null
164      * @throws IOException if an error occurs
165      */
writeOffset(ZoneOffset offset, DataOutput out)166     static void writeOffset(ZoneOffset offset, DataOutput out) throws IOException {
167         final int offsetSecs = offset.getTotalSeconds();
168         int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127;  // compress to -72 to +72
169         out.writeByte(offsetByte);
170         if (offsetByte == 127) {
171             out.writeInt(offsetSecs);
172         }
173     }
174 
175     /**
176      * Reads the state from the stream.
177      *
178      * @param in  the input stream, not null
179      * @return the created object, not null
180      * @throws IOException if an error occurs
181      */
readOffset(DataInput in)182     static ZoneOffset readOffset(DataInput in) throws IOException {
183         int offsetByte = in.readByte();
184         return (offsetByte == 127 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(offsetByte * 900));
185     }
186 
187     //-----------------------------------------------------------------------
188     /**
189      * Writes the state to the stream.
190      *
191      * @param epochSec  the epoch seconds, not null
192      * @param out  the output stream, not null
193      * @throws IOException if an error occurs
194      */
writeEpochSec(long epochSec, DataOutput out)195     static void writeEpochSec(long epochSec, DataOutput out) throws IOException {
196         if (epochSec >= -4575744000L && epochSec < 10413792000L && epochSec % 900 == 0) {  // quarter hours between 1825 and 2300
197             int store = (int) ((epochSec + 4575744000L) / 900);
198             out.writeByte((store >>> 16) & 255);
199             out.writeByte((store >>> 8) & 255);
200             out.writeByte(store & 255);
201         } else {
202             out.writeByte(255);
203             out.writeLong(epochSec);
204         }
205     }
206 
207     /**
208      * Reads the state from the stream.
209      *
210      * @param in  the input stream, not null
211      * @return the epoch seconds, not null
212      * @throws IOException if an error occurs
213      */
readEpochSec(DataInput in)214     static long readEpochSec(DataInput in) throws IOException {
215         int hiByte = in.readByte() & 255;
216         if (hiByte == 255) {
217             return in.readLong();
218         } else {
219             int midByte = in.readByte() & 255;
220             int loByte = in.readByte() & 255;
221             long tot = ((hiByte << 16) + (midByte << 8) + loByte);
222             return (tot * 900) - 4575744000L;
223         }
224     }
225 
226 }
227