1 /* libsswf_file.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2002-2008 */
2 
3 /*
4 
5 Copyright (c) 2002-2008 Made to Order Software Corp.
6 
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16 
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31 
32 */
33 
34 /** \file
35  *
36  * \brief The implementation of the sswf::Data class
37  *
38  * This file declares the body of the functions which are not
39  * inline. It is part of the SSWF library.
40  */
41 
42 
43 
44 #include	"sswf/libsswf.h"
45 
46 using namespace sswf;
47 
48 
49 
50 
51 
52 
53 
54 
55 /////////////////////////////////////////// Data
56 
57 /** \class sswf::Data
58  *
59  * \brief Buffer object used to save the SWF movie
60  *
61  * This object is a buffer used to save the SWF movie in a memory
62  * buffer.
63  *
64  * It grows as required and has functions specific to SWF such
65  * as Align() and WriteBits().
66  *
67  * \sa sswf::Data::Align()
68  * \sa sswf::Data::WriteBits()
69  */
70 
71 
72 /** \brief Initialize a Data buffer
73  *
74  * This function initializes a Data buffer. By default, a Data
75  * buffer is empty.
76  */
Data()77 Data::Data()
78 {
79 	f_pos = 0;
80 	f_size = 0;
81 	f_data = 0;
82 }
83 
84 
85 /** \brief Cleanup a Data buffer
86  *
87  * This function does nothing since the memory used by the Data
88  * buffer is managed by the memory manager directly.
89  */
~Data()90 Data::~Data()
91 {
92 	// the memory manager takes care of everything here
93 }
94 
95 
96 /** \fn sswf::Data::Empty()
97  *
98  * \brief Reset the size
99  *
100  * This function marks the Data buffer as empty.
101  *
102  * All the data previously saved in this buffer is lost.
103  */
104 
105 
106 /** \fn sswf::Data::GetSize() const
107  *
108  * \brief Returns the current size of the buffer
109  *
110  * Returns the size of the buffer in bits. This is the exact position
111  * in the buffer.
112  *
113  * In general, one needs to call ByteSize() instead.
114  *
115  * \return The size of the buffer in bits
116  */
117 
118 
119 /** \fn sswf::Data::ByteSize() const
120  *
121  * \brief Returns the size of the buffer in bytes
122  *
123  * Returns the size of the buffer in bytes. The exact size of the
124  * buffer is in bits. The byte size is the bit size rounded up.
125  *
126  * \return The size of the buffer in bytes
127  */
128 
129 
130 /** \brief Align the buffer position to the next byte
131  *
132  * Whenever writing an SWF movie, it is most often compressed
133  * on bytes and quite often on bits. Whenever bits are used to
134  * save one structure (such as a rectangle), the following data
135  * which are aligned on a byte need to appear on a byte.
136  *
137  * This function ensures that this is indeed the case.
138  *
139  * This function can safely be called multiple times in a raw.
140  * The position will be adjusted only the first time and only
141  * if necessary.
142  */
Align(void)143 void Data::Align(void)
144 {
145 	// align to the next byte
146 	f_pos = (f_pos + CHAR_BIT - 1) & -CHAR_BIT;
147 }
148 
149 
150 /** \brief Make sure that the buffer is at least of that size
151  *
152  * This function ensures that the output buffer is at least of
153  * the specified number of bits (notice: BITS, bot BYTES.)
154  *
155  * This is used to create a buffer for a tag that can later be
156  * modified with the Overwrite functions.
157  *
158  * \param[in] size The new buffer size in bits
159  *
160  * \sa sswf::Data::Overwrite
161  * \sa sswf::Data::OverwriteByte
162  * \sa sswf::Data::OverwriteShort
163  * \sa sswf::Data::OverwriteLong
164  */
AdjustSize(size_t size)165 void Data::AdjustSize(size_t size)
166 {
167 	int		pos;
168 
169 	if(size > f_size) {
170 		// got to enlarge the buffer (adjust to the next 256 bytes)
171 		pos = f_size / CHAR_BIT;
172 		f_size = (f_pos + size + CHAR_BIT * 256 - 1) & -(CHAR_BIT * 256);
173 		f_data = (char *) MemRealloc(f_data, f_size / CHAR_BIT, "Data buffer");
174 
175 		// clear so bits can safely be saved
176 		memset(f_data + pos, 0, f_size / CHAR_BIT - pos);
177 	}
178 }
179 
180 
181 /** \brief Set the size in bits
182  *
183  * This function can be used to shrink the buffer.
184  *
185  * This is used after an AdjustSize() with a size which was too large.
186  *
187  * In general, because the resulting size is determined after
188  * compression.
189  *
190  * \param[in] size The new bit size of the buffer
191  */
SetSize(unsigned long size)192 void Data::SetSize(unsigned long size)
193 {
194 	assert(size <= f_pos, "can't enlarge a data object with a call to the SetSize() function");
195 
196 	f_pos = size;
197 }
198 
199 
200 /** \brief Overwrite data at the specified offset
201  *
202  * This function is used to overwrite data at offset on size bytes
203  * with the data pointed by ptr. This function will not enlarge
204  * the Data buffer and thus is must be used to overwrite only.
205  *
206  * \sa sswf::Data::OverwriteByte
207  * \sa sswf::Data::OverwriteShort
208  * \sa sswf::Data::OverwriteLong
209  */
Overwrite(size_t offset,const void * ptr,size_t size)210 void Data::Overwrite(size_t offset, const void *ptr, size_t size)
211 {
212 	assert(offset + size < f_pos / CHAR_BIT, "trying to overwrite outside the buffer");
213 	memcpy(f_data + offset, ptr, size);
214 }
215 
216 
217 /** \brief Overwrite data at the specified offset
218  *
219  * This function is used to overwrite one byte at the specified
220  * offset. This function will not enlarge the Data buffer and
221  * thus is must be used to overwrite only.
222  *
223  * \sa sswf::Data::Overwrite
224  * \sa sswf::Data::OverwriteShort
225  * \sa sswf::Data::OverwriteLong
226  */
OverwriteByte(size_t offset,char c)227 void Data::OverwriteByte(size_t offset, char c)
228 {
229 	assert(offset + 1 < f_pos / CHAR_BIT, "trying to overwrite outside the buffer");
230 	f_data[offset] = c;
231 }
232 
233 
234 /** \brief Overwrite data at the specified offset
235  *
236  * This function is used to overwrite one short at the specified
237  * offset. This function will not enlarge the Data buffer and
238  * thus is must be used to overwrite only.
239  *
240  * The short value is saved in little endian (least significant
241  * byte first.)
242  *
243  * \sa sswf::Data::Overwrite
244  * \sa sswf::Data::OverwriteByte
245  * \sa sswf::Data::OverwriteLong
246  */
OverwriteShort(size_t offset,short s)247 void Data::OverwriteShort(size_t offset, short s)
248 {
249 	assert(offset + 2 < f_pos / CHAR_BIT, "trying to overwrite outside the buffer");
250 	f_data[offset] = (char) s;
251 	f_data[offset + 1] = (char) (s >> 8);
252 }
253 
254 
255 /** \brief Overwrite data at the specified offset
256  *
257  * This function is used to overwrite one long at the specified
258  * offset (i.e. 4 bytes). This function will not enlarge the Data
259  * buffer and thus is must be used to overwrite only.
260  *
261  * The long value is saved in little endian (least significant
262  * byte first.)
263  *
264  * \sa sswf::Data::Overwrite
265  * \sa sswf::Data::OverwriteByte
266  * \sa sswf::Data::OverwriteShort
267  */
OverwriteLong(size_t offset,long l)268 void Data::OverwriteLong(size_t offset, long l)
269 {
270 	assert(offset + 4 < f_pos / CHAR_BIT, "trying to overwrite outside the buffer");
271 	f_data[offset    ] = (char) l;
272 	f_data[offset + 1] = (char) (l >> 8);
273 	f_data[offset + 2] = (char) (l >> 16);
274 	f_data[offset + 3] = (char) (l >> 24);
275 }
276 
277 
278 /** \brief Write data at the end of the buffer
279  *
280  * This function writes size bytes from ptr at the end of the
281  * buffer. It automatically calls Align() to make sure that
282  * the alignment is correct.
283  *
284  * \param[in] ptr The pointer to the data to append
285  * \param[in] size The number of bytes to append
286  */
Write(const void * ptr,size_t size)287 void Data::Write(const void *ptr, size_t size)
288 {
289 	size_t		bit_size;
290 
291 	Align();
292 	bit_size = size * CHAR_BIT;
293 	AdjustSize(f_pos + bit_size);
294 	memcpy(f_data + f_pos / CHAR_BIT, ptr, size);
295 	f_pos += bit_size;
296 
297 #if DEBUG
298 MemTest(f_data);
299 #endif
300 }
301 
302 
303 
304 /** \brief Write bits at the end of the buffer
305  *
306  * This function writes the specified number of bits from the specified
307  * value.
308  *
309  * The least significant bits of value are used. Thus, a 1 bit value is
310  * defined as 0 or 1. A 2 bits value is defined as 0, 1, 2 or 3. And so
311  * on...
312  *
313  * It is valid to save up to 31 bits with this function. In debug mode,
314  * the function asserts if it looks like the parameters are invalid.
315  *
316  * \param[in] value The value of which bits are saved
317  * \param[in] bits The number of bits to be saved
318  */
WriteBits(long value,size_t bits)319 void Data::WriteBits(long value, size_t bits)
320 {
321 	int		top;
322 
323 	assert(bits >= 32 || ((-1 << bits) & value) == 0 || ((-1 << bits) & value) == (-1 << bits),
324 			"WriteBits() used to write %d bits of 0x%08lX - bits are lost", (int) bits, value);
325 
326 	AdjustSize(f_pos + bits);
327 
328 	top = sizeof(long) * CHAR_BIT - bits;
329 	if(top != 0) {		// avoid a shift by zero which doesn't always work (system dependent)
330 		value <<= top;	// put the 1st bit (most significant) in the sign bit
331 	}
332 
333 	// TODO: there are much more efficent ways to do that by calculating shift values and
334 	// shifting 1 to 8 bits in place instead of looping like crazy!!!
335 	while(bits > 0) {
336 		bits--;
337 		if(value < 0) {
338 			f_data[f_pos / CHAR_BIT] |= (1 << (CHAR_BIT - 1 - (f_pos & (CHAR_BIT - 1))));
339 		}
340 		f_pos++;
341 		value *= 2;
342 	}
343 }
344 
345 
346 /** \brief Save one byte
347  *
348  * This is a convenient function used to save one byte in the
349  * Data buffer.
350  *
351  * This function implicitly calls Align().
352  *
353  * \param[in] c The byte to save
354  *
355  * \sa sswf::Data::PutShort()
356  * \sa sswf::Data::PutLong()
357  * \sa sswf::Data::PutDLong()
358  * \sa sswf::Data::PutShortFloat()
359  * \sa sswf::Data::PutLongFloat()
360  * \sa sswf::Data::PutDoubleFloat()
361  * \sa sswf::Data::PutString()
362  */
PutByte(char c)363 void Data::PutByte(char c)
364 {
365 	Write(&c, 1);
366 }
367 
368 
369 /** \brief Save one short
370  *
371  * This is a convenient function used to save one short in the
372  * Data buffer.
373  *
374  * The short least significant byte is saved first.
375  *
376  * This function implicitly calls Align().
377  *
378  * \param[in] s The short to save
379  *
380  * \sa sswf::Data::PutByte()
381  * \sa sswf::Data::PutLong()
382  * \sa sswf::Data::PutDLong()
383  * \sa sswf::Data::PutShortFloat()
384  * \sa sswf::Data::PutLongFloat()
385  * \sa sswf::Data::PutDoubleFloat()
386  * \sa sswf::Data::PutString()
387  */
PutShort(short s)388 void Data::PutShort(short s)
389 {
390 	PutByte((char) s);
391 	PutByte((char) (s >> 8));
392 }
393 
394 
395 /** \brief Save one 32 bits long
396  *
397  * This is a convenient function used to save one long in the
398  * Data buffer.
399  *
400  * The long least significant byte is saved first.
401  *
402  * This function implicitly calls Align().
403  *
404  * \param[in] l The long to save
405  *
406  * \sa sswf::Data::PutByte()
407  * \sa sswf::Data::PutShort()
408  * \sa sswf::Data::PutDLong()
409  * \sa sswf::Data::PutShortFloat()
410  * \sa sswf::Data::PutLongFloat()
411  * \sa sswf::Data::PutDoubleFloat()
412  * \sa sswf::Data::PutString()
413  */
PutLong(long l)414 void Data::PutLong(long l)
415 {
416 	PutByte((char) l);
417 	PutByte((char) (l >> 8));
418 	PutByte((char) (l >> 16));
419 	PutByte((char) (l >> 24));
420 }
421 
422 
423 /** \brief Save one 64 bits long
424  *
425  * This is a convenient function used to save one 64 bits long
426  * in the Data buffer.
427  *
428  * The long least significant byte is saved first.
429  *
430  * This function implicitly calls Align().
431  *
432  * \param[in] ll The 64 bits long to save
433  *
434  * \sa sswf::Data::PutByte()
435  * \sa sswf::Data::PutShort()
436  * \sa sswf::Data::PutLong()
437  * \sa sswf::Data::PutShortFloat()
438  * \sa sswf::Data::PutLongFloat()
439  * \sa sswf::Data::PutDoubleFloat()
440  * \sa sswf::Data::PutString()
441  */
PutDLong(int64_t ll)442 void Data::PutDLong(int64_t ll)
443 {
444 	PutByte((char) ll);
445 	PutByte((char) (ll >> 8));
446 	PutByte((char) (ll >> 16));
447 	PutByte((char) (ll >> 24));
448 	PutByte((char) (ll >> 32));
449 	PutByte((char) (ll >> 40));
450 	PutByte((char) (ll >> 48));
451 	PutByte((char) (ll >> 56));
452 }
453 
454 
455 /** \brief Save one 16 bits floating point in IEEE format.
456  *
457  * This is a convenient function used to save a floating point
458  * on 16 bits. This is not a fixed point value, it really is
459  * a floating point defined as:
460  *
461  * \li 1 bit of sign
462  * \li 5 bits of exponent
463  * \li 10 bits of mantissa
464  *
465  * \bug
466  * This function assumes that the input floating point is
467  * a valid number, not a NaN. Your SWF will work better that
468  * way anyway.
469  *
470  * \param[in] f The floating point to convert and save
471  *
472  * \sa sswf::Data::PutByte()
473  * \sa sswf::Data::PutShort()
474  * \sa sswf::Data::PutLong()
475  * \sa sswf::Data::PutDLong()
476  * \sa sswf::Data::PutLongFloat()
477  * \sa sswf::Data::PutDoubleFloat()
478  * \sa sswf::Data::PutString()
479  */
PutShortFloat(float f)480 void Data::PutShortFloat(float f)
481 {
482 	float		*fn = &f;
483 	uint32_t	v = *reinterpret_cast<uint32_t *>(fn);
484 	uint16_t	s = 0;
485 	int		exponent;
486 	unsigned int	mantissa;
487 
488 // copy the sign
489 	if(v & 0x80000000) {
490 		s |= 0x8000;
491 	}
492 
493 // extract exponent and mantissa
494 	exponent = ((v & 0x7F800000) >> 23) - 127;
495 	mantissa = v & 0x007FFFFF;
496 
497 	// TODO: check for denormalized numbers, NaN and other
498 	// goodies (i.e. exponent == -127 here means a special
499 	// number; also 128 is a special case we do not handle)
500 
501 // check underflow and overflow of exponent
502 	if(exponent < -16) {
503 		// value is so small that it is like zero
504 		exponent = 0;
505 		mantissa = 0;
506 		s = 0;
507 	}
508 	else if(exponent > 15) {
509 		// value is way big, put the maximum supported by this format
510 		exponent = 15;
511 		mantissa = 0x007FFFFF;
512 	}
513 
514 // save the exponent and mantissa in new floating point
515 	s |= (exponent & 0x1F) << 10;
516 	s |= mantissa >> 13;
517 
518 // save the result
519 	PutShort(s);
520 }
521 
522 
523 /** \brief Save one 32 bits floating point in IEEE format.
524  *
525  * This is a convenient function used to save a 32 bits floating
526  * point.
527  *
528  * \param[in] f The floating point to save
529  *
530  * \sa sswf::Data::PutByte()
531  * \sa sswf::Data::PutShort()
532  * \sa sswf::Data::PutLong()
533  * \sa sswf::Data::PutDLong()
534  * \sa sswf::Data::PutShortFloat()
535  * \sa sswf::Data::PutDoubleFloat()
536  * \sa sswf::Data::PutString()
537  */
PutLongFloat(float f)538 void Data::PutLongFloat(float f)
539 {
540 	float *fn = &f;
541 	long l = *reinterpret_cast<long *>(fn);
542 	PutLong(l);
543 }
544 
545 
546 /** \brief Save one 64 bits floating point in IEEE format.
547  *
548  * This is a convenient function used to save a 64 bits floating
549  * point.
550  *
551  * \param[in] d The floating point to save
552  *
553  * \sa sswf::Data::PutByte()
554  * \sa sswf::Data::PutShort()
555  * \sa sswf::Data::PutLong()
556  * \sa sswf::Data::PutDLong()
557  * \sa sswf::Data::PutShortFloat()
558  * \sa sswf::Data::PutLongFloat()
559  * \sa sswf::Data::PutString()
560  */
PutDoubleFloat(double d)561 void Data::PutDoubleFloat(double d)
562 {
563 	double *dn = &d;
564 	uint64_t l = *reinterpret_cast<uint64_t *>(dn);
565 	PutDLong(l);
566 }
567 
568 
569 /** \brief Save one string
570  *
571  * This is a convenient function used to save a string in the
572  * Data buffer.
573  *
574  * It is valid to call the function with a NULL pointer. It is
575  * considered to be an empty string and just one zero byte is
576  * written.
577  *
578  * Otherwise, strlen(string) + 1 bytes are saved (i.e. the string
579  * characters and the nul terminator.)
580  *
581  * This function implicitly calls Align().
582  *
583  * \param[in] string The string to save
584  *
585  * \sa sswf::Data::PutByte()
586  * \sa sswf::Data::PutShort()
587  * \sa sswf::Data::PutLong()
588  * \sa sswf::Data::PutDLong()
589  * \sa sswf::Data::PutShortFloat()
590  * \sa sswf::Data::PutLongFloat()
591  * \sa sswf::Data::PutDoubleFloat()
592  */
PutString(const char * string)593 void Data::PutString(const char *string)
594 {
595 	if(string == 0) {
596 		// an empty string
597 		PutByte(0);
598 	}
599 	else {
600 		Write(string, strlen(string) + 1);
601 	}
602 }
603 
604 
605 
606 
607 /** \brief Append another Data buffer
608  *
609  * This function appends a Data buffer to this Data buffer.
610  *
611  * The source Data buffer is not modified.
612  *
613  * The destination is first aligned with a call to Align(). The
614  * buffer is grown as required, then the source is copied at the
615  * end of the destination.
616  *
617  * \param[in] data The source Data buffer
618  */
Append(const Data & data)619 void Data::Append(const Data& data)
620 {
621 	int		sz;
622 
623 	Align();
624 	// data.Align() -- we can't do that on a constant
625 	// so we compute sz as the aligned f_pos and use
626 	// that instead
627 	sz = (data.f_pos + CHAR_BIT - 1) & -CHAR_BIT;
628 	AdjustSize(f_pos + sz);
629 	memcpy(f_data + f_pos / CHAR_BIT, data.f_data, sz / CHAR_BIT);
630 	f_pos += sz;
631 
632 #if DEBUG
633 MemTest(f_data);
634 #endif
635 }
636 
637 
638 /** \brief Read the data buffer information
639  *
640  * This function can be used to get access to the internal buffer
641  * pointer and size.
642  *
643  * In general, this function is used at the end to save the Data
644  * buffer in a file.
645  *
646  * This function implicitly calls Align().
647  *
648  * \bug
649  * Warning: this function returns direct access to the internal buffer
650  * pointer and size. If any other function is used, it invalidates
651  * these pointers. So use them, and forget about them right away!
652  *
653  * \param[out] ptr Receives the Data buffer pointer
654  * \param[out] size Receives the size in bytes of the buffer pointer
655  */
Read(void * & ptr,size_t & size)656 void Data::Read(void *& ptr, size_t& size)
657 {
658 	Align();
659 	ptr = f_data;
660 	size = f_pos / CHAR_BIT;
661 }
662 
663 
664 
665 
666 
667 
668 /* The following options fold the documentation; use 'zi' to turn on and off
669  *
670  * vim: foldexpr=getline(v\:lnum)!~'^/\\*\\*'&&getline(v\:lnum)!~'^\ \\*'?0\:1 foldcolumn=2 foldmethod=expr
671  */
672