13693261870
2022-09-16 354b3dbfbffb3df45212a2a44dbbf48b4acc2594
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>The source code</title>
  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  <style type="text/css">
    .highlight { display: block; background-color: #ddd; }
  </style>
  <script type="text/javascript">
    function highlight() {
      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
    }
  </script>
</head>
<body onload="prettyPrint(); highlight();">
  <pre class="prettyprint lang-js">// @tag enterprise
<span id='Ext-data-amf-Packet'>/**
</span> * @class Ext.data.amf.Packet
 * This class represents an Action Message Format (AMF) Packet.  It contains all
 * the logic required to decode an AMF Packet from a byte array.
 * To decode a Packet, first construct a Packet:
 *
 *     var packet = Ext.create('Ext.data.amf.Packet');
 *
 * Then use the decode method to decode an AMF byte array:
 *
 *     packet.decode(bytes);
 *
 * where &quot;bytes&quot; is a Uint8Array or an array of numbers representing the binary
 * AMF data.
 *
 * To access the decoded data use the #version, #headers, and #messages properties:
 *
 *     console.log(packet.version, packet.headers, packet.messages);
 *
 * For more information on working with AMF data please refer to the
 * [AMF Guide](#/guide/amf).
 */
Ext.define('Ext.data.amf.Packet', function() {
    var twoPowN52 = Math.pow(2, -52),
        twoPow8 = Math.pow(2, 8),
        pos = 0,
        bytes, strings, objects, traits;
 
    return {
<span id='Ext-data-amf-Packet-property-headers'>        /**
</span>         * @property {Array} headers
         * @readonly
         * The decoded headers. Each header has the following properties:
         *
         * - `name`: String
         * The header name. Typically identifies a remote operation or method to
         * be invoked by this context header.
         * - `mustUnderstand`: Boolean
         * If `true` this flag instructs the endpoint to abort and generate an
         * error if the header is not understood.
         * - `byteLength`: Number
         * If the byte-length of a header is known it can be specified to optimize
         * memory allocation at the remote endpoint.
         * - `value`: Mixed
         * The header value
         */
 
<span id='Ext-data-amf-Packet-property-messages'>        /**
</span>         * @property {Array} messages
         * @readonly
         * The decoded messages. Each message has the following properties:
         *
         * - `targetURI`: String
         * Describes which operation, function, or method is to be remotely
         * invoked.
         * - `responseURI`: String
         * A unique operation name
         * - `byteLength`: Number
         * Optional byte-length of the message body
         * - `body`: Mixed
         * The message body
         */
 
<span id='Ext-data-amf-Packet-property-version'>        /**
</span>         * @property {Number} version
         * @readonly
         * The AMF version number (0 or 3)
         */
 
<span id='Ext-data-amf-Packet-property-typeMap'>        /**
</span>         * Mapping of AMF data types to the names of the methods responsible for
         * reading them.
         * @private
         */
        typeMap: {
            // AMF0 mapping
            0: {
                0: 'readDouble',
                1: 'readBoolean',
                2: 'readAmf0String',
                3: 'readAmf0Object',
                5: 'readNull',
                6: 'readUndefined',
                7: 'readReference',
                8: 'readEcmaArray',
                10: 'readStrictArray',
                11: 'readAmf0Date',
                12: 'readLongString',
                13: 'readUnsupported',
                15: 'readAmf0Xml',
                16: 'readTypedObject'
            },
            // AMF3 mapping
            3: {
                0: 'readUndefined',
                1: 'readNull',
                2: 'readFalse',
                3: 'readTrue',
                4: 'readUInt29',
                5: 'readDouble',
                6: 'readAmf3String',
                7: 'readAmf3Xml',
                8: 'readAmf3Date',
                9: 'readAmf3Array',
                10: 'readAmf3Object',
                11: 'readAmf3Xml',
                12: 'readByteArray'
            }
        },
 
<span id='Ext-data-amf-Packet-method-decode'>        /**
</span>         * Decodes an AMF btye array and sets the decoded data as the
         * Packet's #version, #headers, and #messages properties
         * @param {Array} byteArray A byte array containing the encoded AMF data.
         * @return {Ext.data.amf.Packet} this AMF Packet
         */
        decode: function(byteArray) {
            var me = this,
                headers = me.headers = [],
                messages = me.messages = [],
                headerCount, messageCount;
 
            pos = 0;
 
            bytes = me.bytes = byteArray;
 
            // The strings array holds references to all of the deserialized
            // AMF3 strings for a given header value or message body so that
            // repeat instances of the same string can be deserialized by
            // reference
            strings = me.strings = [];
 
            // The objects array holds references to deserialized objects so
            // that repeat occurrences of the same object instance in the byte
            // array can be deserialized by reference.
            // If version is AMF0 this array holds anonymous objects, typed
            // objects, arrays, and ecma-arrays.
            // If version is AMF3 this array holds instances of Object, Array, XML,
            // XMLDocument, ByteArray, Date, and instances of user defined Classes
            objects = me.objects = [];
 
            // The traits array holds references to the &quot;traits&quot; (the
            // characteristics of objects that define a strong type such as the
            // class name and public member names) of deserialized AMF3 objects
            // so that if they are repeated they can be deserialized by reference.
            traits = me.traits = [];
 
            // The first two bytes of an AMF packet contain the AMF version
            // as an unsigned 16 bit integer.
            me.version = me.readUInt(2);
 
            // the next 2 bytes contain the header count
            for (headerCount = me.readUInt(2); headerCount--;) {
                headers.push({
                    name: me.readAmf0String(),
                    mustUnderstand: me.readBoolean(),
                    byteLength: me.readUInt(4),
                    value: me.readValue()
                });
                // reset references (reference indices are local to each header)
                strings = me.strings = [];
                objects = me.objects = [];
                traits = me.traits = [];
            }
 
            // The 2 bytes immediately after the header contain the message count.
            for (messageCount = me.readUInt(2); messageCount--;) {
                messages.push({
                    targetURI: me.readAmf0String(),
                    responseURI: me.readAmf0String(),
                    byteLength: me.readUInt(4),
                    body: me.readValue()
                });
                // reset references (reference indices are local to each message)
                strings = me.strings = [];
                objects = me.objects = [];
                traits = me.traits = [];
            }
 
            // reset the pointer
            pos = 0;
            // null the bytes array and reference arrays to free up memory.
            bytes = strings = objects = traits =
                me.bytes = me.strings = me.objects = me.traits = null;
 
            return me;
        },
 
 
<span id='Ext-data-amf-Packet-method-decodeValue'>        /**
</span>         * Decodes an AMF3 byte array and that has one value and returns it.
         * Note: Destroys previously stored data in this Packet.
         * @param {Array} byteArray A byte array containing the encoded AMF data.
         * @return {Object} the decoded object
         */
        decodeValue: function(byteArray) {
            var me = this;
 
            bytes = me.bytes = byteArray;
 
            // reset the pointer
            pos = 0;
 
            // The first two bytes of an AMF packet contain the AMF version
            // as an unsigned 16 bit integer.
            me.version = 3;
 
            // The strings array holds references to all of the deserialized
            // AMF3 strings for a given header value or message body so that
            // repeat instances of the same string can be deserialized by
            // reference
            strings = me.strings = [];
 
            // The objects array holds references to deserialized objects so
            // that repeat occurrences of the same object instance in the byte
            // array can be deserialized by reference.
            // If version is AMF0 this array holds anonymous objects, typed
            // objects, arrays, and ecma-arrays.
            // If version is AMF3 this array holds instances of Object, Array, XML,
            // XMLDocument, ByteArray, Date, and instances of user defined Classes
            objects = me.objects = [];
 
            // The traits array holds references to the &quot;traits&quot; (the
            // characteristics of objects that define a strong type such as the
            // class name and public member names) of deserialized AMF3 objects
            // so that if they are repeated they can be deserialized by reference.
            traits = me.traits = [];
 
            // read one value and return it
            return me.readValue();
        },
 
 
 
<span id='Ext-data-amf-Packet-method-parseXml'>        /**
</span>         * Parses an xml string and returns an xml document
         * @private
         * @param {String} xml
         */
        parseXml: function(xml) {
            var doc;
 
            if (window.DOMParser) {
                doc = (new DOMParser()).parseFromString(xml, &quot;text/xml&quot;);
            } else {
                doc = new ActiveXObject(&quot;Microsoft.XMLDOM&quot;);
                doc.loadXML(xml);
            }
 
            return doc;
        },
 
<span id='Ext-data-amf-Packet-method-readAmf0Date'>        /**
</span>         * Reads an AMF0 date from the byte array
         * @private
         */
        readAmf0Date: function() {
            var date = new Date(this.readDouble());
            // An AMF0 date type ends with a 16 bit integer time-zone, but
            // according to the spec time-zone is &quot;reserved, not supported,
            // should be set to 0x000&quot;.
            pos += 2; // discard the time zone
            return date;
        },
 
<span id='Ext-data-amf-Packet-method-readAmf0Object'>        /**
</span>         * Reads an AMF0 Object from the byte array
         * @private
         */
        readAmf0Object: function(obj) {
            var me = this,
                key;
 
            obj = obj || {};
 
            // add the object to the objects array so that the AMF0 reference
            // type decoder can refer to it by index if needed.
            objects.push(obj);
 
            // An AMF0 object consists of a series of string keys and variable-
            // type values.  The end of the series is marked by an empty string
            // followed by the object-end marker (9).
            while ((key = me.readAmf0String()) || bytes[pos] !== 9) {
                obj[key] = me.readValue();
            }
 
            // move the pointer past the object-end marker
            pos++;
 
            return obj;
        },
 
<span id='Ext-data-amf-Packet-method-readAmf0String'>        /**
</span>         * Reads an AMF0 string from the byte array
         * @private
         */
        readAmf0String: function() {
            // AMF0 strings begin with a 16 bit byte-length header.
            return this.readUtf8(this.readUInt(2));
        },
 
        readAmf0Xml: function() {
            return this.parseXml(this.readLongString());
        },
 
        readAmf3Array: function() {
            var me = this,
                header = me.readUInt29(),
                count, key, array, i;
 
            // AMF considers Arrays in two parts, the dense portion and the
            // associative portion. The binary representation of the associative
            // portion consists of name/value pairs (potentially none) terminated
            // by an empty string. The binary representation of the dense portion
            // is the size of the dense portion (potentially zero) followed by an
            // ordered list of values (potentially none).
            if (header &amp; 1) {
                // If the first (low) bit is a 1 read an array instance.  The
                // remaining 1-28 bits are used to encode the length of the
                // dense portion of the array.
                count = (header &gt;&gt; 1);
                // First read the associative portion of the array (if any).  If
                // there is an associative portion, the array will be read as a
                // javascript object, otherwise it will be a javascript array.
                key = me.readAmf3String();
                if (key) {
                    // First key is not an empty string - this is an associative
                    // array.  Read keys and values from the byte array until
                    // we get to an empty string key
                    array = {};
                    objects.push(array);
                    do {
                        array[key] = me.readValue();
                    } while((key = me.readAmf3String()));
                    // The dense portion of the array is then read into the
                    // associative object, keyed by ordinal index.
                    for (i = 0; i &lt; count; i++) {
                        array[i] = me.readValue();
                    }
                } else {
                    // First key is an empty string - this is an array with
                    // ordinal indices.
                    array = [];
                    objects.push(array);
                    for (i = 0; i &lt; count; i++) {
                        array.push(me.readValue());
                    }
                }
            } else {
                // If the first (low) bit is a 0 read an array reference. The
                // remaining 1-28 bits are used to encode the reference index
                array = objects[header &gt;&gt; 1];
            }
 
            return array;
        },
 
<span id='Ext-data-amf-Packet-method-readAmf3Date'>        /**
</span>         * Reads an AMF3 date from the byte array
         * @private
         */
        readAmf3Date: function() {
            var me = this,
                header = me.readUInt29(),
                date;
 
            if (header &amp; 1) {
                // If the first (low) bit is a 1, this is a date instance.
                date = new Date(me.readDouble());
                objects.push(date);
            } else {
                // If the first (low) bit is a 0, this is a date reference.
                // The remaining 1-28 bits encode the reference index
                date = objects[header &gt;&gt; 1];
            }
 
            return date;
        },
 
<span id='Ext-data-amf-Packet-method-readAmf3Object'>        /**
</span>         * Reads an AMF3 object from the byte array
         * @private
         */
        readAmf3Object: function() {
            var me = this,
                header = me.readUInt29(),
                members = [],
                headerLast3Bits, memberCount, className,
                dynamic, objectTraits, obj, key, klass, i;
 
            // There are 3 different types of object headers, distinguishable
            // by the 1-3 least significant bits.  All object instances have
            // a 1 in the low bit position, while references have a 0:
            //
            // 0    : object reference
            // 011  : traits
            // 01   : traits-ref
            // 111  : traits-ext
            if (header &amp; 1) {
                // first (low) bit of 1, denotes an encoded object instance
                // The next string is the class name.
                headerLast3Bits = (header &amp; 0x07);
                if (headerLast3Bits === 3) {
                    // If the 3 least significant bits of the header are &quot;011&quot;
                    // then trait information follows.
                    className = me.readAmf3String();
                    // A 1 in the header's 4th least significant byte position
                    // indicates that dynamic members may follow the sealed
                    // members.
                    dynamic = !!(header &amp; 0x08);
                    // Shift off the 4 least significant bits, and the remaining
                    // 1-25 bits encode the number of sealed member names. Read
                    // as many strings from the byte array as member names.
                    memberCount = (header &gt;&gt; 4);
                    for (i = 0; i &lt; memberCount; i++) {
                        members.push(me.readAmf3String());
                    }
                    objectTraits = {
                        className: className,
                        dynamic: dynamic,
                        members: members
                    };
                    // An objects traits are cached in the traits array enabling
                    // the traits for a given class to only be encoded once for
                    // a series of instances.
                    traits.push(objectTraits);
                } else if ((header &amp; 0x03) === 1) {
                    // If the 2 least significant bits are &quot;01&quot;, then a traits
                    // reference follows.  The remaining 1-27 bits are used
                    // to encode the trait reference index.
                    objectTraits = traits[header &gt;&gt; 2];
                    className = objectTraits.className;
                    dynamic = objectTraits.dynamic;
                    members = objectTraits.members;
                    memberCount = members.length;
                } else if (headerLast3Bits === 7) {
                    // if the 3 lease significant bits are &quot;111&quot; then
                    // externalizable trait data follows
 
                    // TODO: implement externalizable traits
                }
 
                if (className) {
                    klass = Ext.ClassManager.getByAlias('amf.' + className);
                    obj = klass ? new klass() : {$className: className};
                } else {
                    obj = {};
                }
                objects.push(obj);
 
                // read the sealed member values
                for (i = 0; i &lt; memberCount; i++) {
                    obj[members[i]] = me.readValue();
                }
 
                if (dynamic) {
                    // If the dynamic flag is set, dynamic members may follow
                    // the sealed members. Read key/value pairs until we
                    // encounter an empty string key signifying the end of the
                    // dynamic members.
                    while ((key = me.readAmf3String())) {
                        obj[key] = me.readValue();
                    }
                }
 
                // finally, check if we need to convert this class
                if ((!klass) &amp;&amp; this.converters[className]) {
                    obj = this.converters[className](obj);
                }
 
            } else {
                // If the first (low) bit of the header is a 0, this is an
                // object reference. The remaining 1-28 significant bits are
                // used to encode an object reference index.
                obj = objects[header &gt;&gt; 1];
            }
 
            return obj;
        },
 
<span id='Ext-data-amf-Packet-method-readAmf3String'>        /**
</span>         * Reads an AMF3 string from the byte array
         * @private
         */
        readAmf3String: function() {
            var me = this,
                header = me.readUInt29(),
                value;
 
            if (header &amp; 1) {
                // If the first (low) bit is a 1, this is a string literal.
                // Discard the low bit.  The remaining 1-28 bits are used to
                // encode the string's byte-length.
                value = me.readUtf8(header &gt;&gt; 1);
                if (value) {
                    // the emtpy string is never encoded by reference
                    strings.push(value);
                }
                return value;
            } else {
                // If the first (low) bit is a 0, this is a string reference.
                // Discard the low bit, then look up and return the reference
                // from the strings array using the remaining 1-28 bits as the
                // index.
                return strings[header &gt;&gt; 1];
            }
        },
 
<span id='Ext-data-amf-Packet-method-readAmf3Xml'>        /**
</span>         * Reads an AMF3 XMLDocument type or XML type from the byte array
         * @private
         */
        readAmf3Xml: function() {
            var me = this,
                header = me.readUInt29(),
                doc;
 
            if (header &amp; 1) {
                // If the first (low) bit is a 1, this is an xml instance. The
                // remaining 1-28 bits encode the byte-length of the xml string.
                doc = me.parseXml(me.readUtf8(header &gt;&gt; 1));
                objects.push(doc);
            } else {
                // if the first (low) bit is a 1, this is an xml reference. The
                // remaining 1-28 bits encode the reference index.
                doc = objects[header &gt;&gt; 1];
            }
 
            return doc;
        },
 
<span id='Ext-data-amf-Packet-method-readBoolean'>        /**
</span>         * Reads an AMF0 boolean from the byte array
         * @private
         */
        readBoolean: function() {
            return !!bytes[pos++];
        },
 
<span id='Ext-data-amf-Packet-method-readByteArray'>        /**
</span>         * Reads an AMF3 ByteArray type from the byte array
         * @private
         */
        readByteArray: function() {
            var header = this.readUInt29(),
                byteArray, end;
 
            if (header &amp; 1) {
                // If the first (low) bit is a 1, this is a ByteArray instance.
                // The remaining 1-28 bits encode the ByteArray's byte-length.
                end = pos + (header &gt;&gt; 1);
                // Depending on the browser, &quot;bytes&quot; may be either a Uint8Array
                // or an Array.  Uint8Arrays don't have Array methods, so
                // we have to use Array.prototype.slice to get the byteArray
                byteArray = Array.prototype.slice.call(bytes, pos, end);
                objects.push(byteArray);
                // move the pointer to the first byte after the byteArray that
                // was just read
                pos = end;
            } else {
                // if the first (low) bit is a 1, this is a ByteArray reference.
                // The remaining 1-28 bits encode the reference index.
                byteArray = objects[header &gt;&gt; 1];
            }
 
            return byteArray;
        },
 
<span id='Ext-data-amf-Packet-method-readDouble'>        /**
</span>         * Reads a IEEE 754 double-precision binary floating-point number
         * @private
         */
        readDouble: function() {
            var byte1 = bytes[pos++],
                byte2 = bytes[pos++],
                // the first bit of byte1 is the sign (0 = positive, 1 = negative.
                // We read this bit by shifting the 7 least significant bits of
                // byte1 off to the right.
                sign = (byte1 &gt;&gt; 7) ? -1 : 1,
                // the exponent takes up the next 11 bits.
                exponent =
                    // extract the 7 least significant bits from byte1 and then
                    // shift them left by 4 bits to make room for the 4 remaining
                    // bits from byte 2
                    (((byte1 &amp; 0x7F) &lt;&lt; 4)
                     // add the 4 most significant bits from byte 2 to complete
                     // the exponent
                     | (byte2 &gt;&gt; 4)),
                // the remaining 52 bits make up the significand. read the 4
                // least significant bytes of byte 2 to begin the significand
                significand = (byte2 &amp; 0x0F),
                // The most significant bit of the significand is always 1 for
                // a normalized number, therefore it is not stored. This bit is
                // referred to as the &quot;hidden bit&quot;. The true bit width of the
                // significand is 53 if you include the hidden bit. An exponent
                // of 0 indicates that this is a subnormal number, and subnormal
                // numbers always have a 0 hidden bit.
                hiddenBit = exponent ? 1 : 0,
                i = 6;
 
            // The operands of all bitwise operators in javascript are converted
            // to signed 32 bit integers.  It is therefore impossible to construct
            // the 52 bit significand by repeatedly shifting its bits and then
            // bitwise OR-ing the result with the the next byte. To work around
            // this issue, we repeatedly multiply the significand by 2^8 which
            // produces the same result as (significand &lt;&lt; 8), then we add the
            // next byte, which has the same result as a bitwise OR.
            while (i--) {
                significand = (significand * twoPow8) + bytes[pos++];
            }
 
            if (!exponent) {
                if (!significand) {
                    // if both exponent and significand are 0, the number is 0
                    return 0;
                }
                // If the exponent is 0, but the significand is not 0, this
                // is a subnormal number. Subnormal numbers are encoded with a
                // biased exponent of 0, but are interpreted with the value of
                // the smallest allowed exponent, which is one greater.
                exponent = 1;
            }
 
            // 0x7FF (2047) is a special exponent value that represents infinity
            // if the significand is 0, and NaN if the significand is not 0
            if (exponent === 0x7FF) {
                return significand ? NaN : (Infinity * sign);
            }
 
            return sign *
                // The exponent is encoded using an offset binary
                // representation with the zero offset being 0x3FF (1023),
                // so we have to subtract 0x3FF to get the true exponent
                Math.pow(2, exponent - 0x3FF) *
                // convert the significand to its decimal value by multiplying
                // it by 2^52 and then add the hidden bit
                (hiddenBit + twoPowN52 * significand);
        },
 
<span id='Ext-data-amf-Packet-method-readEcmaArray'>        /**
</span>         * Reads an AMF0 ECMA Array from the byte array
         * @private
         */
        readEcmaArray: function() {
            // An ecma array type is encoded exactly like an anonymous object
            // with the exception that it has a 32 bit &quot;count&quot; at the beginning.
            // We handle emca arrays by just throwing away the count and then
            // letting the object decoder handle the rest.
            pos += 4;
            return this.readAmf0Object();
        },
 
<span id='Ext-data-amf-Packet-method-readFalse'>        /**
</span>         * Returns false.  Used for reading the false type
         * @private
         */
        readFalse: function() {
            return false;
        },
 
<span id='Ext-data-amf-Packet-method-readLongString'>        /**
</span>         * Reads a long string (longer than 65535 bytes) from the byte array
         * @private
         */
        readLongString: function() {
            // long strings begin with a 32 bit byte-length header.
            return this.readUtf8(this.readUInt(4));
        },
 
<span id='Ext-data-amf-Packet-method-readNull'>        /**
</span>         * Returns null.  Used for reading the null type
         * @private
         */
        readNull: function() {
            return null;
        },
 
<span id='Ext-data-amf-Packet-method-readReference'>        /**
</span>         * Reads a reference from the byte array.  Reference types are used to
         * avoid duplicating data if the same instance of a complex object (which
         * is defined in AMF0 as an anonymous object, typed object, array, or
         * ecma-array) is included in the data more than once.
         * @private
         */
        readReference: function() {
            // a reference type contains a single 16 bit integer that represents
            // the index of an already deserialized object in the objects array
            return objects[this.readUInt(2)];
        },
 
<span id='Ext-data-amf-Packet-method-readStrictArray'>        /**
</span>         * Reads an AMF0 strict array (an array with ordinal indices)
         * @private
         */
        readStrictArray: function() {
            var me = this,
                len = me.readUInt(4),
                arr = [];
 
            objects.push(arr);
 
            while (len--) {
                arr.push(me.readValue());
            }
 
            return arr;
        },
 
<span id='Ext-data-amf-Packet-method-readTrue'>        /**
</span>         * Returns true.  Used for reading the true type
         * @private
         */
        readTrue: function() {
            return true;
        },
 
<span id='Ext-data-amf-Packet-method-readTypedObject'>        /**
</span>         * Reads an AMF0 typed object from the byte array
         * @private
         */
        readTypedObject: function() {
            var me = this,
                className = me.readAmf0String(),
                klass, instance, modified;
 
            klass = Ext.ClassManager.getByAlias('amf.' + className);
            instance = klass ? new klass() : {$className: className}; // if there is no klass, mark the classname for easier parsing of returned results
 
            modified = me.readAmf0Object(instance);
 
            // check if we need to convert this class
            if ((!klass) &amp;&amp; this.converters[className]) {
                modified = this.converters[className](instance);
            }
            return modified;
        },
 
<span id='Ext-data-amf-Packet-method-readUInt'>        /**
</span>         * Reads an unsigned integer from the byte array
         * @private
         * @param {Number} byteCount the number of bytes to read, e.g. 2 to read
         * a 16 bit integer, 4 to read a 32 bit integer, etc.
         * @return {Number}
         */
        readUInt: function(byteCount) {
            var i = 1,
                result;
 
            // read the first byte
            result = bytes[pos++];
            // if this is a multi-byte int, loop over the remaining bytes
            for (; i &lt; byteCount; ++i) {
                // shift the result 8 bits to the left and add the next byte.
                result = (result &lt;&lt; 8) | bytes[pos++];
            }
 
            return result;
        },
 
<span id='Ext-data-amf-Packet-method-readUInt29'>        /**
</span>         * Reads an unsigned 29-bit integer from the byte array.
         * AMF 3 makes use of a special compact format for writing integers to
         * reduce the number of bytes required for encoding. As with a normal
         * 32-bit integer, up to 4 bytes are required to hold the value however
         * the high bit of the first 3 bytes are used as flags to determine
         * whether the next byte is part of the integer. With up to 3 bits of
         * the 32 bits being used as flags, only 29 significant bits remain for
         * encoding an integer. This means the largest unsigned integer value
         * that can be represented is 2^29-1.
         *
         *           (hex)         :                (binary)
         * 0x00000000 - 0x0000007F :  0xxxxxxx
         * 0x00000080 - 0x00003FFF :  1xxxxxxx 0xxxxxxx
         * 0x00004000 - 0x001FFFFF :  1xxxxxxx 1xxxxxxx 0xxxxxxx
         * 0x00200000 - 0x3FFFFFFF :  1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx
         * @private
         * @return {Number}
         */
        readUInt29: function() {
            var value = bytes[pos++],
                nextByte;
 
            if (value &amp; 0x80) {
                // if the high order bit of the first byte is a 1, the next byte
                // is also part of this integer.
                nextByte = bytes[pos++];
                // remove the high order bit from both bytes before combining them
                value = ((value &amp; 0x7F) &lt;&lt; 7) | (nextByte &amp; 0x7F);
                if (nextByte &amp; 0x80) {
                    // if the high order byte of the 2nd byte is a 1, then
                    // there is a 3rd byte
                    nextByte = bytes[pos++];
                    // remove the high order bit from the 3rd byte before
                    // adding it to the value
                    value = (value &lt;&lt; 7) | (nextByte &amp; 0x7F);
                    if (nextByte &amp; 0x80) {
                        // 4th byte is also part of the integer
                        nextByte = bytes[pos++];
                        // use all 8 bits of the 4th byte
                        value = (value &lt;&lt; 8) | nextByte;
                    }
 
                }
            }
 
            return value;
        },
 
<span id='Ext-data-amf-Packet-method-readUndefined'>        /**
</span>         * Returns undefined.  Used for reading the undefined type
         * @private
         */
        readUndefined: Ext.emptyFn,
 
<span id='Ext-data-amf-Packet-method-readUnsupported'>        /**
</span>         * Returns undefined.  Used for reading the unsupported type
         * @private
         */
        readUnsupported: Ext.emptyFn,
 
<span id='Ext-data-amf-Packet-method-readUtf8'>        /**
</span>         * Reads a UTF-8 string from the byte array
         * @private
         * @param {Number} byteLength The number of bytes to read
         * @return {String}
         */
        readUtf8: function(byteLength) {
            var end = pos + byteLength, // the string's end position
                chars = [],
                charCount = 0,
                maxCharCount = 65535,
                charArrayCount = 1,
                result = [],
                i = 0,
                charArrays, byteCount, charCode;
 
            charArrays = [chars];
 
            // UTF-8 characters may be encoded using 1-4 bytes. The number of
            // bytes that a character consumes is determined by reading the
            // leading byte.  Values 0-127 in the leading byte indicate a single-
            // byte ASCII-compatible character. Values 192-223 (bytes with &quot;110&quot;
            // in the high-order position) indicate a 2-byte character, values
            // 224-239 (bytes with &quot;1110&quot; in the high-order position) indicate a
            // 3-byte character, and values 240-247 (bytes with &quot;11110&quot; in the
            // high-order position) indicate a 4-byte character. The remaining
            // bits of the leading byte hold bits of the encoded character, with
            // leading zeros if necessary.
            //
            // The continuation bytes all have &quot;10&quot; in the high-order position,
            // which means only the 6 least significant bits of continuation
            // bytes are available to hold the bits of the encoded character.
            //
            // The following table illustrates the binary format of UTF-8
            // characters:
            //
            // Bits     Byte 1      Byte 2      Byte 3      Byte 4
            // -----------------------------------------------------
            //  7       0xxxxxxx
            // 11       110xxxxx    10xxxxxx
            // 16       1110xxxx    10xxxxxx    10xxxxxx
            // 21       11110xxx    10xxxxxx    10xxxxxx    10xxxxxx
            while (pos &lt; end) {
                // read a byte from the byte array - if the byte's value is less
                // than 128 we are dealing with a single byte character
                charCode = bytes[pos++];
                if (charCode &gt; 127) {
                    // if the byte's value is greater than 127 we are dealing
                    // with a multi-byte character.
                    if (charCode &gt; 239) {
                        // a leading-byte value greater than 239 means this is a
                        // 4-byte character
                        byteCount = 4;
                        // Use only the 3 least-significant bits of the leading
                        // byte of a 4-byte character. This is achieved by
                        // applying the following bit mask:
                        // (charCode &amp; 0x07)
                        // which is equivalent to:
                        //     11110xxx (the byte)
                        // AND 00000111 (the mask)
                        charCode = (charCode &amp; 0x07);
                    } else if (charCode &gt; 223) {
                        // a leading-byte value greater than 223 but less than
                        // 240 means this is a 3-byte character
                        byteCount = 3;
                        // Use only the 4 least-significant bits of the leading
                        // byte of a 3-byte character. This is achieved by
                        // applying the following bit mask:
                        // (charCode &amp; 0x0F)
                        // which is equivalent to:
                        //     1110xxxx (the byte)
                        // AND 00001111 (the mask)
                        charCode = (charCode &amp; 0x0F);
                    } else {
                        // a leading-byte value less than 224 but (implicitly)
                        // greater than 191 means this is a 2-byte character
                        byteCount = 2;
                        // Use only the 5 least-significant bits of the first
                        // byte of a 2-byte character. This is achieved by
                        // applying the following bit mask:
                        // (charCode &amp; 0x1F)
                        // which is equivalent to:
                        //     110xxxxx (the byte)
                        // AND 00011111 (the mask)
                        charCode = (charCode &amp; 0x1F);
                    }
 
                    while (--byteCount) {
                        // get one continuation byte. then strip off the leading
                        // &quot;10&quot; by applying the following bit mask:
                        // (b &amp; 0x3F)
                        // which is equialent to:
                        //     10xxxxxx (the byte)
                        // AND 00111111 (the mask)
                        // That leaves 6 remaining bits on the continuation byte
                        // which are concatenated onto the character's bits
                        charCode = ((charCode &lt;&lt; 6) | (bytes[pos++] &amp; 0x3F));
                    }
                }
 
                chars.push(charCode);
 
                if (++charCount === maxCharCount) {
                    charArrays.push(chars = []);
                    charCount = 0;
                    charArrayCount ++;
                }
            }
 
            // At this point we end up with an array of char arrays, each char
            // array being no longer than 65,535 characters, the fastest way to
            // turn these char arrays into strings is to pass them as the
            // arguments to fromCharCode (fortunately all currently supported
            // browsers can handle at least 65,535 function arguments).
            for (; i &lt; charArrayCount; i++) {
                // create a result array containing the strings converted from
                // the individual character arrays.
                result.push(String.fromCharCode.apply(String, charArrays[i]));
            }
 
            return result.join('');
        },
 
<span id='Ext-data-amf-Packet-method-readValue'>        /**
</span>         * Reads an AMF &quot;value-type&quot; from the byte array.  Automatically detects
         * the data type by reading the &quot;type marker&quot; from the first byte after
         * the pointer.
         * @private
         */
        readValue: function() {
            var me = this,
                marker = bytes[pos++];
 
            // With the introduction of AMF3, a special type marker was added to
            // AMF0 to signal a switch to AMF3 serialization. This allows a packet
            // to start out in AMF 0 and switch to AMF 3 on the first complex type
            // to take advantage of the more the efficient encoding of AMF 3.
            if (marker === 17) {
                // change the version to AMF3 when we see a 17 marker
                me.version = 3;
                marker = bytes[pos++];
            }
 
            return me[me.typeMap[me.version][marker]]();
        },
 
<span id='Ext-data-amf-Packet-property-converters'>        /**
</span>         * Converters used in converting specific typed Flex classes to JavaScript usable form.
         * @private
         */
 
        converters: {
            'flex.messaging.io.ArrayCollection': function(obj) {
                return obj.source || []; // array collections have a source var that contains the actual data
            }
        }
 
    };
});</pre>
</body>
</html>