diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/serialization/Deserializer.java b/renderer/native/android/src/main/java/com/tencent/renderer/serialization/Deserializer.java index c0043340f..3ecc21c17 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/serialization/Deserializer.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/serialization/Deserializer.java @@ -19,6 +19,7 @@ package com.tencent.renderer.serialization; import static com.tencent.renderer.NativeRenderException.ExceptionCode.DESERIALIZE_NOT_SUPPORTED_ERR; import static com.tencent.renderer.NativeRenderException.ExceptionCode.DESERIALIZE_READ_LENGTH_ERR; +import com.tencent.mtt.hippy.exception.UnexpectedException; import com.tencent.mtt.hippy.serialization.PrimitiveSerializationTag; import com.tencent.mtt.hippy.serialization.exception.DataCloneOutOfRangeException; import com.tencent.mtt.hippy.serialization.PrimitiveValueDeserializer; @@ -77,6 +78,8 @@ public class Deserializer extends PrimitiveValueDeserializer { return readMap(); case SerializationTag.BEGIN_DENSE_ARRAY: return readDenseArray(); + case SerializationTag.BEGIN_SPARSE_JS_ARRAY: + return readSparseArray(); default: throw createUnsupportedTagException(tag); } @@ -195,6 +198,61 @@ public class Deserializer extends PrimitiveValueDeserializer { return array; } + + /** + * Reads Spare Array from buffer. + * + *

Note

+ * Sparse arrays will be serialized as an object-like manner. Normally, it should be representable + * as {@link ArrayList}, but in order to be compatible with the previous serialization implement, + * we use {@link ArrayList} to express sparse arrays.
When a hole is encountered, null is + * used to fill it. + * @return array + */ + private List readSparseArray() { + long length = reader.getVarint(); + List array = new ArrayList<>(); + assignId(array); + byte tag; + int read = 0; + while ((tag = readTag()) != SerializationTag.END_SPARSE_JS_ARRAY) { + read++; + Object key = readValue(tag, StringLocation.SPARSE_ARRAY_KEY, null); + Object value = readValue(StringLocation.SPARSE_ARRAY_ITEM, key); + int index = -1; + if (key instanceof Number) { + index = ((Number) key).intValue(); + } else if (key instanceof String) { + try { + index = Integer.parseInt((String) key); + } catch (NumberFormatException ignored) { + // ignore not parsable string + } + } + if (index >= 0) { + int spaceNeeded = (index + 1) - array.size(); + if (spaceNeeded + == 1) { // Fast path, item are ordered in general ECMAScript(VM) implementation + array.add(value); + } else { // Slow path, universal + for (int i = 0; i < spaceNeeded; i++) { + array.add(null); + } + array.set(index, value); + } + } + } + int expected = (int) reader.getVarint(); + if (read != expected) { + throw new UnexpectedException("unexpected number of properties"); + } + long length2 = reader.getVarint(); + if (length != length2) { + throw new AssertionError("length ambiguity"); + } + return array; + } + @Override protected Object getHole() { return null; diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/serialization/SerializationTag.java b/renderer/native/android/src/main/java/com/tencent/renderer/serialization/SerializationTag.java index f0e8bfe2a..8b7564467 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/serialization/SerializationTag.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/serialization/SerializationTag.java @@ -29,4 +29,6 @@ public interface SerializationTag { byte END_OBJECT = (byte) '{'; byte BEGIN_DENSE_ARRAY = (byte) 'A'; byte END_DENSE_ARRAY = (byte) '$'; + byte BEGIN_SPARSE_JS_ARRAY = (byte) 'a'; // kBeginSparseJSArray + byte END_SPARSE_JS_ARRAY = (byte) '@'; // kEndSparseJSArray }