1 /* libsswf_errormanager.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 error manager 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 #include	"sswf/libsswf.h"
44 
45 using namespace sswf;
46 
47 
48 
49 
50 
51 /////////////////////////////////////////// ErrorManager
52 
53 /** \class sswf::ErrorManager
54  *
55  * \brief This class helps the user to know what errors occur in the library
56  *
57  * This class was introduced in version 1.8.0.
58  *
59  * The ErrorManager class is used to let the library call one of your
60  * function to handle the error (i.e. so you can print out the message,
61  * exit your program, etc.)
62  *
63  * The callback happens at the time the error occurs.
64  *
65  * At this time, only the TagHeader derives from this object. All the
66  * tags and the Actions call the sswf::ErrorManager::OnError()
67  * function.
68  *
69  * \sa sswf::TagHeader
70  */
71 
72 
73 
74 /** \class sswf::ErrorManager::InternalErrorException
75  *
76  * \brief Class defined to throw exceptions in the library.
77  *
78  * Some errors are simply unrecoverable. These errors generate an
79  * exception. At this time, the library will only generate this
80  * InternalErrorException. Later I may add a hiearchy and information
81  * in the exception.
82  *
83  * In general, at this time you should not try to catch these
84  * exceptions. Use them to crash in the library with your debugger
85  * and see what went wrong.
86  *
87  * \sa sswf::ErrorManager
88  * \sa sswf::ErrorManager::ErrorHandler
89  */
90 
91 /** \class sswf::ErrorManager::ErrorHandler
92  *
93  * \brief A sub-class to derive from to receive errors
94  *
95  * This class is used to catch the errors generated by the library
96  * through the error manager. You can setup one error handler
97  * pointer in the library. It is called each time there is an
98  * error letting you application deal with how to display the
99  * error to the end user. By default, the library prints the
100  * error on stderr.
101  *
102  * \sa sswf::ErrorManager::ErrorHandler::OnError(error_code_t errcode, const char *msg) = 0
103  */
104 
105 /** \brief A destructor since the class has a virtual function.
106  *
107  * This destructor ensures that all the destructors from classes
108  * derived from this class are called as expected.
109  */
~ErrorHandler()110 ErrorManager::ErrorHandler::~ErrorHandler()
111 {
112 }
113 
114 
115 /** \fn sswf::ErrorManager::ErrorHandler::OnError(error_code_t errcode, const char *msg) = 0
116  *
117  * \brief Function to overload to catch errors.
118  *
119  * To catch the errors, derive from the ErrorHandler sub-class and
120  * implement this function. It receives the error code and a
121  * message one can print on the screen.
122  *
123  * \param[in] errcode The code of the error being generated
124  * \param[in] msg The message corresponding to the specified errcode
125  *
126  * \return The function is expected to return errcode, but if you want
127  * the library to ignore the error, you can instead return
128  * ERROR_CODE_NONE. In this case, some functions will still fail
129  * and ignore that return code.
130  */
131 
132 
133 
134 
135 
136 /** \enum sswf::ErrorManager::error_code_t
137  *
138  * \brief Enumeration of all the SSWF errors.
139  *
140  * This enumeration is a list of the different errors that can
141  * occur while using the SSWF library. Most errors are considered
142  * bad and should not happen.
143  *
144  * To catch the errors, derive from the ErrorHandler sub-class and
145  * implement the
146  * ErrorManager::ErrorHandler::OnError(error_code_t errcode, const char *message, va_list args)
147  * function.
148  *
149  * If your function generates multiple errors or call sub-functions
150  * which themselves can generate multiple errors, then you can
151  * use the KeepFirst(error_code_t a, error_code_t b) function to
152  * make sure that you keep the first error.
153  *
154  * \code
155  *	ec = ErrorManager::ERROR_CODE_NONE;
156  *	...
157  *	ec = ErrorManager::KeepFirst(ec, SaveMore(obj[idx]));
158  *	...
159  *	return ec;
160  * \endcode
161  */
162 
163 
164 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_NONE
165  *
166  * \brief No error occured.
167  *
168  * This value should never be passed via the OnError() function. However,
169  * some functions return an error and this value can be used when the
170  * function does not generate an error.
171  *
172  * <hr>
173  */
174 
175 
176 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_ACTION_OVERFLOW
177  *
178  * \brief Trying to add too many actions in the same buffer
179  *
180  * Action buffers are limited in the number of actions they can record.
181  * In general this is about 64Kb of action data including constant
182  * strings, dictionaries, etc. In some circumstances, only 255 bytes
183  * are available.
184  *
185  * <hr>
186  */
187 
188 
189 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_BUTTON_MISSING_STATE
190  *
191  * \brief Buttons do not work without at least one state.
192  *
193  * This errors tells you that you are trying to save a button which
194  * has no states whatsoever.
195  *
196  * <hr>
197  */
198 
199 
200 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_CHILDREN_NOT_SUPPORTED
201  *
202  * \brief Tag passed as parent cannot accept children.
203  *
204  * Whenever a tag is created, you need to specify a parent tag.
205  * However, most tags do not accept children. These tags will
206  * generate this error when used as a parent of another tag.
207  *
208  * At this time, only an sswf::TagHeader and sswf::TagSprite can
209  * be used as a parent.
210  *
211  * <hr>
212  */
213 
214 
215 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_ENDED_ACTION_SCRIPT
216  *
217  * \brief The END action was found before the end.
218  *
219  * This error occurs when the list of actions includes an END
220  * action within the list instead of being at the end.
221  *
222  * There is usually no need for you to include the END
223  * action so just don't do so and let the system close your
224  * list of actions as expected.
225  *
226  * <hr>
227  */
228 
229 
230 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_INTERNAL_ERROR
231  *
232  * \brief An error which should never occur!
233  *
234  * This indicates a problem in logic in the library.
235  *
236  * Please report such errors if you can produce them!
237  *
238  * <hr>
239  */
240 
241 
242 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_LABEL_NOT_FOUND
243  *
244  * \brief No label corresponding to a branch instruction was found.
245  *
246  * Branch instructions specify the name of a label to which they
247  * jump. No label with that name could be found in the label block
248  * of action at the same level.
249  *
250  * This happens when the label was not added or when the label
251  * is in a sub-block or a parent block (i.e. you cannot branch
252  * from within a \e With action block to outside of that block.)
253  *
254  * <hr>
255  */
256 
257 
258 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_LABEL_OVERFLOW
259  *
260  * \brief A label is too far from a corresponding branch.
261  *
262  * The distance between a label and a corresponding branch is limited by the
263  * offset one can use with the branch instructions. If the label is too far
264  * (i.e. more than 32Kb before or after), the branch cannot be used and the
265  * library generates this error.
266  *
267  * <hr>
268  */
269 
270 
271 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_MISSING_FRAME_NAME
272  *
273  * \brief A required frame name is missing.
274  *
275  * Some objects such as the WaitForFrame action need to be given the name of
276  * a frame to properly be defined. This error occurs if the name was not
277  * defined or set to the empty string.
278  *
279  * <hr>
280  */
281 
282 
283 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_OBJECT_NOT_FOUND
284  *
285  * \brief An object or a tag could not be found.
286  *
287  * Different functions use references to other objects or tags.
288  * This error occurs if a named object or tag cannot be found
289  * in the list of tags. Verify the names and try again.
290  *
291  * <hr>
292  */
293 
294 
295 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_REGISTER_OVERFLOW
296  *
297  * \brief Too large a register number was specified.
298  *
299  * Registers are limited to 0, 1, 2 and 3 in older versions of SWF.
300  *
301  * In version 7 and over, registers 0 to 255 can be used (255 seems to
302  * be special in some ways though!) within a function.
303  *
304  * If a register number larger than what is allowed is used, the library
305  * generates this error.
306  *
307  * <hr>
308  */
309 
310 
311 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_START_SOUND_NO_INFO
312  *
313  * \brief Cannot create a StartSound tag without information about the sound.
314  *
315  * This error occurs when a StartSound tag is saved without some sound
316  * information (i.e. what sound needs to be started?!)
317  *
318  * \sa sswf::ErrorManager::ERROR_CODE_COMPRESSED_SOUND_8BITS
319  * \sa sswf::ErrorManager::ERROR_CODE_UNSUPPORTED_SOUND_FORMAT
320  *
321  * <hr>
322  */
323 
324 
325 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_COMPRESSED_SOUND_8BITS
326  *
327  * \brief Library cannot compress 8 bits sound data.
328  *
329  * Only 16 bits sound data can be compressed at this time.
330  *
331  * The library may later be capable of converting the 8 bits sound data in
332  * a 16 bits buffer ready for compression.
333  *
334  * \sa sswf::ErrorManager::ERROR_CODE_START_SOUND_NO_INFO
335  * \sa sswf::ErrorManager::ERROR_CODE_UNSUPPORTED_SOUND_FORMAT
336  *
337  * <hr>
338  */
339 
340 
341 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_INCOMPATIBLE_CHILD
342  *
343  * \brief Parent refused that child (by type)
344  *
345  * Whenever a tag is created, you need to specify a parent tag;
346  * except for the sswf::TagHeader object which represents the root
347  * tag.
348  *
349  * The parent tag checks whether it can accept the child depending on its
350  * type. If not, an error is generated and the new tag will have no parent.
351  *
352  * The only two tags which currently accept children are the sswf::TagHeader
353  * and sswf::TagSprite. The sswf::TagSprite has rather limited number of
354  * tags which can be added as a child.
355  *
356  * <hr>
357  */
358 
359 
360 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_UNSUPPORTED_SOUND_FORMAT
361  *
362  * \brief The library does not currently support this sound format.
363  *
364  * Thought the specified sound format is a valid SWF format, it
365  * is not currently supported by the library.
366  *
367  * \sa sswf::ErrorManager::ERROR_CODE_COMPRESSED_SOUND_8BITS
368  * \sa sswf::ErrorManager::ERROR_CODE_START_SOUND_NO_INFO
369  *
370  * <hr>
371  */
372 
373 
374 /** \var sswf::ErrorManager::error_code_t sswf::ErrorManager::ERROR_CODE_max
375  *
376  * \brief The last error + 1
377  *
378  * This value represents the last error + 1.
379  */
380 
381 
382 
383 
384 
385 
386 
387 
388 /** \brief Initializes an error manager
389  *
390  * The constructor sets the number of errors to zero and the error
391  * handler pointer to null.
392  */
ErrorManager(void)393 ErrorManager::ErrorManager(void)
394 {
395 	f_error_count = 0;
396 	f_error_handler = 0;
397 }
398 
399 
400 
401 
402 /** \brief Defines a pointer to a user error handler
403  *
404  * This function is called to define the pointer to use as the
405  * error handler pointer.
406  *
407  * The function returns the current error handler. You may either
408  * call it or ignore it from within your function. By calling it
409  * you in effect create a chain and all error handlers can be called
410  * in this way.
411  *
412  * \note
413  * You should save the returned pointer and restore it when you
414  * are done with your pointer. However, this is not a 100% viable
415  * scheme since another function could add another pointer after
416  * you put yours. Then restoring would in effect prevent the newer
417  * function from being called.
418  *
419  * My point of view is that it won't be necessary to put more than
420  * one error handler in the error manager. If need be, create a
421  * class which handles one to many a bit like the following code:
422  *
423  * \code
424  *	class MyStuff
425  *	{
426  *	public:
427  *		void AddHandler(ErrorHandler *handler)
428  *		{
429  *			f_handlers += handler;
430  *		}
431  *		std::vector<ErrorHandler*>	f_handlers;
432  *		error_code_t OnError(error_code_t errcode, ...)
433  *		{
434  *			for(i = 0; i < f_handlers.size(); ++i) {
435  *				f_handlers[i].OnError(errcode, ...);
436  *			}
437  *			return errcode;
438  *		}
439  *	};
440  * \endcode
441  *
442  * \warning
443  * This function is not visible in the C library. Instead, you need
444  * to use the specialized function:
445  *
446  * \code
447  * void sswf_error_manager_set_callback(struct SSWF_ErrorManager *error_manager, sswf_error_manager_on_error_callback callback);
448  * \endcode
449  *
450  * The error_manager pointer is taken by casting your tag header
451  * as required.
452  *
453  * \param[in] error_handler The handler to attach to this error manager
454  *
455  * \return The previous error handler
456  */
SetErrorHandler(ErrorManager::ErrorHandler * error_handler)457 ErrorManager::ErrorHandler *ErrorManager::SetErrorHandler(ErrorManager::ErrorHandler *error_handler)
458 {
459 	ErrorHandler	*old_handler = f_error_handler;
460 
461 	f_error_handler = error_handler;
462 
463 	return old_handler;
464 }
465 
466 
467 
468 /** \brief Called whenever an error occurs
469  *
470  * This function is called by the library whenever an error occurs
471  * (you can also call it yourself).
472  *
473  * The message and following arguments are defined as for vprintf(3C).
474  *
475  * The error code is defined as one of the ErrorManager error code.
476  *
477  * Each time this function is called, the number of errors is increased.
478  * You can use the sswf::ErrorManager::Count(void) const function to
479  * retrieve the value of the current counter.
480  *
481  * There is no level for errors. All are considered as errors, some are
482  * fatal meaning that the process in progress will end immediately.
483  *
484  * \note
485  * The error code returned by this function is usually the input
486  * error code. The user handler may, however, modify that value
487  * and return any other error code including ERROR_CODE_NONE to
488  * (try to) cancel the error.
489  *
490  * \param[in] errcode On of the ERROR_CODE_... values
491  * \param[in] message The message, can include formatting characters
492  * \param[in] args The arguments for the message formatting characters
493  *
494  * \return An error code; usually the input error code
495  *
496  * \sa sswf::ErrorManager::Count(void) const
497  * \sa sswf::ErrorManager::OnError(error_code_t errcode, const char *message, ...) const
498  */
OnError(error_code_t errcode,const char * message,va_list args) const499 ErrorManager::error_code_t ErrorManager::OnError(error_code_t errcode, const char *message, va_list args) const
500 {
501 	++f_error_count;
502 
503 	char buf[1024];
504 	vsnprintf(buf, sizeof(buf), message, args);
505 	buf[sizeof(buf) - 1] = '\0';
506 
507 	if(f_error_handler != 0) {
508 		// the user handler can modify the returned error code
509 		return f_error_handler->OnError(errcode, buf);
510 	}
511 
512 	fprintf(stderr, "sswf: error: %d: %s\n", errcode, buf);
513 
514 	return errcode;
515 }
516 
517 
518 /** \brief Called whenever an error occurs
519  *
520  * This function is called by the library whenever an error occurs
521  * (you can also call it yourself).
522  *
523  * The message and following arguments are defined as for printf(3C).
524  *
525  * This function simple calls the
526  * sswf::ErrorManager::OnError(error_code_t errcode, const char *message, va_list args) const
527  *
528  * \note
529  * This function is not visible in the C library.
530  *
531  * \param[in] errcode On of the ERROR_CODE_... values
532  * \param[in] message The message, can include formatting characters
533  * \param[in] ... The arguments for the message formatting characters
534  *
535  * \return An error code; usually the input error code
536  *
537  * \sa sswf::ErrorManager::Count(void) const
538  * \sa sswf::ErrorManager::OnError(error_code_t errcode, const char *message, va_list args) const
539  */
OnError(error_code_t errcode,const char * message,...) const540 ErrorManager::error_code_t ErrorManager::OnError(error_code_t errcode, const char *message, ...) const
541 {
542 	va_list args;
543 	va_start(args, message);
544 	errcode = OnError(errcode, message, args);
545 	va_end(args);
546 	return errcode;
547 }
548 
549 
550 /** \brief Reset the error counter
551  *
552  * This function resets the error counter. The counter is set to
553  * zero on creation of an ErrorManager object. It is increased each
554  * time the OnError() function is called and can be retrieved using
555  * the Count() function.
556  *
557  * \sa sswf::ErrorManager::ErrorManager(void)
558  * \sa sswf::ErrorManager::OnError(error_code_t errcode, const char *message, va_list args) const
559  * \sa sswf::ErrorManager::OnError(error_code_t errcode, const char *message, ...) const
560  * \sa sswf::ErrorManager::Count(void) const
561  */
Reset(void)562 void ErrorManager::Reset(void)
563 {
564 	f_error_count = 0;
565 }
566 
567 
568 /** \brief Retrieve the value of the current error counter
569  *
570  * This function can be used to retrieve the current error
571  * counter. This is set to zero on creation of an error
572  * manager and whenever the Reset() function is called.
573  *
574  * You can use this counter to print out the total number of
575  * errors which occured once a function you called returns.
576  *
577  * \return The number of errors so far or zero when no errors occured
578  *
579  * \sa sswf::ErrorManager::ErrorManager(void)
580  * \sa sswf::ErrorManager::OnError(error_code_t errcode, const char *message, va_list args) const
581  * \sa sswf::ErrorManager::OnError(error_code_t errcode, const char *message, ...) const
582  * \sa sswf::ErrorManager::Reset(void)
583  */
Count(void) const584 int ErrorManager::Count(void) const
585 {
586 	return f_error_count;
587 }
588 
589 
590 
591 /** \brief Keep the first error if not NONE, otherwise keep the second
592  *
593  * This function returns the first error code (a) if it is not
594  * ErrorManager::ERROR_CODE_NONE, otherwise it returns the second
595  * error code (b).
596  *
597  * This is used in many functions where an error does not stop the
598  * function processing. Instead the very first error generated is
599  * kept and returned to the caller.
600  *
601  * This is especially useful to generate as many errors as possible
602  * without requiring the user to re-run the Save() process 100 times
603  * if there are 100 errors.
604  *
605  * \sa sswf::ErrorManager::error_code_t
606  * \sa sswf::ErrorManager::OnError(error_code_t errcode, const char *msg)
607  */
KeepFirst(error_code_t a,error_code_t b)608 ErrorManager::error_code_t ErrorManager::KeepFirst(error_code_t a, error_code_t b)
609 {
610 	if(a == ErrorManager::ERROR_CODE_NONE) {
611 		return b;
612 	}
613 
614 	return a;
615 }
616 
617 
618 /* The following options fold the documentation; use 'zi' to turn on and off
619  *
620  * vim: foldexpr=getline(v\:lnum)!~'^/\\*\\*'&&getline(v\:lnum)!~'^\ \\*'?0\:1 foldcolumn=2 foldmethod=expr
621  */
622