1 7 8 package java.io; 9 10 import java.io.ObjectStreamClass.WeakClassKey ; 11 import java.lang.ref.ReferenceQueue ; 12 import java.security.AccessController ; 13 import java.security.PrivilegedAction ; 14 import java.util.Arrays ; 15 import java.util.concurrent.ConcurrentHashMap ; 16 import java.util.concurrent.ConcurrentMap ; 17 import static java.io.ObjectStreamClass.processQueue ; 18 19 139 public class ObjectOutputStream 140 extends OutputStream implements ObjectOutput , ObjectStreamConstants 141 { 142 private static class Caches { 143 144 static final ConcurrentMap <WeakClassKey,Boolean > subclassAudits = 145 new ConcurrentHashMap <WeakClassKey,Boolean >(); 146 147 148 static final ReferenceQueue <Class <?>> subclassAuditsQueue = 149 new ReferenceQueue <Class <?>>(); 150 } 151 152 153 private final BlockDataOutputStream bout; 154 155 private final HandleTable handles; 156 157 private final ReplaceTable subs; 158 159 private int protocol = PROTOCOL_VERSION_2; 160 161 private int depth; 162 163 164 private byte[] primVals; 165 166 167 private final boolean enableOverride; 168 169 private boolean enableReplace; 170 171 173 private Object curObj; 174 175 private ObjectStreamClass curDesc; 176 177 private PutFieldImpl curPut; 178 179 201 public ObjectOutputStream(OutputStream out) throws IOException { 202 verifySubclass(); 203 bout = new BlockDataOutputStream(out); 204 handles = new HandleTable(10, (float) 3.00); 205 subs = new ReplaceTable(10, (float) 3.00); 206 enableOverride = false; 207 writeStreamHeader(); 208 bout.setBlockDataMode(true); 209 } 210 211 227 protected ObjectOutputStream() throws IOException , SecurityException { 228 SecurityManager sm = System.getSecurityManager(); 229 if (sm != null) { 230 sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); 231 } 232 bout = null; 233 handles = null; 234 subs = null; 235 enableOverride = true; 236 } 237 238 258 public void useProtocolVersion(int version) throws IOException { 259 if (handles.size() != 0) { 260 throw new IllegalStateException ("stream non-empty"); 262 } 263 switch (version) { 264 case PROTOCOL_VERSION_1: 265 case PROTOCOL_VERSION_2: 266 protocol = version; 267 break; 268 269 default: 270 throw new IllegalArgumentException ( 271 "unknown version: " + version); 272 } 273 } 274 275 296 public final void writeObject(Object obj) throws IOException { 297 if (enableOverride) { 298 writeObjectOverride(obj); 299 return; 300 } 301 try { 302 writeObject0(obj, false); 303 } catch (IOException ex) { 304 if (depth == 0) { 305 writeFatalException(ex); 306 } 307 throw ex; 308 } 309 } 310 311 325 protected void writeObjectOverride(Object obj) throws IOException { 326 } 327 328 366 public void writeUnshared(Object obj) throws IOException { 367 try { 368 writeObject0(obj, true); 369 } catch (IOException ex) { 370 if (depth == 0) { 371 writeFatalException(ex); 372 } 373 throw ex; 374 } 375 } 376 377 386 public void defaultWriteObject() throws IOException { 387 if (curObj == null || curDesc == null) { 388 throw new NotActiveException ("not in call to writeObject"); 389 } 390 bout.setBlockDataMode(false); 391 defaultWriteFields(curObj, curDesc); 392 bout.setBlockDataMode(true); 393 } 394 395 405 public ObjectOutputStream.PutField putFields() throws IOException { 406 if (curPut == null) { 407 if (curObj == null || curDesc == null) { 408 throw new NotActiveException ("not in call to writeObject"); 409 } 410 curPut = new PutFieldImpl(curDesc); 411 } 412 return curPut; 413 } 414 415 424 public void writeFields() throws IOException { 425 if (curPut == null) { 426 throw new NotActiveException ("no current PutField object"); 427 } 428 bout.setBlockDataMode(false); 429 curPut.writeFields(); 430 bout.setBlockDataMode(true); 431 } 432 433 443 public void reset() throws IOException { 444 if (depth != 0) { 445 throw new IOException ("stream active"); 446 } 447 bout.setBlockDataMode(false); 448 bout.writeByte(TC_RESET); 449 clear(); 450 bout.setBlockDataMode(true); 451 } 452 453 469 protected void annotateClass(Class <?> cl) throws IOException { 470 } 471 472 493 protected void annotateProxyClass(Class <?> cl) throws IOException { 494 } 495 496 534 protected Object replaceObject(Object obj) throws IOException { 535 return obj; 536 } 537 538 558 protected boolean enableReplaceObject(boolean enable) 559 throws SecurityException 560 { 561 if (enable == enableReplace) { 562 return enable; 563 } 564 if (enable) { 565 SecurityManager sm = System.getSecurityManager(); 566 if (sm != null) { 567 sm.checkPermission(SUBSTITUTION_PERMISSION); 568 } 569 } 570 enableReplace = enable; 571 return !enableReplace; 572 } 573 574 582 protected void writeStreamHeader() throws IOException { 583 bout.writeShort(STREAM_MAGIC); 584 bout.writeShort(STREAM_VERSION); 585 } 586 587 612 protected void writeClassDescriptor(ObjectStreamClass desc) 613 throws IOException 614 { 615 desc.writeNonProxy(this); 616 } 617 618 625 public void write(int val) throws IOException { 626 bout.write(val); 627 } 628 629 636 public void write(byte[] buf) throws IOException { 637 bout.write(buf, 0, buf.length, false); 638 } 639 640 648 public void write(byte[] buf, int off, int len) throws IOException { 649 if (buf == null) { 650 throw new NullPointerException (); 651 } 652 int endoff = off + len; 653 if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) { 654 throw new IndexOutOfBoundsException (); 655 } 656 bout.write(buf, off, len, false); 657 } 658 659 665 public void flush() throws IOException { 666 bout.flush(); 667 } 668 669 676 protected void drain() throws IOException { 677 bout.drain(); 678 } 679 680 686 public void close() throws IOException { 687 flush(); 688 clear(); 689 bout.close(); 690 } 691 692 699 public void writeBoolean(boolean val) throws IOException { 700 bout.writeBoolean(val); 701 } 702 703 710 public void writeByte(int val) throws IOException { 711 bout.writeByte(val); 712 } 713 714 721 public void writeShort(int val) throws IOException { 722 bout.writeShort(val); 723 } 724 725 732 public void writeChar(int val) throws IOException { 733 bout.writeChar(val); 734 } 735 736 743 public void writeInt(int val) throws IOException { 744 bout.writeInt(val); 745 } 746 747 754 public void writeLong(long val) throws IOException { 755 bout.writeLong(val); 756 } 757 758 765 public void writeFloat(float val) throws IOException { 766 bout.writeFloat(val); 767 } 768 769 776 public void writeDouble(double val) throws IOException { 777 bout.writeDouble(val); 778 } 779 780 787 public void writeBytes(String str) throws IOException { 788 bout.writeBytes(str); 789 } 790 791 798 public void writeChars(String str) throws IOException { 799 bout.writeChars(str); 800 } 801 802 815 public void writeUTF(String str) throws IOException { 816 bout.writeUTF(str); 817 } 818 819 825 public static abstract class PutField { 826 827 833 public abstract void put(String name, boolean val); 834 835 841 public abstract void put(String name, byte val); 842 843 849 public abstract void put(String name, char val); 850 851 857 public abstract void put(String name, short val); 858 859 865 public abstract void put(String name, int val); 866 867 873 public abstract void put(String name, long val); 874 875 881 public abstract void put(String name, float val); 882 883 889 public abstract void put(String name, double val); 890 891 897 public abstract void put(String name, Object val); 898 899 912 @Deprecated 913 public abstract void write(ObjectOutput out) throws IOException ; 914 } 915 916 917 920 int getProtocolVersion() { 921 return protocol; 922 } 923 924 928 void writeTypeString(String str) throws IOException { 929 int handle; 930 if (str == null) { 931 writeNull(); 932 } else if ((handle = handles.lookup(str)) != -1) { 933 writeHandle(handle); 934 } else { 935 writeString(str, false); 936 } 937 } 938 939 945 private void verifySubclass() { 946 Class cl = getClass(); 947 processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); 948 WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); 949 Boolean result = Caches.subclassAudits.get(key); 950 if (result == null) { 951 result = Boolean.valueOf(auditSubclass(cl)); 952 Caches.subclassAudits.putIfAbsent(key, result); 953 } 954 if (result.booleanValue()) { 955 return; 956 } 957 SecurityManager sm = System.getSecurityManager(); 958 if (sm != null) { 959 sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); 960 } 961 } 962 963 968 private static boolean auditSubclass(final Class subcl) { 969 Boolean result = (Boolean ) AccessController.doPrivileged( 970 new PrivilegedAction () { 971 public Object run() { 972 for (Class cl = subcl; 973 cl != ObjectOutputStream .class; 974 cl = cl.getSuperclass()) 975 { 976 try { 977 cl.getDeclaredMethod( 978 "writeUnshared", new Class [] { Object .class }); 979 return Boolean.FALSE; 980 } catch (NoSuchMethodException ex) { 981 } 982 try { 983 cl.getDeclaredMethod("putFields", new Class [0]); 984 return Boolean.FALSE; 985 } catch (NoSuchMethodException ex) { 986 } 987 } 988 return Boolean.TRUE; 989 } 990 } 991 ); 992 return result.booleanValue(); 993 } 994 995 998 private void clear() { 999 subs.clear(); 1000 handles.clear(); 1001 } 1002 1003 1006 private void writeObject0(Object obj, boolean unshared) 1007 throws IOException 1008 { 1009 boolean oldMode = bout.setBlockDataMode(false); 1010 depth++; 1011 try { 1012 int h; 1014 if ((obj = subs.lookup(obj)) == null) { 1015 writeNull(); 1016 return; 1017 } else if (!unshared && (h = handles.lookup(obj)) != -1) { 1018 writeHandle(h); 1019 return; 1020 } else if (obj instanceof Class ) { 1021 writeClass((Class ) obj, unshared); 1022 return; 1023 } else if (obj instanceof ObjectStreamClass ) { 1024 writeClassDesc((ObjectStreamClass ) obj, unshared); 1025 return; 1026 } 1027 1028 Object orig = obj; 1030 Class cl = obj.getClass(); 1031 ObjectStreamClass desc; 1032 for (;;) { 1033 Class repCl; 1035 desc = ObjectStreamClass.lookup(cl, true); 1036 if (!desc.hasWriteReplaceMethod() || 1037 (obj = desc.invokeWriteReplace(obj)) == null || 1038 (repCl = obj.getClass()) == cl) 1039 { 1040 break; 1041 } 1042 cl = repCl; 1043 } 1044 if (enableReplace) { 1045 Object rep = replaceObject(obj); 1046 if (rep != obj && rep != null) { 1047 cl = rep.getClass(); 1048 desc = ObjectStreamClass.lookup(cl, true); 1049 } 1050 obj = rep; 1051 } 1052 1053 if (obj != orig) { 1055 subs.assign(orig, obj); 1056 if (obj == null) { 1057 writeNull(); 1058 return; 1059 } else if (!unshared && (h = handles.lookup(obj)) != -1) { 1060 writeHandle(h); 1061 return; 1062 } else if (obj instanceof Class ) { 1063 writeClass((Class ) obj, unshared); 1064 return; 1065 } else if (obj instanceof ObjectStreamClass ) { 1066 writeClassDesc((ObjectStreamClass ) obj, unshared); 1067 return; 1068 } 1069 } 1070 1071 if (obj instanceof String ) { 1073 writeString((String ) obj, unshared); 1074 } else if (cl.isArray()) { 1075 writeArray(obj, desc, unshared); 1076 } else if (obj instanceof Enum ) { 1077 writeEnum((Enum ) obj, desc, unshared); 1078 } else if (obj instanceof Serializable ) { 1079 writeOrdinaryObject(obj, desc, unshared); 1080 } else { 1081 throw new NotSerializableException (cl.getName()); 1082 } 1083 } finally { 1084 depth--; 1085 bout.setBlockDataMode(oldMode); 1086 } 1087 } 1088 1089 1092 private void writeNull() throws IOException { 1093 bout.writeByte(TC_NULL); 1094 } 1095 1096 1099 private void writeHandle(int handle) throws IOException { 1100 bout.writeByte(TC_REFERENCE); 1101 bout.writeInt(baseWireHandle + handle); 1102 } 1103 1104 1107 private void writeClass(Class cl, boolean unshared) throws IOException { 1108 bout.writeByte(TC_CLASS); 1109 writeClassDesc(ObjectStreamClass.lookup(cl, true), false); 1110 handles.assign(unshared ? null : cl); 1111 } 1112 1113 1116 private void writeClassDesc(ObjectStreamClass desc, boolean unshared) 1117 throws IOException 1118 { 1119 int handle; 1120 if (desc == null) { 1121 writeNull(); 1122 } else if (!unshared && (handle = handles.lookup(desc)) != -1) { 1123 writeHandle(handle); 1124 } else if (desc.isProxy()) { 1125 writeProxyDesc(desc, unshared); 1126 } else { 1127 writeNonProxyDesc(desc, unshared); 1128 } 1129 } 1130 1131 1134 private void writeProxyDesc(ObjectStreamClass desc, boolean unshared) 1135 throws IOException 1136 { 1137 bout.writeByte(TC_PROXYCLASSDESC); 1138 handles.assign(unshared ? null : desc); 1139 1140 Class cl = desc.forClass(); 1141 Class [] ifaces = cl.getInterfaces(); 1142 bout.writeInt(ifaces.length); 1143 for (int i = 0; i < ifaces.length; i++) { 1144 bout.writeUTF(ifaces[i].getName()); 1145 } 1146 1147 bout.setBlockDataMode(true); 1148 annotateProxyClass(cl); 1149 bout.setBlockDataMode(false); 1150 bout.writeByte(TC_ENDBLOCKDATA); 1151 1152 writeClassDesc(desc.getSuperDesc(), false); 1153 } 1154 1155 1159 private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared) 1160 throws IOException 1161 { 1162 bout.writeByte(TC_CLASSDESC); 1163 handles.assign(unshared ? null : desc); 1164 1165 if (protocol == PROTOCOL_VERSION_1) { 1166 desc.writeNonProxy(this); 1168 } else { 1169 writeClassDescriptor(desc); 1170 } 1171 1172 Class cl = desc.forClass(); 1173 bout.setBlockDataMode(true); 1174 annotateClass(cl); 1175 bout.setBlockDataMode(false); 1176 bout.writeByte(TC_ENDBLOCKDATA); 1177 1178 writeClassDesc(desc.getSuperDesc(), false); 1179 } 1180 1181 1185 private void writeString(String str, boolean unshared) throws IOException { 1186 handles.assign(unshared ? null : str); 1187 long utflen = bout.getUTFLength(str); 1188 if (utflen <= 0xFFFF) { 1189 bout.writeByte(TC_STRING); 1190 bout.writeUTF(str, utflen); 1191 } else { 1192 bout.writeByte(TC_LONGSTRING); 1193 bout.writeLongUTF(str, utflen); 1194 } 1195 } 1196 1197 1200 private void writeArray(Object array, 1201 ObjectStreamClass desc, 1202 boolean unshared) 1203 throws IOException 1204 { 1205 bout.writeByte(TC_ARRAY); 1206 writeClassDesc(desc, false); 1207 handles.assign(unshared ? null : array); 1208 1209 Class ccl = desc.forClass().getComponentType(); 1210 if (ccl.isPrimitive()) { 1211 if (ccl == Integer.TYPE) { 1212 int[] ia = (int[]) array; 1213 bout.writeInt(ia.length); 1214 bout.writeInts(ia, 0, ia.length); 1215 } else if (ccl == Byte.TYPE) { 1216 byte[] ba = (byte[]) array; 1217 bout.writeInt(ba.length); 1218 bout.write(ba, 0, ba.length, true); 1219 } else if (ccl == Long.TYPE) { 1220 long[] ja = (long[]) array; 1221 bout.writeInt(ja.length); 1222 bout.writeLongs(ja, 0, ja.length); 1223 } else if (ccl == Float.TYPE) { 1224 float[] fa = (float[]) array; 1225 bout.writeInt(fa.length); 1226 bout.writeFloats(fa, 0, fa.length); 1227 } else if (ccl == Double.TYPE) { 1228 double[] da = (double[]) array; 1229 bout.writeInt(da.length); 1230 bout.writeDoubles(da, 0, da.length); 1231 } else if (ccl == Short.TYPE) { 1232 short[] sa = (short[]) array; 1233 bout.writeInt(sa.length); 1234 bout.writeShorts(sa, 0, sa.length); 1235 } else if (ccl == Character.TYPE) { 1236 char[] ca = (char[]) array; 1237 bout.writeInt(ca.length); 1238 bout.writeChars(ca, 0, ca.length); 1239 } else if (ccl == Boolean.TYPE) { 1240 boolean[] za = (boolean[]) array; 1241 bout.writeInt(za.length); 1242 bout.writeBooleans(za, 0, za.length); 1243 } else { 1244 throw new InternalError (); 1245 } 1246 } else { 1247 Object [] objs = (Object []) array; 1248 int len = objs.length; 1249 bout.writeInt(len); 1250 for (int i = 0; i < len; i++) { 1251 writeObject0(objs[i], false); 1252 } 1253 } 1254 } 1255 1256 1259 private void writeEnum(Enum en, 1260 ObjectStreamClass desc, 1261 boolean unshared) 1262 throws IOException 1263 { 1264 bout.writeByte(TC_ENUM); 1265 ObjectStreamClass sdesc = desc.getSuperDesc(); 1266 writeClassDesc((sdesc.forClass() == Enum .class) ? desc : sdesc, false); 1267 handles.assign(unshared ? null : en); 1268 writeString(en.name(), false); 1269 } 1270 1271 1276 private void writeOrdinaryObject(Object obj, 1277 ObjectStreamClass desc, 1278 boolean unshared) 1279 throws IOException 1280 { 1281 desc.checkSerialize(); 1282 1283 bout.writeByte(TC_OBJECT); 1284 writeClassDesc(desc, false); 1285 handles.assign(unshared ? null : obj); 1286 1287 if (desc.isExternalizable() && !desc.isProxy()) { 1288 writeExternalData((Externalizable ) obj); 1289 } else { 1290 writeSerialData(obj, desc); 1291 } 1292 } 1293 1294 1298 private void writeExternalData(Externalizable obj) throws IOException { 1299 Object oldObj = curObj; 1300 ObjectStreamClass oldDesc = curDesc; 1301 PutFieldImpl oldPut = curPut; 1302 curObj = obj; 1303 curDesc = null; 1304 curPut = null; 1305 1306 if (protocol == PROTOCOL_VERSION_1) { 1307 obj.writeExternal(this); 1308 } else { 1309 bout.setBlockDataMode(true); 1310 obj.writeExternal(this); 1311 bout.setBlockDataMode(false); 1312 bout.writeByte(TC_ENDBLOCKDATA); 1313 } 1314 1315 curObj = oldObj; 1316 curDesc = oldDesc; 1317 curPut = oldPut; 1318 } 1319 1320 1324 private void writeSerialData(Object obj, ObjectStreamClass desc) 1325 throws IOException 1326 { 1327 ObjectStreamClass.ClassDataSlot [] slots = desc.getClassDataLayout(); 1328 for (int i = 0; i < slots.length; i++) { 1329 ObjectStreamClass slotDesc = slots[i].desc; 1330 if (slotDesc.hasWriteObjectMethod()) { 1331 Object oldObj = curObj; 1332 ObjectStreamClass oldDesc = curDesc; 1333 PutFieldImpl oldPut = curPut; 1334 curObj = obj; 1335 curDesc = slotDesc; 1336 curPut = null; 1337 1338 bout.setBlockDataMode(true); 1339 slotDesc.invokeWriteObject(obj, this); 1340 bout.setBlockDataMode(false); 1341 bout.writeByte(TC_ENDBLOCKDATA); 1342 1343 curObj = oldObj; 1344 curDesc = oldDesc; 1345 curPut = oldPut; 1346 } else { 1347 defaultWriteFields(obj, slotDesc); 1348 } 1349 } 1350 } 1351 1352 1357 private void defaultWriteFields(Object obj, ObjectStreamClass desc) 1358 throws IOException 1359 { 1360 desc.checkDefaultSerialize(); 1362 1363 int primDataSize = desc.getPrimDataSize(); 1364 if (primVals == null || primVals.length < primDataSize) { 1365 primVals = new byte[primDataSize]; 1366 } 1367 desc.getPrimFieldValues(obj, primVals); 1368 bout.write(primVals, 0, primDataSize, false); 1369 1370 ObjectStreamField [] fields = desc.getFields(false); 1371 Object [] objVals = new Object [desc.getNumObjFields()]; 1372 int numPrimFields = fields.length - objVals.length; 1373 desc.getObjFieldValues(obj, objVals); 1374 for (int i = 0; i < objVals.length; i++) { 1375 writeObject0(objVals[i], fields[numPrimFields + i].isUnshared()); 1376 } 1377 } 1378 1379 1383 private void writeFatalException(IOException ex) throws IOException { 1384 1394 clear(); 1395 boolean oldMode = bout.setBlockDataMode(false); 1396 try { 1397 bout.writeByte(TC_EXCEPTION); 1398 writeObject0(ex, false); 1399 clear(); 1400 } finally { 1401 bout.setBlockDataMode(oldMode); 1402 } 1403 } 1404 1405 1408 private static native void floatsToBytes(float[] src, int srcpos, 1410 byte[] dst, int dstpos, 1411 int nfloats); 1412 1413 1416 private static native void doublesToBytes(double[] src, int srcpos, 1418 byte[] dst, int dstpos, 1419 int ndoubles); 1420 1421 1424 private class PutFieldImpl extends PutField { 1425 1426 1427 private final ObjectStreamClass desc; 1428 1429 private final byte[] primVals; 1430 1431 private final Object [] objVals; 1432 1433 1437 PutFieldImpl(ObjectStreamClass desc) { 1438 this.desc = desc; 1439 primVals = new byte[desc.getPrimDataSize()]; 1440 objVals = new Object [desc.getNumObjFields()]; 1441 } 1442 1443 public void put(String name, boolean val) { 1444 Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val); 1445 } 1446 1447 public void put(String name, byte val) { 1448 primVals[getFieldOffset(name, Byte.TYPE)] = val; 1449 } 1450 1451 public void put(String name, char val) { 1452 Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val); 1453 } 1454 1455 public void put(String name, short val) { 1456 Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val); 1457 } 1458 1459 public void put(String name, int val) { 1460 Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val); 1461 } 1462 1463 public void put(String name, float val) { 1464 Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val); 1465 } 1466 1467 public void put(String name, long val) { 1468 Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val); 1469 } 1470 1471 public void put(String name, double val) { 1472 Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val); 1473 } 1474 1475 public void put(String name, Object val) { 1476 objVals[getFieldOffset(name, Object .class)] = val; 1477 } 1478 1479 public void write(ObjectOutput out) throws IOException { 1481 1496 if (ObjectOutputStream.this != out) { 1497 throw new IllegalArgumentException ("wrong stream"); 1498 } 1499 out.write(primVals, 0, primVals.length); 1500 1501 ObjectStreamField [] fields = desc.getFields(false); 1502 int numPrimFields = fields.length - objVals.length; 1503 for (int i = 0; i < objVals.length; i++) { 1505 if (fields[numPrimFields + i].isUnshared()) { 1506 throw new IOException ("cannot write unshared object"); 1507 } 1508 out.writeObject(objVals[i]); 1509 } 1510 } 1511 1512 1515 void writeFields() throws IOException { 1516 bout.write(primVals, 0, primVals.length, false); 1517 1518 ObjectStreamField [] fields = desc.getFields(false); 1519 int numPrimFields = fields.length - objVals.length; 1520 for (int i = 0; i < objVals.length; i++) { 1521 writeObject0( 1522 objVals[i], fields[numPrimFields + i].isUnshared()); 1523 } 1524 } 1525 1526 1532 private int getFieldOffset(String name, Class type) { 1533 ObjectStreamField field = desc.getField(name, type); 1534 if (field == null) { 1535 throw new IllegalArgumentException ("no such field"); 1536 } 1537 return field.getOffset(); 1538 } 1539 } 1540 1541 1547 private static class BlockDataOutputStream 1548 extends OutputStream implements DataOutput 1549 { 1550 1551 private static final int MAX_BLOCK_SIZE = 1024; 1552 1553 private static final int MAX_HEADER_SIZE = 5; 1554 1555 private static final int CHAR_BUF_SIZE = 256; 1556 1557 1558 private final byte[] buf = new byte[MAX_BLOCK_SIZE]; 1559 1560 private final byte[] hbuf = new byte[MAX_HEADER_SIZE]; 1561 1562 private final char[] cbuf = new char[CHAR_BUF_SIZE]; 1563 1564 1565 private boolean blkmode = false; 1566 1567 private int pos = 0; 1568 1569 1570 private final OutputStream out; 1571 1572 private final DataOutputStream dout; 1573 1574 1578 BlockDataOutputStream(OutputStream out) { 1579 this.out = out; 1580 dout = new DataOutputStream (this); 1581 } 1582 1583 1590 boolean setBlockDataMode(boolean mode) throws IOException { 1591 if (blkmode == mode) { 1592 return blkmode; 1593 } 1594 drain(); 1595 blkmode = mode; 1596 return !blkmode; 1597 } 1598 1599 1603 boolean getBlockDataMode() { 1604 return blkmode; 1605 } 1606 1607 1608 1613 1614 public void write(int b) throws IOException { 1615 if (pos >= MAX_BLOCK_SIZE) { 1616 drain(); 1617 } 1618 buf[pos++] = (byte) b; 1619 } 1620 1621 public void write(byte[] b) throws IOException { 1622 write(b, 0, b.length, false); 1623 } 1624 1625 public void write(byte[] b, int off, int len) throws IOException { 1626 write(b, off, len, false); 1627 } 1628 1629 public void flush() throws IOException { 1630 drain(); 1631 out.flush(); 1632 } 1633 1634 public void close() throws IOException { 1635 flush(); 1636 out.close(); 1637 } 1638 1639 1645 void write(byte[] b, int off, int len, boolean copy) 1646 throws IOException 1647 { 1648 if (!(copy || blkmode)) { drain(); 1650 out.write(b, off, len); 1651 return; 1652 } 1653 1654 while (len > 0) { 1655 if (pos >= MAX_BLOCK_SIZE) { 1656 drain(); 1657 } 1658 if (len >= MAX_BLOCK_SIZE && !copy && pos == 0) { 1659 writeBlockHeader(MAX_BLOCK_SIZE); 1661 out.write(b, off, MAX_BLOCK_SIZE); 1662 off += MAX_BLOCK_SIZE; 1663 len -= MAX_BLOCK_SIZE; 1664 } else { 1665 int wlen = Math.min(len, MAX_BLOCK_SIZE - pos); 1666 System.arraycopy(b, off, buf, pos, wlen); 1667 pos += wlen; 1668 off += wlen; 1669 len -= wlen; 1670 } 1671 } 1672 } 1673 1674 1678 void drain() throws IOException { 1679 if (pos == 0) { 1680 return; 1681 } 1682 if (blkmode) { 1683 writeBlockHeader(pos); 1684 } 1685 out.write(buf, 0, pos); 1686 pos = 0; 1687 } 1688 1689 1694 private void writeBlockHeader(int len) throws IOException { 1695 if (len <= 0xFF) { 1696 hbuf[0] = TC_BLOCKDATA; 1697 hbuf[1] = (byte) len; 1698 out.write(hbuf, 0, 2); 1699 } else { 1700 hbuf[0] = TC_BLOCKDATALONG; 1701 Bits.putInt(hbuf, 1, len); 1702 out.write(hbuf, 0, 5); 1703 } 1704 } 1705 1706 1707 1708 1713 1714 public void writeBoolean(boolean v) throws IOException { 1715 if (pos >= MAX_BLOCK_SIZE) { 1716 drain(); 1717 } 1718 Bits.putBoolean(buf, pos++, v); 1719 } 1720 1721 public void writeByte(int v) throws IOException { 1722 if (pos >= MAX_BLOCK_SIZE) { 1723 drain(); 1724 } 1725 buf[pos++] = (byte) v; 1726 } 1727 1728 public void writeChar(int v) throws IOException { 1729 if (pos + 2 <= MAX_BLOCK_SIZE) { 1730 Bits.putChar(buf, pos, (char) v); 1731 pos += 2; 1732 } else { 1733 dout.writeChar(v); 1734 } 1735 } 1736 1737 public void writeShort(int v) throws IOException { 1738 if (pos + 2 <= MAX_BLOCK_SIZE) { 1739 Bits.putShort(buf, pos, (short) v); 1740 pos += 2; 1741 } else { 1742 dout.writeShort(v); 1743 } 1744 } 1745 1746 public void writeInt(int v) throws IOException { 1747 if (pos + 4 <= MAX_BLOCK_SIZE) { 1748 Bits.putInt(buf, pos, v); 1749 pos += 4; 1750 } else { 1751 dout.writeInt(v); 1752 } 1753 } 1754 1755 public void writeFloat(float v) throws IOException { 1756 if (pos + 4 <= MAX_BLOCK_SIZE) { 1757 Bits.putFloat(buf, pos, v); 1758 pos += 4; 1759 } else { 1760 dout.writeFloat(v); 1761 } 1762 } 1763 1764 public void writeLong(long v) throws IOException { 1765 if (pos + 8 <= MAX_BLOCK_SIZE) { 1766 Bits.putLong(buf, pos, v); 1767 pos += 8; 1768 } else { 1769 dout.writeLong(v); 1770 } 1771 } 1772 1773 public void writeDouble(double v) throws IOException { 1774 if (pos + 8 <= MAX_BLOCK_SIZE) { 1775 Bits.putDouble(buf, pos, v); 1776 pos += 8; 1777 } else { 1778 dout.writeDouble(v); 1779 } 1780 } 1781 1782 public void writeBytes(String s) throws IOException { 1783 int endoff = s.length(); 1784 int cpos = 0; 1785 int csize = 0; 1786 for (int off = 0; off < endoff; ) { 1787 if (cpos >= csize) { 1788 cpos = 0; 1789 csize = Math.min(endoff - off, CHAR_BUF_SIZE); 1790 s.getChars(off, off + csize, cbuf, 0); 1791 } 1792 if (pos >= MAX_BLOCK_SIZE) { 1793 drain(); 1794 } 1795 int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos); 1796 int stop = pos + n; 1797 while (pos < stop) { 1798 buf[pos++] = (byte) cbuf[cpos++]; 1799 } 1800 off += n; 1801 } 1802 } 1803 1804 public void writeChars(String s) throws IOException { 1805 int endoff = s.length(); 1806 for (int off = 0; off < endoff; ) { 1807 int csize = Math.min(endoff - off, CHAR_BUF_SIZE); 1808 s.getChars(off, off + csize, cbuf, 0); 1809 writeChars(cbuf, 0, csize); 1810 off += csize; 1811 } 1812 } 1813 1814 public void writeUTF(String s) throws IOException { 1815 writeUTF(s, getUTFLength(s)); 1816 } 1817 1818 1819 1820 1826 1827 void writeBooleans(boolean[] v, int off, int len) throws IOException { 1828 int endoff = off + len; 1829 while (off < endoff) { 1830 if (pos >= MAX_BLOCK_SIZE) { 1831 drain(); 1832 } 1833 int stop = Math.min(endoff, off + (MAX_BLOCK_SIZE - pos)); 1834 while (off < stop) { 1835 Bits.putBoolean(buf, pos++, v[off++]); 1836 } 1837 } 1838 } 1839 1840 void writeChars(char[] v, int off, int len) throws IOException { 1841 int limit = MAX_BLOCK_SIZE - 2; 1842 int endoff = off + len; 1843 while (off < endoff) { 1844 if (pos <= limit) { 1845 int avail = (MAX_BLOCK_SIZE - pos) >> 1; 1846 int stop = Math.min(endoff, off + avail); 1847 while (off < stop) { 1848 Bits.putChar(buf, pos, v[off++]); 1849 pos += 2; 1850 } 1851 } else { 1852 dout.writeChar(v[off++]); 1853 } 1854 } 1855 } 1856 1857 void writeShorts(short[] v, int off, int len) throws IOException { 1858 int limit = MAX_BLOCK_SIZE - 2; 1859 int endoff = off + len; 1860 while (off < endoff) { 1861 if (pos <= limit) { 1862 int avail = (MAX_BLOCK_SIZE - pos) >> 1; 1863 int stop = Math.min(endoff, off + avail); 1864 while (off < stop) { 1865 Bits.putShort(buf, pos, v[off++]); 1866 pos += 2; 1867 } 1868 } else { 1869 dout.writeShort(v[off++]); 1870 } 1871 } 1872 } 1873 1874 void writeInts(int[] v, int off, int len) throws IOException { 1875 int limit = MAX_BLOCK_SIZE - 4; 1876 int endoff = off + len; 1877 while (off < endoff) { 1878 if (pos <= limit) { 1879 int avail = (MAX_BLOCK_SIZE - pos) >> 2; 1880 int stop = Math.min(endoff, off + avail); 1881 while (off < stop) { 1882 Bits.putInt(buf, pos, v[off++]); 1883 pos += 4; 1884 } 1885 } else { 1886 dout.writeInt(v[off++]); 1887 } 1888 } 1889 } 1890 1891 void writeFloats(float[] v, int off, int len) throws IOException { 1892 int limit = MAX_BLOCK_SIZE - 4; 1893 int endoff = off + len; 1894 while (off < endoff) { 1895 if (pos <= limit) { 1896 int avail = (MAX_BLOCK_SIZE - pos) >> 2; 1897 int chunklen = Math.min(endoff - off, avail); 1898 floatsToBytes(v, off, buf, pos, chunklen); 1899 off += chunklen; 1900 pos += chunklen << 2; 1901 } else { 1902 dout.writeFloat(v[off++]); 1903 } 1904 } 1905 } 1906 1907 void writeLongs(long[] v, int off, int len) throws IOException { 1908 int limit = MAX_BLOCK_SIZE - 8; 1909 int endoff = off + len; 1910 while (off < endoff) { 1911 if (pos <= limit) { 1912 int avail = (MAX_BLOCK_SIZE - pos) >> 3; 1913 int stop = Math.min(endoff, off + avail); 1914 while (off < stop) { 1915 Bits.putLong(buf, pos, v[off++]); 1916 pos += 8; 1917 } 1918 } else { 1919 dout.writeLong(v[off++]); 1920 } 1921 } 1922 } 1923 1924 void writeDoubles(double[] v, int off, int len) throws IOException { 1925 int limit = MAX_BLOCK_SIZE - 8; 1926 int endoff = off + len; 1927 while (off < endoff) { 1928 if (pos <= limit) { 1929 int avail = (MAX_BLOCK_SIZE - pos) >> 3; 1930 int chunklen = Math.min(endoff - off, avail); 1931 doublesToBytes(v, off, buf, pos, chunklen); 1932 off += chunklen; 1933 pos += chunklen << 3; 1934 } else { 1935 dout.writeDouble(v[off++]); 1936 } 1937 } 1938 } 1939 1940 1943 long getUTFLength(String s) { 1944 int len = s.length(); 1945 long utflen = 0; 1946 for (int off = 0; off < len; ) { 1947 int csize = Math.min(len - off, CHAR_BUF_SIZE); 1948 s.getChars(off, off + csize, cbuf, 0); 1949 for (int cpos = 0; cpos < csize; cpos++) { 1950 char c = cbuf[cpos]; 1951 if (c >= 0x0001 && c <= 0x007F) { 1952 utflen++; 1953 } else if (c > 0x07FF) { 1954 utflen += 3; 1955 } else { 1956 utflen += 2; 1957 } 1958 } 1959 off += csize; 1960 } 1961 return utflen; 1962 } 1963 1964 1970 void writeUTF(String s, long utflen) throws IOException { 1971 if (utflen > 0xFFFFL) { 1972 throw new UTFDataFormatException (); 1973 } 1974 writeShort((int) utflen); 1975 if (utflen == (long) s.length()) { 1976 writeBytes(s); 1977 } else { 1978 writeUTFBody(s); 1979 } 1980 } 1981 1982 1987 void writeLongUTF(String s) throws IOException { 1988 writeLongUTF(s, getUTFLength(s)); 1989 } 1990 1991 1995 void writeLongUTF(String s, long utflen) throws IOException { 1996 writeLong(utflen); 1997 if (utflen == (long) s.length()) { 1998 writeBytes(s); 1999 } else { 2000 writeUTFBody(s); 2001 } 2002 } 2003 2004 2008 private void writeUTFBody(String s) throws IOException { 2009 int limit = MAX_BLOCK_SIZE - 3; 2010 int len = s.length(); 2011 for (int off = 0; off < len; ) { 2012 int csize = Math.min(len - off, CHAR_BUF_SIZE); 2013 s.getChars(off, off + csize, cbuf, 0); 2014 for (int cpos = 0; cpos < csize; cpos++) { 2015 char c = cbuf[cpos]; 2016 if (pos <= limit) { 2017 if (c <= 0x007F && c != 0) { 2018 buf[pos++] = (byte) c; 2019 } else if (c > 0x07FF) { 2020 buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F)); 2021 buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F)); 2022 buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F)); 2023 pos += 3; 2024 } else { 2025 buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F)); 2026 buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F)); 2027 pos += 2; 2028 } 2029 } else { if (c <= 0x007F && c != 0) { 2031 write(c); 2032 } else if (c > 0x07FF) { 2033 write(0xE0 | ((c >> 12) & 0x0F)); 2034 write(0x80 | ((c >> 6) & 0x3F)); 2035 write(0x80 | ((c >> 0) & 0x3F)); 2036 } else { 2037 write(0xC0 | ((c >> 6) & 0x1F)); 2038 write(0x80 | ((c >> 0) & 0x3F)); 2039 } 2040 } 2041 } 2042 off += csize; 2043 } 2044 } 2045 } 2046 2047 2051 private static class HandleTable { 2052 2053 2054 private int size; 2055 2056 private int threshold; 2057 2058 private final float loadFactor; 2059 2060 private int[] spine; 2061 2062 private int[] next; 2063 2064 private Object [] objs; 2065 2066 2069 HandleTable(int initialCapacity, float loadFactor) { 2070 this.loadFactor = loadFactor; 2071 spine = new int[initialCapacity]; 2072 next = new int[initialCapacity]; 2073 objs = new Object [initialCapacity]; 2074 threshold = (int) (initialCapacity * loadFactor); 2075 clear(); 2076 } 2077 2078 2082 int assign(Object obj) { 2083 if (size >= next.length) { 2084 growEntries(); 2085 } 2086 if (size >= threshold) { 2087 growSpine(); 2088 } 2089 insert(obj, size); 2090 return size++; 2091 } 2092 2093 2097 int lookup(Object obj) { 2098 if (size == 0) { 2099 return -1; 2100 } 2101 int index = hash(obj) % spine.length; 2102 for (int i = spine[index]; i >= 0; i = next[i]) { 2103 if (objs[i] == obj) { 2104 return i; 2105 } 2106 } 2107 return -1; 2108 } 2109 2110 2113 void clear() { 2114 Arrays.fill(spine, -1); 2115 Arrays.fill(objs, 0, size, null); 2116 size = 0; 2117 } 2118 2119 2122 int size() { 2123 return size; 2124 } 2125 2126 2130 private void insert(Object obj, int handle) { 2131 int index = hash(obj) % spine.length; 2132 objs[handle] = obj; 2133 next[handle] = spine[index]; 2134 spine[index] = handle; 2135 } 2136 2137 2141 private void growSpine() { 2142 spine = new int[(spine.length << 1) + 1]; 2143 threshold = (int) (spine.length * loadFactor); 2144 Arrays.fill(spine, -1); 2145 for (int i = 0; i < size; i++) { 2146 insert(objs[i], i); 2147 } 2148 } 2149 2150 2153 private void growEntries() { 2154 int newLength = (next.length << 1) + 1; 2155 int[] newNext = new int[newLength]; 2156 System.arraycopy(next, 0, newNext, 0, size); 2157 next = newNext; 2158 2159 Object [] newObjs = new Object [newLength]; 2160 System.arraycopy(objs, 0, newObjs, 0, size); 2161 objs = newObjs; 2162 } 2163 2164 2167 private int hash(Object obj) { 2168 return System.identityHashCode(obj) & 0x7FFFFFFF; 2169 } 2170 } 2171 2172 2176 private static class ReplaceTable { 2177 2178 2179 private final HandleTable htab; 2180 2181 private Object [] reps; 2182 2183 2186 ReplaceTable(int initialCapacity, float loadFactor) { 2187 htab = new HandleTable(initialCapacity, loadFactor); 2188 reps = new Object [initialCapacity]; 2189 } 2190 2191 2194 void assign(Object obj, Object rep) { 2195 int index = htab.assign(obj); 2196 while (index >= reps.length) { 2197 grow(); 2198 } 2199 reps[index] = rep; 2200 } 2201 2202 2206 Object lookup(Object obj) { 2207 int index = htab.lookup(obj); 2208 return (index >= 0) ? reps[index] : obj; 2209 } 2210 2211 2214 void clear() { 2215 Arrays.fill(reps, 0, htab.size(), null); 2216 htab.clear(); 2217 } 2218 2219 2222 int size() { 2223 return htab.size(); 2224 } 2225 2226 2229 private void grow() { 2230 Object [] newReps = new Object [(reps.length << 1) + 1]; 2231 System.arraycopy(reps, 0, newReps, 0, reps.length); 2232 reps = newReps; 2233 } 2234 } 2235} 2236 | Popular Tags |