Bug Summary

File:platform/mac/avmshell/../../../core/ByteArrayGlue.cpp
Location:line 377, column 9
Description:Value stored to 'error' is never read

Annotated Source Code

1/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3/* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * The Original Code is [Open Source Virtual Machine.].
17 *
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2004-2006
21 * the Initial Developer. All Rights Reserved.
22 *
23 * Contributor(s):
24 * Adobe AS3 Team
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
40
41#include "avmplus.h"
42#include "zlib.h"
43
44namespace avmplus
45{
46 //
47 // ByteArray
48 //
49
50 ByteArray::ByteArray(Toplevel* toplevel)
51 : DataIOBase()
52 , DataInput()
53 , DataOutput()
54 , m_toplevel(toplevel)
55 , m_gc(toplevel->core()->GetGC())
56 , m_subscribers(m_gc, 0)
57 , m_copyOnWriteOwner(NULL__null)
58 , m_array(NULL__null)
59 , m_capacity(0)
60 , m_length(0)
61 , m_position(0)
62 {
63 AvmAssert(m_gc != NULL)do { } while (0);
64 }
65
66 ByteArray::~ByteArray()
67 {
68 // no: this can reallocate memory, which is bad to do in a dtor
69 // m_subscribers.clear();
70 _Clear();
71 }
72
73 void ByteArray::Clear()
74 {
75 if (m_subscribers.length() > 0)
76 {
77 AvmAssert(false)do { } while (0); // shouldn't get here?
78 m_toplevel->throwRangeError(kInvalidRangeError);
79 }
80 _Clear();
81 }
82
83 void ByteArray::_Clear()
84 {
85 if (m_array && !IsCopyOnWrite())
86 {
87 TellGcDeleteBufferMemory(m_array, m_length);
88 mmfx_delete_array(m_array)::MMgcDestructTaggedArrayChecked(m_array);
89 }
90 m_array = NULL__null;
91 m_capacity = 0;
92 m_length = 0;
93 m_copyOnWriteOwner = NULL__null;
94 }
95
96 void ByteArray::SetCopyOnWriteOwner(MMgc::GCObject* owner)
97 {
98 if (owner != NULL__null && m_gc->IsPointerToGCPage(this))
99 {
100 WB(m_gc, m_gc->FindBeginningFast(this), &m_copyOnWriteOwner, owner)m_gc->privateWriteBarrier(m_gc->FindBeginningFast(this)
, &m_copyOnWriteOwner, (const void *) (owner))
;
101 }
102 else
103 {
104 m_copyOnWriteOwner = owner;
105 }
106 }
107
108 void ByteArray::SetCopyOnWriteData(MMgc::GCObject* owner, const uint8_t* data, uint32_t length)
109 {
110 Clear();
111 m_array = const_cast<uint8_t*>(data);
112 m_capacity = length;
113 m_length = length;
114 // we must have a non-null value for m_copyOnWriteOwner, as we
115 // use it as an implicit boolean as well, so if none is provided,
116 // cheat and use m_gc->emptyWeakRef
117 if (owner == NULL__null)
118 owner = (MMgc::GCObject*)m_gc->emptyWeakRef;
119 SetCopyOnWriteOwner(owner);
120 }
121
122 void FASTCALL__attribute__((fastcall)) ByteArray::Grower::EnsureWritableCapacity(uint32_t minimumCapacity)
123 {
124 if (minimumCapacity > (MMgc::GCHeap::kMaxObjectSize - MMgc::GCHeap::kBlockSize*2))
125 m_owner->ThrowMemoryError();
126
127 if (minimumCapacity > m_owner->m_capacity || m_owner->IsCopyOnWrite())
128 {
129 uint32_t newCapacity = m_owner->m_capacity << 1;
130 if (newCapacity < minimumCapacity)
131 newCapacity = uint32_t(minimumCapacity);
132 if (newCapacity < kGrowthIncr)
133 newCapacity = kGrowthIncr;
134
135 m_oldArray = m_owner->m_array;
136 m_oldLength = m_owner->m_length;
137
138 uint8_t* newArray = mmfx_new_array_opt(uint8_t, newCapacity, MMgc::kCanFailAndZero)::MMgcConstructTaggedArray((uint8_t*)__null, newCapacity, MMgc
::kCanFailAndZero)
;
139 if (!newArray)
140 m_owner->ThrowMemoryError();
141
142 m_owner->TellGcNewBufferMemory(newArray, newCapacity);
143 if (m_oldArray)
144 VMPI_memcpy::memcpy(newArray, m_oldArray, m_oldLength);
145
146 m_owner->m_array = newArray;
147 m_owner->m_capacity = newCapacity;
148 if (m_owner->m_copyOnWriteOwner != NULL__null)
149 {
150 m_owner->m_copyOnWriteOwner = NULL__null;
151 // Set this to NULL so we don't attempt to delete it in our dtor.
152 m_oldArray = NULL__null;
153 }
154 }
155 }
156
157 /*
158 Why the "Grower" class?
159
160 (1) It provides a clean way to defer discarding the old buffer until the
161 end of the calling function; this matters in the case of Write(),
162 as it's legal to call Write() on your own buffer, and so if growth
163 occurs, you must not discard the old buffer until copying takes place.
164 (2) It avoid redundant calls to NotifySubscribers(); previously we'd call
165 once when a reallocation occurred, then again when the length field
166 changed.
167 (3) It streamlines copy-on-write handling; formerly we either did
168 redundant CopyOnWrite alloc-and-copy followed by a Grow alloc-and-copy,
169 or an if-else clause with redundant alloc-and-copy.
170
171 Of course, the dtor will be skipped (and thus notify and deletes skipped)
172 if a longjmp over it, but the old code was subject to the same defects,
173 so this is not a new liability.
174 */
175 ByteArray::Grower::~Grower()
176 {
177 if (m_oldArray != m_owner->m_array || m_oldLength != m_owner->m_length)
178 {
179 m_owner->NotifySubscribers();
180 }
181 // m_oldArray could be NULL if we grew a copy-on-write ByteArray.
182 if (m_oldArray != NULL__null && m_oldArray != m_owner->m_array)
183 {
184 m_owner->TellGcDeleteBufferMemory(m_oldArray, m_oldLength);
185 mmfx_delete_array(m_oldArray)::MMgcDestructTaggedArrayChecked(m_oldArray);
186 }
187 }
188
189 uint8_t* FASTCALL__attribute__((fastcall)) ByteArray::GetWritableBuffer()
190 {
191 Grower grower(this);
192 grower.EnsureWritableCapacity(m_capacity);
193 return m_array;
194 }
195
196 uint8_t& ByteArray::operator[](uint32_t index)
197 {
198 if (index >= m_length)
199 SetLength(index + 1);
200 return m_array[index];
201 }
202
203 void FASTCALL__attribute__((fastcall)) ByteArray::SetLength(uint32_t newLength)
204 {
205 if (m_subscribers.length() > 0 && m_length < DomainEnv::GLOBAL_MEMORY_MIN_SIZE)
206 m_toplevel->throwRangeError(kInvalidRangeError);
207
208 Grower grower(this);
209 if (newLength > m_capacity)
210 {
211 grower.EnsureWritableCapacity(newLength);
212 }
213 m_length = newLength;
214 if (m_position > newLength)
215 m_position = newLength;
216 }
217
218 // When we might be reading or writing to ourself, use this function
219 // apparently SunPro compiler doesn't like combining REALLY_INLINE with static functions in CPP files
220 /*static*/
221 REALLY_INLINEinline __attribute__((always_inline)) void move_or_copy(void* dst, const void* src, uint32_t count)
222 {
223 if ((uintptr_t(dst) - uintptr_t(src)) >= uintptr_t(count))
224 {
225 VMPI_memcpy::memcpy(dst, src, count);
226 }
227 else
228 {
229 VMPI_memmove::memmove(dst, src, count);
230 }
231 }
232
233 void ByteArray::Read(void* buffer, uint32_t count)
234 {
235 CheckEOF(count);
236 move_or_copy(buffer, m_array + m_position, count);
237 m_position += count;
238 }
239
240 void ByteArray::Write(const void* buffer, uint32_t count)
241 {
242 uint32_t writeEnd = m_position + count;
243
244 Grower grower(this);
245 grower.EnsureWritableCapacity(writeEnd);
246
247 move_or_copy(m_array + m_position, buffer, count);
248 m_position += count;
249 if (m_length < m_position)
250 m_length = m_position;
251 }
252
253 void ByteArray::EnsureCapacity(uint32_t capacity)
254 {
255 Grower grower(this);
256 grower.EnsureWritableCapacity(capacity);
257 }
258
259 void ByteArray::NotifySubscribers()
260 {
261 for (uint32_t i = 0, n = m_subscribers.length(); i < n; ++i)
262 {
263 AvmAssert(m_length >= DomainEnv::GLOBAL_MEMORY_MIN_SIZE)do { } while (0);
264
265 DomainEnv* subscriber = m_subscribers.get(i);
266 if (subscriber)
267 {
268 subscriber->notifyGlobalMemoryChanged(m_array, m_length);
269 }
270 else
271 {
272 // Domain went away? remove link
273 m_subscribers.removeAt(i);
274 --i;
275 }
276 }
277 }
278
279 boolbool ByteArray::addSubscriber(DomainEnv* subscriber)
280 {
281 if (m_length >= DomainEnv::GLOBAL_MEMORY_MIN_SIZE)
282 {
283 removeSubscriber(subscriber);
284 m_subscribers.add(subscriber);
285 // notify the new "subscriber" of the current state of the world
286 subscriber->notifyGlobalMemoryChanged(m_array, m_length);
287 return truetrue;
288 }
289 return falsefalse;
290 }
291
292 boolbool ByteArray::removeSubscriber(DomainEnv* subscriber)
293 {
294 for (uint32_t i = 0, n = m_subscribers.length(); i < n; ++i)
295 {
296 if (m_subscribers.get(i) == subscriber)
297 {
298 m_subscribers.removeAt(i);
299 return truetrue;
300 }
301 }
302 return falsefalse;
303 }
304
305#ifdef DEBUGGER
306 uint64_t ByteArray::bytesUsed() const
307 {
308 // If m_copyOnWrite is set, then we don't own the buffer, so the profiler
309 // should not attribute it to us.
310 return IsCopyOnWrite() ? 0 : m_capacity;
311 }
312#endif
313
314 void ByteArray::TellGcNewBufferMemory(const uint8_t* buf, uint32_t numberOfBytes)
315 {
316 if (buf && numberOfBytes > 0)
317 {
318 m_gc->SignalDependentAllocation(numberOfBytes);
319 }
320 }
321
322 void ByteArray::TellGcDeleteBufferMemory(const uint8_t* buf, uint32_t numberOfBytes)
323 {
324 // Note that we can't rely on using m_toplevel->core()->GetGC();
325 // order of destruction is unspecified, and if this is called at destruction
326 // time, Toplevel might have been destroyed before us. So keep a separate GC*.
327 if (buf && numberOfBytes > 0)
328 {
329 m_gc->SignalDependentDeallocation(numberOfBytes);
330 }
331 }
332
333 void ByteArray::Compress(CompressionAlgorithm algorithm)
334 {
335 // Snarf the data and give ourself some empty data
336 // (remember, existing data might be copy-on-write so don't dance on it)
337 uint8_t* origData = m_array;
338 uint32_t origLen = m_length;
339 MMgc::GCObject* origCopyOnWriteOwner = m_copyOnWriteOwner;
340 if (!origLen) // empty buffer should give empty result
341 return;
342
343 m_array = NULL__null;
344 m_length = 0;
345 m_capacity = 0;
346 m_position = 0;
347 m_copyOnWriteOwner = NULL__null;
348
349 int error = Z_OK0;
350
351 // Use zlib to compress the data. This next block is essentially the
352 // implementation of the compress2() method, but modified to pass a
353 // negative window value (-15) to deflateInit2() for k_deflate mode
354 // in order to obtain deflate-only compression (no ZLib headers).
355
356 const int MAX_WINDOW_RAW_DEFLATE = -15;
357 const int DEFAULT_MEMORY_USE = 8;
358
359 z_stream stream;
360 VMPI_memset::memset(&stream, 0, sizeof(stream));
361 error = deflateInit2(&stream,deflateInit2_((&stream),(9),(8),(algorithm == k_zlib ? 15
: MAX_WINDOW_RAW_DEFLATE),(DEFAULT_MEMORY_USE), (0), "1.2.3"
, (int)sizeof(z_stream))
362 Z_BEST_COMPRESSION,deflateInit2_((&stream),(9),(8),(algorithm == k_zlib ? 15
: MAX_WINDOW_RAW_DEFLATE),(DEFAULT_MEMORY_USE), (0), "1.2.3"
, (int)sizeof(z_stream))
363 Z_DEFLATED,deflateInit2_((&stream),(9),(8),(algorithm == k_zlib ? 15
: MAX_WINDOW_RAW_DEFLATE),(DEFAULT_MEMORY_USE), (0), "1.2.3"
, (int)sizeof(z_stream))
364 algorithm == k_zlib ? MAX_WBITS : MAX_WINDOW_RAW_DEFLATE,deflateInit2_((&stream),(9),(8),(algorithm == k_zlib ? 15
: MAX_WINDOW_RAW_DEFLATE),(DEFAULT_MEMORY_USE), (0), "1.2.3"
, (int)sizeof(z_stream))
365 DEFAULT_MEMORY_USE,deflateInit2_((&stream),(9),(8),(algorithm == k_zlib ? 15
: MAX_WINDOW_RAW_DEFLATE),(DEFAULT_MEMORY_USE), (0), "1.2.3"
, (int)sizeof(z_stream))
366 Z_DEFAULT_STRATEGY)deflateInit2_((&stream),(9),(8),(algorithm == k_zlib ? 15
: MAX_WINDOW_RAW_DEFLATE),(DEFAULT_MEMORY_USE), (0), "1.2.3"
, (int)sizeof(z_stream))
;
367 AvmAssert(error == Z_OK)do { } while (0);
368
369 uint32_t newCap = deflateBound(&stream, origLen);
370 EnsureCapacity(newCap);
371
372 stream.next_in = origData;
373 stream.avail_in = origLen;
374 stream.next_out = m_array;
375 stream.avail_out = m_capacity;
376
377 error = deflate(&stream, Z_FINISH4);
Value stored to 'error' is never read
378 AvmAssert(error == Z_STREAM_END)do { } while (0);
379
380 m_length = stream.total_out;
381 AvmAssert(m_length <= m_capacity)do { } while (0);
382
383 // Note that Compress() has always ended with position == length,
384 // but Uncompress() has always ended with position == 0.
385 // Weird, but we must maintain it.
386 m_position = m_length;
387
388 deflateEnd(&stream);
389
390 // Note: the Compress() method has never reported an error for corrupted data,
391 // so we won't start now. (Doing so would probably require a version check,
392 // to avoid breaking content that relies on misbehavior.)
393 if (origData && origData != m_array && origCopyOnWriteOwner == NULL__null)
394 {
395 TellGcDeleteBufferMemory(origData, origLen);
396 mmfx_delete_array(origData)::MMgcDestructTaggedArrayChecked(origData);
397 }
398 }
399
400 void ByteArray::Uncompress(CompressionAlgorithm algorithm)
401 {
402 // Snarf the data and give ourself some empty data
403 // (remember, existing data might be copy-on-write so don't dance on it)
404 uint8_t* origData = m_array;
405 uint32_t origCap = m_capacity;
406 uint32_t origLen = m_length;
407 uint32_t origPos = m_position;
408 MMgc::GCObject* origCopyOnWriteOwner = m_copyOnWriteOwner;
409 if (!origLen) // empty buffer should give empty result
410 return;
411
412 m_array = NULL__null;
413 m_length = 0;
414 m_capacity = 0;
415 m_position = 0;
416 m_copyOnWriteOwner = NULL__null;
417 // we know that the uncompressed data will be at least as
418 // large as the compressed data, so let's start there,
419 // rather than at zero.
420 EnsureCapacity(origCap);
421
422 const uint32_t kScratchSize = 8192;
423 uint8_t* scratch = mmfx_new_array(uint8_t, kScratchSize)::MMgcConstructTaggedArray((uint8_t*)__null, kScratchSize, MMgc
::kNone)
;
424
425 int error = Z_OK0;
426
427 z_stream stream;
428 VMPI_memset::memset(&stream, 0, sizeof(stream));
429 error = inflateInit2(&stream, algorithm == k_zlib ? 15 : -15)inflateInit2_((&stream), (algorithm == k_zlib ? 15 : -15)
, "1.2.3", (int)sizeof(z_stream))
;
430 AvmAssert(error == Z_OK)do { } while (0);
431
432 stream.next_in = origData;
433 stream.avail_in = origLen;
434 while (error == Z_OK0)
435 {
436 stream.next_out = scratch;
437 stream.avail_out = kScratchSize;
438 error = inflate(&stream, Z_NO_FLUSH0);
439 Write(scratch, kScratchSize - stream.avail_out);
440 }
441
442 inflateEnd(&stream);
443
444 mmfx_delete_array(scratch)::MMgcDestructTaggedArrayChecked(scratch);
445
446 if (error == Z_STREAM_END1)
447 {
448 // everything is cool
449 if (origData && origData != m_array && origCopyOnWriteOwner == NULL__null)
450 {
451 TellGcDeleteBufferMemory(origData, origLen);
452 mmfx_delete_array(origData)::MMgcDestructTaggedArrayChecked(origData);
453 }
454
455 // Note that Compress() has always ended with position == length,
456 // but Uncompress() has always ended with position == 0.
457 // Weird, but we must maintain it.
458 m_position = 0;
459 }
460 else
461 {
462 // When we error, put the original data back
463 m_array = origData;
464 m_length = origLen;
465 m_capacity = origCap;
466 m_position = origPos;
467 SetCopyOnWriteOwner(origCopyOnWriteOwner);
468 toplevel()->throwIOError(kCompressedDataError);
469 }
470 }
471
472 //
473 // ByteArrayObject
474 //
475
476 ByteArrayObject::ByteArrayObject(VTable* ivtable, ScriptObject* delegate)
477 : ScriptObject(ivtable, delegate)
478 , m_byteArray(toplevel())
479 {
480 c.set(&m_byteArray, sizeof(ByteArray));
481 ByteArrayClass* cls = toplevel()->byteArrayClass();
482 m_byteArray.SetObjectEncoding((ObjectEncoding)cls->get_defaultObjectEncoding());
483 toplevel()->byteArrayCreated(this);
484 }
485
486 Atom ByteArrayObject::getUintProperty(uint32_t i) const
487 {
488 if (i < m_byteArray.GetLength())
489 {
490 intptr_t const b = m_byteArray[i];
491 return atomFromIntptrValue(b);
492 }
493 else
494 {
495 return undefinedAtom;
496 }
497 }
498
499 boolbool ByteArrayObject::hasUintProperty(uint32_t i) const
500 {
501 return i < m_byteArray.GetLength();
502 }
503
504 void ByteArrayObject::setUintProperty(uint32_t i, Atom value)
505 {
506 m_byteArray[i] = uint8_t(AvmCore::integer(value));
507 }
508
509 Atom ByteArrayObject::getAtomProperty(Atom name) const
510 {
511 uint32_t index;
512 if (AvmCore::getIndexFromAtom(name, &index))
513 {
514 return getUintProperty(index);
515 }
516
517 return ScriptObject::getAtomProperty(name);
518 }
519
520 void ByteArrayObject::setAtomProperty(Atom name, Atom value)
521 {
522 uint32_t index;
523 if (AvmCore::getIndexFromAtom(name, &index))
524 {
525 setUintProperty(index, value);
526 }
527 else
528 {
529 ScriptObject::setAtomProperty(name, value);
530 }
531 }
532
533 boolbool ByteArrayObject::hasAtomProperty(Atom name) const
534 {
535 if (core()->currentBugCompatibility()->bugzilla558863)
536 {
537 uint32_t index;
538 if (AvmCore::getIndexFromAtom(name, &index))
539 {
540 return index < m_byteArray.GetLength();
541 }
542
543 return ScriptObject::hasAtomProperty(name);
544 }
545 else
546 {
547 return ScriptObject::hasAtomProperty(name)
548 || getAtomProperty(name) != undefinedAtom;
549 }
550 }
551
552 Atom ByteArrayObject::getMultinameProperty(const Multiname* name) const
553 {
554 uint32_t index;
555 if (name->getName()->parseIndex(index))
556 {
557 return getUintProperty(index);
558 }
559
560 return ScriptObject::getMultinameProperty(name);
561 }
562
563 void ByteArrayObject::setMultinameProperty(const Multiname* name, Atom value)
564 {
565 uint32_t index;
566 if (name->getName()->parseIndex(index))
567 {
568 setUintProperty(index, value);
569 }
570 else
571 {
572 ScriptObject::setMultinameProperty(name, value);
573 }
574 }
575
576 boolbool ByteArrayObject::hasMultinameProperty(const Multiname* name) const
577 {
578 uint32_t index;
579 if (name->getName()->parseIndex(index))
580 {
581 return index < m_byteArray.GetLength();
582 }
583
584 return ScriptObject::hasMultinameProperty(name);
585 }
586
587 String* ByteArrayObject::_toString()
588 {
589 uint32_t len = m_byteArray.GetLength();
590 const uint8_t* c = m_byteArray.GetReadableBuffer();
591
592 Toplevel* toplevel = this->toplevel();
593 AvmCore* core = toplevel->core();
594
595 if (len >= 3)
596 {
597 // UTF8 BOM
598 if ((c[0] == 0xef) && (c[1] == 0xbb) && (c[2] == 0xbf))
599 {
600 return core->newStringUTF8((const char*)c + 3, len - 3);
601 }
602 else if ((c[0] == 0xfe) && (c[1] == 0xff))
603 {
604 //UTF-16 big endian
605 c += 2;
606 len = (len - 2) >> 1;
607 return core->newStringEndianUTF16(/*littleEndian*/falsefalse, (const wchar*)c, len);
608 }
609 else if ((c[0] == 0xff) && (c[1] == 0xfe))
610 {
611 //UTF-16 little endian
612 c += 2;
613 len = (len - 2) >> 1;
614 return core->newStringEndianUTF16(/*littleEndian*/truetrue, (const wchar*)c, len);
615 }
616 }
617
618 String* result = toplevel->tryFromSystemCodepage(c);
619 if (result != NULL__null)
620 return result;
621
622 // Use newStringUTF8() with "strict" explicitly set to false to mimick old,
623 // buggy behavior, where malformed UTF-8 sequences are stored as single characters.
624 return core->newStringUTF8((const char*)c, len, falsefalse);
625 }
626
627 Atom ByteArrayObject::readObject()
628 {
629 return m_byteArray.ReadObject();
630 }
631
632 void ByteArrayObject::writeObject(Atom value)
633 {
634 m_byteArray.WriteObject(value);
635 }
636
637 int ByteArrayObject::readByte()
638 {
639 return (int8_t)m_byteArray.ReadU8();
640 }
641
642 int ByteArrayObject::readUnsignedByte()
643 {
644 return m_byteArray.ReadU8();
645 }
646
647 int ByteArrayObject::readShort()
648 {
649 return (int16_t)m_byteArray.ReadU16();
650 }
651
652 int ByteArrayObject::readUnsignedShort()
653 {
654 return m_byteArray.ReadU16();
655 }
656
657 int ByteArrayObject::readInt()
658 {
659 return (int32_t)m_byteArray.ReadU32();
660 }
661
662 uint32_t ByteArrayObject::readUnsignedInt()
663 {
664 return m_byteArray.ReadU32();
665 }
666
667 double ByteArrayObject::readFloat()
668 {
669 return m_byteArray.ReadFloat();
670 }
671
672 double ByteArrayObject::readDouble()
673 {
674 return m_byteArray.ReadDouble();
675 }
676
677 boolbool ByteArrayObject::readBoolean()
678 {
679 return m_byteArray.ReadBoolean();
680 }
681
682 void ByteArrayObject::writeBoolean(boolbool value)
683 {
684 m_byteArray.WriteBoolean(value);
685 }
686
687 void ByteArrayObject::writeByte(int value)
688 {
689 m_byteArray.WriteU8((uint8_t)value);
690 }
691
692 void ByteArrayObject::writeShort(int value)
693 {
694 m_byteArray.WriteU16((uint16_t)value);
695 }
696
697 void ByteArrayObject::writeInt(int value)
698 {
699 m_byteArray.WriteU32((uint32_t)value);
700 }
701
702 void ByteArrayObject::writeUnsignedInt(uint32_t value)
703 {
704 m_byteArray.WriteU32(value);
705 }
706
707 void ByteArrayObject::writeFloat(double value)
708 {
709 m_byteArray.WriteFloat((float)value);
710 }
711
712 void ByteArrayObject::writeDouble(double value)
713 {
714 m_byteArray.WriteDouble(value);
715 }
716
717 ByteArray::CompressionAlgorithm ByteArrayObject::algorithmToEnum(String* algorithm)
718 {
719 Toplevel* toplevel = this->toplevel();
720 toplevel->checkNull(algorithm, "algorithm");
721 if (algorithm->equalsLatin1("zlib"))
722 {
723 return ByteArray::k_zlib;
724 }
725 if (algorithm->equalsLatin1("deflate"))
726 {
727 return ByteArray::k_deflate;
728 }
729 else
730 {
731 // Unknown format
732 toplevel->throwIOError(kCompressedDataError);
733 return ByteArray::k_zlib; // not reached, pacify compiler
734 }
735 }
736
737 void ByteArrayObject::_compress(String* algorithm)
738 {
739 m_byteArray.Compress(algorithmToEnum(algorithm));
740 }
741
742 void ByteArrayObject::_uncompress(String* algorithm)
743 {
744 m_byteArray.Uncompress(algorithmToEnum(algorithm));
745 }
746
747 void ByteArrayObject::writeBytes(ByteArrayObject *bytes,
748 uint32_t offset,
749 uint32_t length)
750 {
751 toplevel()->checkNull(bytes, "bytes");
752
753 if (length == 0) {
754 length = bytes->get_length() - offset;
755 }
756
757 m_byteArray.WriteByteArray(bytes->GetByteArray(),
758 offset,
759 length);
760 }
761
762 void ByteArrayObject::readBytes(ByteArrayObject *bytes,
763 uint32_t offset,
764 uint32_t length)
765 {
766 toplevel()->checkNull(bytes, "bytes");
767
768 if (length == 0) {
769 length = m_byteArray.Available();
770 }
771
772 m_byteArray.ReadByteArray(bytes->GetByteArray(),
773 offset,
774 length);
775 }
776
777 String* ByteArrayObject::readMultiByte(uint32_t length, String* charSet)
778 {
779 toplevel()->checkNull(charSet, "charSet");
780 return m_byteArray.ReadMultiByte(length, charSet);
781 }
782
783 String* ByteArrayObject::readUTF()
784 {
785 return m_byteArray.ReadUTF();
786 }
787
788 String* ByteArrayObject::readUTFBytes(uint32_t length)
789 {
790 return m_byteArray.ReadUTFBytes(length);
791 }
792
793 void ByteArrayObject::writeMultiByte(String* value, String* charSet)
794 {
795 toplevel()->checkNull(value, "value");
796 toplevel()->checkNull(charSet, "charSet");
797 m_byteArray.WriteMultiByte(value, charSet);
798 }
799
800 void ByteArrayObject::writeUTF(String* value)
801 {
802 toplevel()->checkNull(value, "value");
803 m_byteArray.WriteUTF(value);
804 }
805
806 void ByteArrayObject::writeUTFBytes(String* value)
807 {
808 toplevel()->checkNull(value, "value");
809 m_byteArray.WriteUTFBytes(value);
810 }
811
812 uint32_t ByteArrayObject::get_objectEncoding()
813 {
814 return m_byteArray.GetObjectEncoding();
815 }
816
817 void ByteArrayObject::set_objectEncoding(uint32_t objectEncoding)
818 {
819 if ((objectEncoding == kAMF3)||(objectEncoding == kAMF0))
820 {
821 m_byteArray.SetObjectEncoding(ObjectEncoding(objectEncoding));
822 }
823 else
824 {
825 toplevel()->throwArgumentError(kInvalidEnumError, "objectEncoding");
826 }
827 }
828
829 Stringp ByteArrayObject::get_endian()
830 {
831 return (m_byteArray.GetEndian() == kBigEndian) ? core()->kbigEndian : core()->klittleEndian;
832 }
833
834 void ByteArrayObject::set_endian(Stringp type)
835 {
836 Toplevel* toplevel = this->toplevel();
837 AvmCore* core = toplevel->core();
838
839 toplevel->checkNull(type, "endian");
840
841 type = core->internString(type);
842 if (type == core->kbigEndian)
843 {
844 m_byteArray.SetEndian(kBigEndian);
845 }
846 else if (type == core->klittleEndian)
847 {
848 m_byteArray.SetEndian(kLittleEndian);
849 }
850 else
851 {
852 toplevel->throwArgumentError(kInvalidEnumError, "type");
853 }
854 }
855
856 void ByteArrayObject::clear()
857 {
858 m_byteArray.Clear();
859 m_byteArray.SetPosition(0);
860 }
861
862#ifdef DEBUGGER
863 uint64_t ByteArrayObject::bytesUsed() const
864 {
865 uint64_t size = ScriptObject::bytesUsed();
866 size += m_byteArray.bytesUsed();
867 return size;
868 }
869#endif
870
871 //
872 // ByteArrayClass
873 //
874
875 ByteArrayClass::ByteArrayClass(VTable *vtable)
876 : ClassClosure(vtable)
877 {
878 setPrototypePtr(toplevel()->objectClass->construct());
879 set_defaultObjectEncoding(kEncodeDefault);
880 }
881
882 GCRef<ByteArrayObject> ByteArrayClass::constructByteArray()
883 {
884 return constructObject();
885 }
886}
887