[SabreAMF] String references serializing AMF3
Jim Mischel
jim at mischel.com
Tue Nov 14 19:09:34 EST 2006
I'll get back with you on this one tomorrow. My partner who's working
on the other end (he's doing the Flash stuff and I'm doing the PHP
stuff) said that it worked, but I'm pretty sure he didn't make the test
that you suggest.
My (admittedly limited) understanding of ActionScript 3 is that the
language doesn't have the concept of two strings referencing the same
data, but I could be wrong. The limited AMF3 documentation available at
http://www.osflash.org/amf3/index isn't specific on the meaning of
"reference", but the way that your deserialization code is written leads
me to believe that the references are as I described.
I'll find out for sure tomorrow.
Jim
Evert | Rooftop wrote:
> Are you sure though.. that this won't end up in actionscript as
> multiple variables referencing the same data..
>
> If your example would be generated by PHP, and end up in
> actionscript.., and say I would do..
>
> object.payload1 = 'this is not a test';
>
> alert(object.payload2); // if its an actionscript reference, this will
> say 'this is not a test'
>
> Is there a document available that will confirm this, or is this your
> personal experience?
>
> Just like to be sure about this.. otherwise we might end up with
> really weird bugs.. Especially since for example mysql returns every
> field as a string.. so even row-id's will end up in the reference table..
>
> Evert
>
> Jim Mischel wrote:
>
>> Actually, I don't think this is a problem. The "references" in AMF
>> are really just a simple compression method that prevents you from
>> including the same text string multiple times in an AMF message. For
>> example, consider an object (this isn't valid PHP or
>> ActionScript--just pseudo-code):
>>
>> object
>> var id = 2;
>> var command = "connect";
>> var payload1 = "this is a test";
>> var payload2 = "this is a test";
>> var payload3 = "this is a test";
>> var payload4 = "this is a test";
>> var payload5 = "this is a test";
>> var payload6 = "this is a test";
>> end object
>>
>> The naive way of transmitting this object is to send the string "this
>> is a test" six times: once for each field. But if you construct
>> this object in Flash and look at the generated AMF, you'll see that
>> it only sends the string one time and passes a reference (just a
>> string index) for the other five occurrences:
>>
>> 0000: 0A 0B 01 0F 63 6F 6D 6D - 61 6E 64 06 0F 63 6F 6E
>> ....command..con
>> 0010: 6E 65 63 74 11 70 61 79 - 6C 6F 61 64 33 06 1D 74
>> nect.payload3..t
>> 0020: 68 69 73 20 69 73 20 61 - 20 74 65 73 74 11 70 61
>> his.is.a.test.pa
>> 0030: 79 6C 6F 61 64 34 06 06 - 05 69 64 04 02 11 70 61
>> yload4...id...pa
>> 0040: 79 6C 6F 61 64 36 06 06 - 11 70 61 79 6C 6F 61 64
>> yload6...payload
>> 0050: 32 06 06 11 70 61 79 6C - 6F 61 64 35 06 06 11 70
>> 2...payload5...p
>> 0060: 61 79 6C 6F 61 64 31 06 - 06 01
>> ayload1.........
>>
>> This "reference" isn't saying that one varible is a reference to the
>> other, but rather that one variable's value is identical to the
>> other. This deserializes in PHP to what you would expect, and
>> changing the value of payload1 won't change the value of payload2 or
>> any of the others.
>>
>> When Flash deserializes this, it does the same thing: it assigns the
>> value "this is a test" to each of the individual strings, but doesn't
>> make them refer to each other.
>>
>> It turns out that modifying writeString() (in
>> SabreAMF/AMF3/Serializer.php) was pretty easy. I've not tested it
>> fully yet, but this appears to work:
>>
>> /**
>> * writeString
>> *
>> * @param string $str
>> * @return void
>> */
>> public function writeString($str) {
>>
>> // Check for this string in the storedStrings array.
>> $key = NULL;
>> for ($i = 0; $i < sizeof($this->storedStrings); $i++)
>> {
>> if ($str === $this->storedStrings[$i])
>> {
>> $key = $i;
>> break;
>> }
>> }
>> if (is_null($key))
>> {
>> // string not stored. Store it and send as a literal.
>> $strref = strlen($str) << 1 | 0x01;
>> $this->writeInt($strref);
>> // Add to the storedStrings array and write.
>> // But don't add empty strings or bother to write them.
>> if ($str != "")
>> {
>> $this->storedStrings[] = $str;
>> $this->stream->writeBuffer($str);
>> //printf("String %d = %s\n",
>> sizeof($this->storedStrings)-1, $str);
>> }
>> }
>> else
>> {
>> // the string already exists. Store the key.
>> //printf("String reference %d\n", $key);
>> $strref = ($key << 1);
>> $this->writeInt($strref);
>> }
>> }
>>
>> That assumes, of course, that you've defined this array in the
>> SabreAMF_AMF3_Serializer class:
>>
>> /**
>> * storedStrings
>> *
>> * @var array
>> */
>> private $storedStrings = array();
>>
>> Jim
>>
>>
>> Evert | Rooftop wrote:
>>
>>> Update: there doesn't seem to be a way to check if 2 scalar
>>> variables reference the same data. So I would say, don't implement
>>> this.. Could be a really bad idea.
>>>
>>> For objects it is possible (and should probably be done), because
>>> you can do a simple == check.
>>>
>>> I'll implement that one of these days.. Along with the fixes you
>>> provided I'll put out a 0.5..
>>>
>>> To the other people on this list: if you got a feature request, be
>>> sure to let me know.. I'll create a roadmap for 1.0 soon, so people
>>> know what they can expect.
>>>
>>> Evert
>>>
>>> Evert | Rooftop wrote:
>>>
>>>
>>>> There's one big problem with this..
>>>>
>>>> You have to check if 2 strings are actually references to each
>>>> other.. If this is not the case, unexpected things might happen. If
>>>> you do a simple check if 2 strings contain the same data, the data
>>>> will end up in flex as references to each other..
>>>>
>>>> If you would then change 'stringA', 'stringB' automatically gets
>>>> changed. I've never really needed to check if 2 variables are
>>>> referencingo the same thing in PHP, but I also could not find it in
>>>> the manual..
>>>>
>>>> I'm going to see if I can get a bit more info on this.
>>>>
>>>> Evert
>>>>
>>>> Evert | Rooftop wrote:
>>>>
>>>>
>>>>> If your up for it, i'd happily accept a patch! I can also give you
>>>>> write access to subversion if you'd like to..
>>>>>
>>>>> Jim Mischel wrote:
>>>>>
>>>>>
>>>>>> SabreAMF currently does not cache strings and create references
>>>>>> when serializing AMF3. The writeString() function in
>>>>>> SabreAMF/AMF3/Serializer.php always writes the literal string.
>>>>>> It doesn't look terribly difficult to cache the strings so that
>>>>>> writeString() can create references if needed. Has anybody done
>>>>>> this? If so, I'd like to see the code. If not, I'll code it up.
>>>>>>
>>>>>> Jim
>>>>>>
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> sabreamf mailing list
>>>>>> sabreamf at osflash.org
>>>>>> http://osflash.org/mailman/listinfo/sabreamf_osflash.org
>>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> sabreamf mailing list
>>>>> sabreamf at osflash.org
>>>>> http://osflash.org/mailman/listinfo/sabreamf_osflash.org
>>>>>
>>>>
>>>> _______________________________________________
>>>> sabreamf mailing list
>>>> sabreamf at osflash.org
>>>> http://osflash.org/mailman/listinfo/sabreamf_osflash.org
>>>>
>>>
>>>
>>>
>>> _______________________________________________
>>> sabreamf mailing list
>>> sabreamf at osflash.org
>>> http://osflash.org/mailman/listinfo/sabreamf_osflash.org
>>>
>>>
>>>
>>
>
>
>
More information about the sabreamf
mailing list