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