// write identical to other version, but take field values from hashmap (because of annoying
 // putField/getField feature)
 private void writeCompatibleObjectFields(
     Object toWrite, Map fields, FSTClazzInfo.FSTFieldInfo[] fieldInfo) throws IOException {
   int booleanMask = 0;
   int boolcount = 0;
   for (int i = 0; i < fieldInfo.length; i++) {
     try {
       FSTClazzInfo.FSTFieldInfo subInfo = fieldInfo[i];
       boolean isarr = subInfo.isArray();
       Class subInfType = subInfo.getType();
       if (subInfType != boolean.class || isarr) {
         if (boolcount > 0) {
           codec.writeFByte(booleanMask << (8 - boolcount));
           boolcount = 0;
           booleanMask = 0;
         }
       }
       if (subInfo.isIntegral() && !isarr) {
         if (subInfType == boolean.class) {
           if (boolcount == 8) {
             codec.writeFByte(booleanMask << (8 - boolcount));
             boolcount = 0;
             booleanMask = 0;
           }
           boolean booleanValue =
               ((Boolean) fields.get(subInfo.getField().getName())).booleanValue();
           booleanMask = booleanMask << 1;
           booleanMask = (booleanMask | (booleanValue ? 1 : 0));
           boolcount++;
         } else if (subInfType == int.class) {
           codec.writeFInt(((Number) fields.get(subInfo.getField().getName())).intValue());
         } else if (subInfType == long.class) {
           codec.writeFLong(((Number) fields.get(subInfo.getField().getName())).longValue());
         } else if (subInfType == byte.class) {
           codec.writeFByte(((Number) fields.get(subInfo.getField().getName())).byteValue());
         } else if (subInfType == char.class) {
           codec.writeFChar((char) ((Number) fields.get(subInfo.getField().getName())).intValue());
         } else if (subInfType == short.class) {
           codec.writeFShort(((Number) fields.get(subInfo.getField().getName())).shortValue());
         } else if (subInfType == float.class) {
           codec.writeFFloat(((Number) fields.get(subInfo.getField().getName())).floatValue());
         } else if (subInfType == double.class) {
           codec.writeFDouble(((Number) fields.get(subInfo.getField().getName())).doubleValue());
         }
       } else {
         // object
         Object subObject = fields.get(subInfo.getField().getName());
         writeObjectWithContext(subInfo, subObject);
       }
     } catch (Exception ex) {
       throw FSTUtil.rethrow(ex);
     }
   }
   if (boolcount > 0) {
     codec.writeFByte(booleanMask << (8 - boolcount));
   }
 }
 private void writeObjectFields(
     Object toWrite,
     FSTClazzInfo serializationInfo,
     FSTClazzInfo.FSTFieldInfo[] fieldInfo,
     int startIndex,
     int version)
     throws IOException {
   try {
     int booleanMask = 0;
     int boolcount = 0;
     final int length = fieldInfo.length;
     int j = startIndex;
     if (!codec.isWritingAttributes()) {
       for (; ; j++) {
         if (j == length || fieldInfo[j].getVersion() != version) {
           if (boolcount > 0) {
             codec.writeFByte(booleanMask << (8 - boolcount));
           }
           break;
         }
         final FSTClazzInfo.FSTFieldInfo subInfo = fieldInfo[j];
         if (subInfo.getIntegralType() != subInfo.BOOL) {
           if (boolcount > 0) {
             codec.writeFByte(booleanMask << (8 - boolcount));
           }
           break;
         } else {
           if (boolcount == 8) {
             codec.writeFByte(booleanMask << (8 - boolcount));
             boolcount = 0;
             booleanMask = 0;
           }
           boolean booleanValue = subInfo.getBooleanValue(toWrite);
           booleanMask = booleanMask << 1;
           booleanMask = (booleanMask | (booleanValue ? 1 : 0));
           boolcount++;
         }
       }
     }
     for (int i = j; i < length; i++) {
       final FSTClazzInfo.FSTFieldInfo subInfo = fieldInfo[i];
       if (subInfo.getVersion() != version) {
         codec.writeVersionTag(subInfo.getVersion());
         writeObjectFields(toWrite, serializationInfo, fieldInfo, i, subInfo.getVersion());
         return;
       }
       codec.writeAttributeName(subInfo);
       if (subInfo.isPrimitive()) {
         // speed safe
         int integralType = subInfo.getIntegralType();
         switch (integralType) {
           case FSTClazzInfo.FSTFieldInfo.BOOL:
             codec.writeFByte(subInfo.getBooleanValue(toWrite) ? 1 : 0);
             break;
           case FSTClazzInfo.FSTFieldInfo.BYTE:
             codec.writeFByte(subInfo.getByteValue(toWrite));
             break;
           case FSTClazzInfo.FSTFieldInfo.CHAR:
             codec.writeFChar((char) subInfo.getCharValue(toWrite));
             break;
           case FSTClazzInfo.FSTFieldInfo.SHORT:
             codec.writeFShort((short) subInfo.getShortValue(toWrite));
             break;
           case FSTClazzInfo.FSTFieldInfo.INT:
             codec.writeFInt(subInfo.getIntValue(toWrite));
             break;
           case FSTClazzInfo.FSTFieldInfo.LONG:
             codec.writeFLong(subInfo.getLongValue(toWrite));
             break;
           case FSTClazzInfo.FSTFieldInfo.FLOAT:
             codec.writeFFloat(subInfo.getFloatValue(toWrite));
             break;
           case FSTClazzInfo.FSTFieldInfo.DOUBLE:
             codec.writeFDouble(subInfo.getDoubleValue(toWrite));
             break;
         }
       } else if (subInfo.isConditional()) {
         final int conditional = codec.getWritten();
         codec.skip(4);
         // object
         Object subObject = subInfo.getObjectValue(toWrite);
         if (subObject == null) {
           codec.writeTag(NULL, null, 0, toWrite);
         } else {
           writeObjectWithContext(subInfo, subObject);
         }
         int v = codec.getWritten();
         codec.writeInt32At(conditional, v);
       } else {
         // object
         Object subObject = subInfo.getObjectValue(toWrite);
         if (subObject == null) {
           codec.writeTag(NULL, null, 0, toWrite);
         } else {
           writeObjectWithContext(subInfo, subObject);
         }
       }
     }
     codec.writeVersionTag((byte) 0);
   } catch (IllegalAccessException ex) {
     throw FSTUtil.rethrow(ex);
   }
 }
 @Override
 public void writeChar(int v) throws IOException {
   codec.writeFChar((char) v);
 }