private function deserializeStringTable() { $typeNameCount = $this->readInt(); $buffer = new SSSR_BoundedList(String::clazz(), $typeNameCount); for ($typeNameIndex = 0; $typeNameIndex < $typeNameCount; ++$typeNameIndex) { $str = $this->extract(); // Change quoted characters back. $idx = mb_strpos($str, '\\'); if ($idx !== false) { $buf = ''; $pos = 0; while ($idx >= 0) { $buf .= mb_substr($str, $pos, $idx - $pos); if (++$idx == mb_strlen($str)) { throw new SerializationException("Unmatched backslash: \"{$str}\""); } $ch = mb_substr($str, $idx, 1); $pos = $idx + 1; switch (Character::ord($ch)) { case Character::ord('0'): $buf .= '\\u0000'; break; case Character::ord('!'): $buf .= self::RPC_SEPARATOR_CHAR; break; case Character::ord('\\'): $buf .= $ch; break; case Character::ord('u'): try { $ch = Character::chr(Integer::parseHex(mb_substr($str, $idx + 1, 4))); } catch (NumberFormatException $e) { throw new SerializationException("Invalid Unicode escape sequence \"{$str}\""); } $buf .= $ch; $pos += 4; break; default: throw new SerializationException("Unexpected escape character {$ch} after backslash: \"{$str}\""); } $idx = mb_strpos($str, '\\', $pos); } $buf .= mb_substr($str, $pos); $str = buf; } $buffer->add($str); } if ($buffer->size() != $buffer->getExpectedSize()) { throw new SerializationException('Expected ' . $buffer->getExpectedSize() . ' string table elements; received ' . $buffer->size()); } $this->stringTable = $buffer->toArray(); }
private function decodeCommand() { $command = $this->next(); if ($command == NL_CHAR) { $command = $this->next(); } $token = $this->token(); switch ($command) { case BOOLEAN_TYPE: $this->pushScalar(new BooleanValueCommand($token == '1')); break; case BYTE_TYPE: $this->pushScalar(new ByteValueCommand(Byte::valueOf($token))); break; case CHAR_TYPE: $this->pushScalar(new CharValueCommand(Character::chr(intval($token)))); break; case DOUBLE_TYPE: $this->pushScalar(new DoubleValueCommand(Double::valueOf($token))); break; case FLOAT_TYPE: $this->pushScalar(new FloatValueCommand(Float::valueOf($token))); break; case INT_TYPE: $this->pushScalar(new IntValueCommand(Integer::valueOf($token))); break; case LONG_TYPE: $this->pushScalar(new LongValueCommand(Long::valueOf($token))); break; case VOID_TYPE: $this->pushScalar(NullValueCommand::INSTANCE()); break; case SHORT_TYPE: $this->pushScalar(new ShortValueCommand(Short::valueOf($token))); break; case STRING_TYPE: // "4~abcd $length = Integer::valueOf($token); $value = $this->nextCount($length); if ($this->next() != RPC_SEPARATOR_CHAR) { throw new RuntimeException('Overran string'); } $this->pushString(new StringValueCommand($value)); break; case ENUM_TYPE: // ETypeSeedName~IOrdinal~ $ordinal = $this->readCommand('IntValueCommand')->getValue(); $clazz = $this->findClass($token); $x = new EnumValueCommand($clazz); $this->pushIdentity($x); $x->setValue($ordinal); break; case ARRAY_TYPE: // Encoded as (leafType, dimensions, length, ...) $leaf = $this->findClass($token); $numDims = $this->readCommand('IntValueCommand')->getValue(); $clazz = null; if ($numDims > 1) { $clazz = ArrayType::clazz($leaf, $numDims); } else { $clazz = $leaf; } $x = new ArrayValueCommand($clazz); $this->pushIdentity($x); $length = $this->readCommand('IntValueCommand')->getValue(); for ($i = 0; $i < $length; $i++) { $x->add($this->readCommand('ValueCommand')); } break; case OBJECT_TYPE: // LTypeSeedName~3... N-many setters ... $clazz = $this->findClass($token); $x = new InstantiateCommand($clazz); $this->pushIdentity($x); $this->readSetters($clazz, $x); break; case INVOKE_TYPE: // !TypeSeedName~Number of objects written by CFS~...CFS objects...~ // Number of extra fields~...N-many setters... $clazz = $this->findClass($token); $serializerClass = null; $manualType = $clazz; while ($manualType != null) { $serializerClass = SerializabilityUtil::hasCustomFieldSerializer($manualType); if ($serializerClass != null) { break; } $manualType = $manualType->getSuperClass(); } if ($serializerClass == null) { throw new IncompatibleRemoteServiceException('Class [' . $clazz->getName() . '] has no custom serializer on server'); } $x = new InvokeCustomFieldSerializerCommand($clazz, $serializerClass, $manualType); $this->pushIdentity($x); $this->readFields($x); $this->readSetters($clazz, $x); break; case RETURN_TYPE: // R4~...values... $this->toReturn = new ReturnCommand(); $toRead = Integer::valueOf($token); for ($i = 0; $i < $toRead; $i++) { $this->toReturn->addValue($this->readCommand('ValueCommand')); } break; case THROW_TYPE: // T...value... $this->toThrow = $this->readCommand('ValueCommand'); break; case BACKREF_TYPE: // @backrefNumber~ $x = $this->backRefs[Integer::valueOf($token)]; assert($x != null); array_push($this->commands, $x); break; case RPC_SEPARATOR_CHAR: throw new RuntimeException('Segmentation overrun at ' + $this->idx); default: throw new RuntimeException('Unknown Command ' + $command); } }