1 //
2 // Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 //
18
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
22
23 #include <cstdint>
24 #include <iostream>
25 #include <boost/random/uniform_int.hpp>
26 #include <boost/random/mersenne_twister.hpp>
27
28 #include "buffer.h"
29 #include "amf.h"
30 #include "log.h"
31 //#include "network.h"
32 #include "GnashException.h"
33
34
35 /// \namespace cygnal
36 ///
37 /// This namespace is for all the AMF specific classes in libamf.
38 namespace cygnal
39 {
40
41 /// \brief Convert a Hex digit into it's decimal value.
42 ///
43 /// @param digit The digit as a hex value
44 ///
45 /// @return The byte as a decimal value.
46 std::uint8_t
hex2digit(std::uint8_t digit)47 Buffer::hex2digit (std::uint8_t digit)
48 {
49 if (digit == 0)
50 return 0;
51
52 if (digit >= '0' && digit <= '9')
53 return digit - '0';
54 if (digit >= 'a' && digit <= 'f')
55 return digit - 'a' + 10;
56 if (digit >= 'A' && digit <= 'F')
57 return digit - 'A' + 10;
58
59 // shouldn't ever get this far
60 return -1;
61 }
62
63 /// \brief Encode a Buffer from a hex string.
64 ///
65 /// @param str A hex string, ex... "00 03 05 0a"
66 ///
67 /// @return A reference to a Buffer in host endian format. This is
68 /// primary used only for testing to create binary data
69 /// from an easy to read and edit format.
70 Buffer &
hex2mem(const std::string & str)71 Buffer::hex2mem(const std::string &str)
72 {
73 // GNASH_REPORT_FUNCTION;
74 size_t count = str.size();
75 size_t size = (count/3) + 4;
76 std::uint8_t ch = 0;
77
78 std::uint8_t *ptr = const_cast<std::uint8_t *>(reinterpret_cast<const std::uint8_t *>(str.c_str()));
79 std::uint8_t *end = ptr + count;
80
81 init(size);
82
83 for (size_t i=0; ptr<end; i++) {
84 if (*ptr == ' ') { // skip spaces.
85 ptr++;
86 continue;
87 }
88 ch = hex2digit(*ptr++) << 4;
89 ch |= hex2digit(*ptr++);
90 *this += ch;
91 i++;
92 }
93 resize(size);
94
95 return *this;
96 }
97
98 // Convert each byte into its hex representation
99 std::string
hexify()100 Buffer::hexify ()
101 {
102 return gnash::hexify(_data.get(), allocated(), false);
103 }
104
105 std::string
hexify(bool ascii)106 Buffer::hexify (bool ascii)
107 {
108 return gnash::hexify(_data.get(), allocated(), ascii);
109 }
110
111 std::string
hexify(cygnal::Buffer & buf,bool ascii)112 Buffer::hexify (cygnal::Buffer &buf, bool ascii)
113 {
114 return gnash::hexify(buf.reference(), buf.allocated(), ascii);
115 }
116
117 /// \brief Initialize a block of memory for this buffer.
118 /// This should only be used internally by the Buffer
119 /// class.
120 ///
121 /// @param nbytes The total size to allocate memory for.
122 ///
123 /// @return A reference to the initialized Buffer.
124 Buffer &
init(size_t size)125 Buffer::init(size_t size)
126 {
127 // GNASH_REPORT_FUNCTION;
128 if (!_data) {
129 _data.reset(new std::uint8_t[size]);
130 _seekptr = _data.get();
131 }
132 _seekptr = _data.get();
133 _nbytes = size;
134
135 clear();// FIXME; this is a perforance hit, but aids in debugging
136 #ifdef USE_STATS_BUFFERS
137 clock_gettime (CLOCK_REALTIME, &_stamp);
138 #endif
139
140 return *this;
141 }
142
143 /// \brief Create a new Buffer with the default size
Buffer()144 Buffer::Buffer()
145 : _seekptr(nullptr)
146 {
147 // GNASH_REPORT_FUNCTION;
148 _nbytes = cygnal::NETBUFSIZE;
149 init(cygnal::NETBUFSIZE);
150 }
151
152 /// \brief Create a new Buffer with a size other than the default
Buffer(size_t nbytes)153 Buffer::Buffer(size_t nbytes)
154 : _seekptr(nullptr)
155 {
156 // GNASH_REPORT_FUNCTION;
157 _nbytes = nbytes;
158 init(_nbytes);
159 }
160
161 /// \brief Create a new Buffer with a hex string.
162 /// This is primary used only for testing to create binary
163 /// data from an easy to read and edit format.
164 /// @param str A hex string, ex... "00 03 05 0a"
Buffer(const std::string & str)165 Buffer::Buffer(const std::string &str)
166 {
167 // GNASH_REPORT_FUNCTION;
168 hex2mem(str);
169 }
170
171 /// Delete the memory allocated for this Buffer
~Buffer()172 Buffer::~Buffer()
173 {
174 // GNASH_REPORT_FUNCTION;
175 if (_data) {
176 #ifdef USE_STATS_BUFFERS
177 struct timespec now;
178 clock_gettime (CLOCK_REALTIME, &now);
179 log_debug(_("Buffer %x (%d) stayed in queue for %f seconds"),
180 (void *)_data.get(), _nbytes,
181 (float)((now.tv_sec - _stamp.tv_sec) + ((now.tv_nsec - _stamp.tv_nsec)/1e9)));
182 #endif
183 _seekptr = nullptr;
184 _nbytes = 0;
185 }
186 }
187
188 /// \brief Copy data into the buffer.
189 /// This overwrites all data, and resets the seek ptr.
190 ///
191 /// @param data A pointer to the raw bytes to copy into the
192 /// buffer.
193 ///
194 /// @param nbytes The number of bytes to copy.
195 ///
196 /// @return A reference to a Buffer.
197 Buffer &
copy(std::uint8_t * data,size_t nbytes)198 Buffer::copy(std::uint8_t *data, size_t nbytes)
199 {
200 // GNASH_REPORT_FUNCTION;
201 if (_data) {
202 if (_nbytes >= nbytes) {
203 std::copy(data, data + nbytes, _data.get());
204 _seekptr = _data.get() + nbytes;
205 } else {
206 boost::format msg("Not enough storage was allocated to hold the "
207 "copied data! Needs %1%, only has %2% bytes");
208 msg % nbytes % _nbytes;
209 throw gnash::GnashException(msg.str());
210 }
211 }
212 return *this;
213 }
214
215 /// \brief Append data to existing data in the buffer.
216 ///
217 /// @param data A pointer to the raw bytes to append to the
218 /// buffer.
219 ///
220 /// @param nbytes The number of bytes to append.
221 ///
222 /// @return A reference to a Buffer.
223 Buffer &
append(std::uint8_t * data,size_t nbytes)224 Buffer::append(std::uint8_t *data, size_t nbytes)
225 {
226 // GNASH_REPORT_FUNCTION;
227 if (_data) {
228 if (spaceLeft() >= nbytes) {
229 std::copy(data, data + nbytes, _seekptr);
230 _seekptr += nbytes;
231 } else {
232 boost::format msg("Not enough storage was allocated to hold the "
233 "appended data! Needs %1%, only has %2% bytes");
234 msg % nbytes % spaceLeft();
235 throw gnash::GnashException(msg.str());
236 }
237 }
238
239 return *this;
240 }
241
242 /// \brief Append a Buffer class to existing data in the buffer.
243 ///
244 /// @param buf A Buffer class containing the data to append.
245 ///
246 /// @return A reference to a Buffer.
247 Buffer &
operator +=(Buffer & buf)248 Buffer::operator+=(Buffer &buf)
249 {
250 // // GNASH_REPORT_FUNCTION;
251 append(buf.reference(), buf.allocated());
252 return *this;
253 }
254
255 /// \brief Copy a AMF0 type into the buffer.
256 /// This overwrites all data, and resets the seek ptr.
257 ///
258 /// @param type An AMF0 type.
259 ///
260 /// @return A reference to a Buffer.
261 Buffer &
operator +=(cygnal::Element::amf0_type_e type)262 Buffer::operator+=(cygnal::Element::amf0_type_e type)
263 {
264 // GNASH_REPORT_FUNCTION;
265 std::uint8_t nb = static_cast<std::uint8_t>(type);
266
267 return operator+=(nb);
268 }
269
270 /// \brief Append a byte to existing data in the buffer.
271 ///
272 /// @param byte A single byte.
273 ///
274 /// @return A reference to a Buffer.
275 Buffer &
operator +=(char byte)276 Buffer::operator+=(char byte)
277 {
278 // GNASH_REPORT_FUNCTION;
279 std::uint8_t nb = static_cast<std::uint8_t>(byte);
280 return operator+=(nb);
281 }
282
283 /// \brief Append a boolean to existing data in the buffer.
284 ///
285 /// @param type A boolean.
286 ///
287 /// @return A reference to a Buffer.
288 Buffer &
operator +=(bool flag)289 Buffer::operator+=(bool flag)
290 {
291 // GNASH_REPORT_FUNCTION;
292 std::uint8_t nb = static_cast<std::uint8_t>(flag);
293 return operator+=(nb);
294 }
295
296 /// \brief Append a byte to existing data in the buffer.
297 ///
298 /// @param byte A single byte.
299 ///
300 /// @return A reference to a Buffer.
301 Buffer &
operator +=(std::uint8_t byte)302 Buffer::operator+=(std::uint8_t byte)
303 {
304 // GNASH_REPORT_FUNCTION;
305 if ((_seekptr + 1) <= (_data.get() + _nbytes)) {
306 *_seekptr = byte;
307 _seekptr += sizeof(std::uint8_t);
308 }
309 return *this;
310 }
311
312 /// \brief Append a string to existing data in the buffer.
313 ///
314 /// @param str A string containing ASCII data to copy into the
315 /// buffer.
316 ///
317 /// @return A reference to a Buffer.
318 Buffer &
operator +=(const char * str)319 Buffer::operator+=(const char *str)
320 {
321 // GNASH_REPORT_FUNCTION;
322 std::uint8_t *ptr = const_cast<std::uint8_t *>(reinterpret_cast<const std::uint8_t *>(str));
323 return append(ptr, strlen(str));
324
325 }
326
327 /// \brief Append a string to existing data in the buffer.
328 ///
329 /// @param str A string containing ASCII data to copy into the
330 /// buffer.
331 ///
332 /// @return A reference to a Buffer.
333 Buffer &
operator +=(const std::string & str)334 Buffer::operator+=(const std::string &str)
335 {
336 // GNASH_REPORT_FUNCTION;
337 std::uint8_t *ptr = const_cast<std::uint8_t *>(reinterpret_cast<const std::uint8_t *>(str.c_str()));
338 return append(ptr, str.size());
339
340 }
341
342 /// \brief Append a double to existing data in the buffer.
343 ///
344 /// @param num A numeric double value.
345 ///
346 /// @return A reference to a Buffer.
347 Buffer &
operator +=(double num)348 Buffer::operator+=(double num)
349 {
350 // GNASH_REPORT_FUNCTION;
351 std::uint8_t *ptr = reinterpret_cast<std::uint8_t *>(&num);
352 return append(ptr, AMF0_NUMBER_SIZE);
353 }
354
355 /// \brief Append a short to existing data in the buffer.
356 ///
357 /// @param num A numeric short value.
358 ///
359 /// @return A reference to a Buffer.
360 Buffer &
operator +=(std::uint16_t length)361 Buffer::operator+=(std::uint16_t length)
362 {
363 // GNASH_REPORT_FUNCTION;
364 std::uint8_t *ptr = reinterpret_cast<std::uint8_t *>(&length);
365 return append(ptr, sizeof(std::uint16_t));
366 }
367
368 /// \brief Append an integer to existing data in the buffer.
369 ///
370 /// @param num A numeric integer value.
371 ///
372 /// @return A reference to a Buffer.
373 Buffer &
operator +=(std::uint32_t length)374 Buffer::operator+=(std::uint32_t length)
375 {
376 // GNASH_REPORT_FUNCTION;
377 std::uint8_t *ptr = reinterpret_cast<std::uint8_t *>(&length);
378 return append(ptr, sizeof(std::uint32_t));
379 }
380
381 /// \brief Append a Buffer class to existing data in the buffer.
382 ///
383 /// @param buf A Buffer class containing the data to append.
384 ///
385 /// @return A reference to a Buffer.
386 Buffer &
operator +=(std::shared_ptr<Buffer> buf)387 Buffer::operator+=(std::shared_ptr<Buffer> buf)
388 {
389 // GNASH_REPORT_FUNCTION;
390 append(buf->reference(), buf->allocated());
391 return *this;
392 }
393
394 /// \brief Append a Buffer class to existing data in the buffer.
395 ///
396 /// @param buf A Buffer class containing the data to append.
397 ///
398 /// @return A reference to a Buffer.
399 Buffer &
operator =(Buffer & buf)400 Buffer::operator=(Buffer &buf)
401 {
402 // GNASH_REPORT_FUNCTION;
403 if (buf.size() != _nbytes) {
404 resize(buf.size());
405 }
406 copy(buf.reference(), buf.size());
407
408 return *this;
409 }
410
411 /// \brief Copy a string into the buffer.
412 /// This overwrites all data, and resets the seek ptr.
413 ///
414 /// @param str A string containing ASCII data to copy into the
415 /// buffer.
416 ///
417 /// @return A reference to a Buffer.
418 Buffer &
operator =(const std::string & str)419 Buffer::operator=(const std::string &str)
420 {
421 // GNASH_REPORT_FUNCTION;
422 std::uint8_t *ptr = const_cast<std::uint8_t *>(reinterpret_cast<const std::uint8_t *>(str.c_str()));
423 return copy(ptr, str.size());
424 }
425
426 Buffer &
operator =(const char * str)427 Buffer::operator=(const char *str)
428 {
429 // GNASH_REPORT_FUNCTION;
430 std::uint8_t *ptr = const_cast<std::uint8_t *>(reinterpret_cast<const std::uint8_t *>(str));
431 return copy(ptr, strlen(str));
432 }
433
434 /// \brief Copy a double into the buffer.
435 /// This overwrites all data, and resets the seek ptr.
436 ///
437 /// @param num A numeric double value.
438 ///
439 /// @return A reference to a Buffer.
440 Buffer &
operator =(double num)441 Buffer::operator=(double num)
442 {
443 // GNASH_REPORT_FUNCTION;
444 std::uint8_t *ptr = reinterpret_cast<std::uint8_t *>(&num);
445 return copy(ptr, AMF0_NUMBER_SIZE);
446 }
447
448 /// \brief Copy a short into the buffer.
449 /// This overwrites all data, and resets the seek ptr.
450 ///
451 /// @param num A numeric short value.
452 ///
453 /// @return A reference to a Buffer.
454 Buffer &
operator =(std::uint16_t length)455 Buffer::operator=(std::uint16_t length)
456 {
457 // GNASH_REPORT_FUNCTION;
458 std::uint8_t *ptr = reinterpret_cast<std::uint8_t *>(&length);
459 return copy(ptr, sizeof(std::uint16_t));
460 }
461
462 /// \brief Copy a AMF0 type into the buffer.
463 /// This overwrites all data, and resets the seek ptr.
464 ///
465 /// @param type An AMF0 type.
466 ///
467 /// @return A reference to a Buffer.
468 Buffer &
operator =(cygnal::Element::amf0_type_e type)469 Buffer::operator=(cygnal::Element::amf0_type_e type)
470 {
471 std::uint8_t nb = static_cast<std::uint8_t>(type);
472 return operator=(nb);
473 }
474
475 /// Copy a boolean into the buffer. This overwrites all data, and
476 /// resets the seek ptr.
477 ///
478 /// @param flag A boolean.
479 ///
480 /// @return A reference to a Buffer.
481 Buffer &
operator =(bool flag)482 Buffer::operator=(bool flag)
483 {
484 std::uint8_t nb = static_cast<std::uint8_t>(flag);
485 return operator=(nb);
486 }
487
488 /// \brief Copy a byte into the buffer.
489 /// This overwrites all data, and resets the seek ptr.
490 ///
491 /// @param byte A single byte.
492 ///
493 /// @return A reference to a Buffer.
494 Buffer &
operator =(std::uint8_t byte)495 Buffer::operator=(std::uint8_t byte)
496 {
497 // GNASH__FUNCTION;
498
499 return copy(&byte, 1);
500 }
501
502 /// \brief Copy a byte into the buffer.
503 /// This overwrites all data, and resets the seek ptr.
504 ///
505 /// @param byte A pointer to a single byte.
506 ///
507 /// @return A reference to a Buffer.
508 Buffer &
operator =(std::uint8_t * data)509 Buffer::operator=(std::uint8_t *data)
510 {
511 // GNASH_REPORT_FUNCTION;
512 if (data) {
513 _data.reset(data);
514 } else {
515 throw gnash::ParserException("Passing invalid pointer!");
516 }
517 return *this;
518 }
519
520 /// \brief Copy a Buffer class into the buffer.
521 /// This overwrites all data, and resets the seek ptr.
522 ///
523 /// @param buf A Buffer class containing the data to copy.
524 ///
525 /// @return A reference to a Buffer.
526 Buffer &
operator =(std::shared_ptr<Buffer> buf)527 Buffer::operator=(std::shared_ptr<Buffer> buf)
528 {
529 // GNASH_REPORT_FUNCTION;
530 copy(buf->reference(), buf->size());
531 return *this;
532 }
533
534 /// \brief Test equivalance against another Buffer.
535 /// This compares all the data on the current Buffer with
536 /// the supplied one, so it can be a performance hit. This
537 /// is primarily only used for testing purposes.
538 ///
539 /// @param buf A reference to a Buffer.
540 ///
541 /// @return A boolean true if the Buffers are indentical.
542 bool
operator ==(Buffer & buf)543 Buffer::operator==(Buffer &buf)
544 {
545 // GNASH_REPORT_FUNCTION;
546 if (buf.size() == _nbytes){
547 if (memcmp(buf.reference(), _data.get(), _nbytes) == 0) {
548 return true;
549 }
550 }
551 return false;
552 }
553
554 /// \brief Drop a byte without resizing.
555 /// This will remove the byte from the Buffer, and then
556 /// move the remaining data to be in the correct
557 /// location. This resets the seek pointer.
558 ///
559 /// @param byte The byte to remove from the buffer.
560 ///
561 /// @return A real pointer to the base address of the buffer.
562 std::uint8_t *
remove(std::uint8_t c)563 Buffer::remove(std::uint8_t c)
564 {
565 // GNASH_REPORT_FUNCTION;
566 std::uint8_t *start = std::find(begin(), end(), c);
567
568 // log_debug("Byte is at %x", (void *)start);
569
570 if (start == nullptr) {
571 return nullptr;
572 }
573
574 std::copy(start + 1, end(), start);
575 *(end() - 1) = 0;
576 _seekptr--;
577
578 return _data.get();
579 }
580
581 /// \brief Drop a byte without resizing.
582 /// This will remove the byte from the Buffer, and then
583 /// move the remaining data to be in the correct
584 /// location. This resets the seek pointer.
585 ///
586 /// @param start The location of the byte to remove from the
587 /// Buffer
588 ///
589 /// @return A real pointer to the base address of the Buffer.
590 std::uint8_t *
remove(int start)591 Buffer::remove(int start)
592 {
593 // GNASH_REPORT_FUNCTION;
594 std::copy((_data.get() + start + 1), end(), (_data.get() + start)),
595 // *end() = 0;
596 _seekptr--;
597 return _data.get();
598 }
599
600 /// \brief Drop bytes without resizing.
601 /// This will remove the bytes from the Buffer, and then
602 /// move the remaining data to be in the correct
603 /// location. This resets the seek pointer.
604 ///
605 /// @param index The location of the byte to start removing data
606 /// from the Buffer. This is an numerical value, not a
607 /// pointer.
608 ///
609 /// @param start The location of the byte to remove from the
610 /// Buffer
611 /// @param range The amount of bytes to remove from the Buffer.
612 ///
613 /// @return A real pointer to the base address of the Buffer.
614 std::uint8_t *
remove(int start,int range)615 Buffer::remove(int start, int range)
616 {
617 // GNASH_REPORT_FUNCTION;
618 std::copy((_data.get() + range + 1), end(), (_data.get() + start)),
619 // *end() = 0;
620 _seekptr -= range;
621
622 return _data.get();
623 }
624
625 /// \brief Clear the contents of the buffer by setting all the bytes to
626 /// zeros.
627 ///
628 /// @return nothing
629 void
clear()630 Buffer::clear()
631 {
632 // GNASH_REPORT_FUNCTION;
633 if (_data) {
634 memset(_data.get(), 0, _nbytes);
635 }
636 _seekptr = _data.get();
637 }
638
639 /// \brief Resize the buffer that holds the data.
640 /// The new size of the current data is based on the
641 /// current amount of data within the allocated memory.
642 /// This is used to make a Buffer the same size as
643 /// the existing data, and to truncate the unsed portion
644 /// of the Buffer when copying to the new memory
645 /// location.
646 ///
647 /// @return A reference to a Buffer.
648 Buffer &
resize()649 Buffer::resize()
650 {
651 // GNASH_REPORT_FUNCTION;
652 return resize(_seekptr - _data.get());
653 }
654
655 /// \brief Resize the buffer that holds the data.
656 /// If the size is larger than the existing data, the data
657 /// is copied into the new region. If the size is smaller
658 /// than the existing data, the remaining data is
659 /// truncated when copying to the new memory location.
660 ///
661 /// @param nbyte The size to resize the Buffer to.
662 ///
663 /// @return A reference to a Buffer.
664 Buffer &
resize(size_t size)665 Buffer::resize(size_t size)
666 {
667 // GNASH_REPORT_FUNCTION;
668 std::unique_ptr<std::uint8_t[]> tmp;
669
670 // If there is no size, don't do anything
671 if (size == 0) {
672 return *this;
673 }
674
675 // If we don't have any data yet in this buffer, resizing is cheap, as
676 // we don't havce to copy any data.
677 if (_seekptr == _data.get()) {
678 _data.reset(new std::uint8_t[size]);
679 _nbytes= size;
680 return *this;
681 }
682
683 if (_nbytes == 0) {
684 return init(size);
685 } else {
686 // Don't bother to resize without really changing anything
687 if (size == _nbytes) {
688 return *this;
689 }
690
691 // check the sizes. If we had data read using ->reference(), the seekptr isn't
692 // increased, so in these cases we just copy al lthe data blindly, as it's
693 // better than loosing data.
694 size_t used = 0;
695 if (_seekptr != _data.get()) {
696 used = _seekptr - _data.get();
697 } else {
698 if (size < _nbytes) {
699 used = size;
700 } else {
701 used = _nbytes;
702 }
703 }
704
705
706 // Copy the existing data into the new block of memory. The data
707 // held currently is moved to the temporary array, and then gets
708 // deleted when this method returns.
709 // We loose data if we resize smaller than the data currently held.
710 if (size < used) {
711 gnash::log_error(_("cygnal::Buffer::resize(%d): Truncating data (%d bytes) while resizing!"), size, used - size);
712 used = size;
713 }
714 std::uint8_t *newptr = new std::uint8_t[size];
715 std::copy(_data.get(), _data.get() + used, newptr);
716 _data.reset(newptr);
717
718 // Make the seekptr point into the new space with the correct offset
719 _seekptr = _data.get() + used;
720
721 // Adjust the size
722 _nbytes = size;
723 }
724
725 return *this;
726 }
727
728 /// \brief Dump the internal data of this class in a human readable form.
729 /// This should only be used for debugging purposes.
730 void
dump(std::ostream & os) const731 Buffer::dump(std::ostream& os) const
732 {
733 os << "Buffer is " << _seekptr-_data.get() << "/" << _nbytes << " bytes: ";
734 // Skip in-memory address " at " << (void *)_data.get() << endl;
735 if (_nbytes > 0) {
736 const size_t bytes = _seekptr - _data.get();
737 os << gnash::hexify((unsigned char *)_data.get(), bytes, false)
738 << std::endl;
739 os << gnash::hexify((unsigned char *)_data.get(), bytes, true)
740 << std::endl;
741 } else {
742 os << "ERROR: Buffer size out of range!" << std::endl;
743 }
744 }
745
746 /// \brief Corrupt a buffer with random errors.
747 /// This is used only for testing to make sure we can cleanly
748 /// handle corruption of the packets.
749 ///
750 /// @param factor A divisor to adjust how many errors are created.
751 ///
752 /// @return nothing
753 int
corrupt()754 Buffer::corrupt()
755 {
756 return corrupt(10);
757 }
758
759 int
corrupt(int factor)760 Buffer::corrupt(int factor)
761 {
762 boost::mt19937 seed;
763 // Pick the number of errors to create based on the Buffer's data size
764 boost::uniform_int<> errs(1, (_nbytes/factor));
765 int errors = errs(seed);
766 gnash::log_debug(_("Creating %d errors in the buffer"), errors);
767
768 for (int i=0; i<errors; i++) {
769 // find a location someplace within the file.
770 boost::uniform_int<> location(0, _nbytes);
771 int pos = location(seed);
772
773 // log_debug("Creating error at %d in the buffer", pos);
774 // Create a random new value for the byte
775 boost::uniform_int<> shift(1, 256);
776 int newval = shift(seed);
777 // stomp the old value for our new one.
778 _data[pos] = newval;
779 }
780
781 return errors;
782 }
783
784 } // end of amf namespace
785
786 // local Variables:
787 // mode: C++
788 // indent-tabs-mode: nil
789 // End:
790