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