1 /* sswf_save.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2002-2009 */
2 
3 /*
4 
5 Copyright (c) 2002-2009 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 #define	SSWF_NEED_ASSERT
35 #include	"sswf.h"
36 #include	"sswf/libsswf.h"
37 #include	"sswf/libsswf_asas.h"
38 
39 
40 #ifdef SSWF_INTERNAL_ASC
41 #include	"sswf/libsswf_asc.h"
42 #endif
43 
44 
45 
46 
47 // Special class so the Import tag looks like
48 // it is derived from the TagBaseID class!
49 // This is specific to sswf_save.c++ only and
50 // it doesn't need to be fully functional.
51 // (we need to be capable of retrieving the
52 // proper identifiers at the proper time)
53 class TagImportID : public sswf::TagBaseID
54 {
55 public:
TagImportID(sswf::TagImport & import,sswf::sswf_id_t id,const char * name="import-id")56 				TagImportID(sswf::TagImport& import, sswf::sswf_id_t id, const char *name = "import-id")
57 					: TagBaseID(name, import.Parent()), f_import(import), f_id(id)
58 				{
59 					// we don't have, want or need
60 					// any identification for this
61 					// object!
62 					NoIdentification();
63 				}
64 
Identification(void) const65 	virtual sswf::sswf_id_t	Identification(void) const
66 				{
67 					return f_id;
68 				}
69 
70 	virtual sswf::ErrorManager::error_code_t
Save(sswf::Data & data)71 				Save(sswf::Data& data)
72 				{
73 					// this is not a real tag, there is nothing to save
74 					return sswf::ErrorManager::ERROR_CODE_NONE;
75 				}
76 	virtual sswf::TagBase::swf_type_t
TypeFlags(void) const77 				TypeFlags(void) const
78 				{
79 					return 0;
80 				}
81 
82 private:
83 	sswf::TagImport&	f_import;	// the real import tag
84 	const sswf::sswf_id_t	f_id;		// this specific TagImportID identification
85 };
86 
87 
88 
89 
90 
91 
92 struct property_t {
93 	const char *	name;
94 	int		value;
95 };
96 
97 static const property_t direct_properties[] = {
98 	{ "X",				 0 },
99 	{ "Y",				 1 },
100 	{ "X.SCALE",			 2 },
101 	{ "Y.SCALE",			 3 },
102 	{ "CURRENT.FRAME",		 4 },
103 	{ "NUMBER.OF.FRAMES",		 5 },
104 	{ "ALPHA",			 6 },
105 	{ "VISIBILITY",			 7 },
106 	{ "WIDTH",			 8 },
107 	{ "HEIGHT",			 9 },
108 	{ "ROTATION",			10 },
109 	{ "TARGET",			11 },
110 	{ "FRAMES.LOADED",		12 },
111 	{ "NAME",			13 },
112 	{ "DROP.TARGET",		14 },
113 	{ "URL",			15 },
114 	{ "HIGH.QUALITY",		16 },
115 	{ "SHOW.FOCUS.RECTANGLE",	17 },
116 	{ "SOUND.BUFFER.TIME",		18 },
117 	{ "QUALITY",			19 },
118 	{ "X.MOUSE",			20 },
119 	{ "Y.MOUSE",			21 },
120 	{ "WTHIT",			16384 },
121 
122 	{ NULL, 0 }
123 };
124 
125 
126 
127 class SaveState : public sswf::MemoryManager
128 {
129 public:
130 	class ObjectItem : public sswf::ItemBase {
131 	public:
ObjectItem(const char * name,sswf::TagBaseID * object)132 					ObjectItem(const char *name, sswf::TagBaseID *object)
133 					{
134 						f_name = name;
135 						f_object = object;
136 					}
~ObjectItem()137 					~ObjectItem()
138 					{
139 						sswf_free(const_cast<char *>(f_name));
140 					}
Name(void) const141 		const char *		Name(void) const { return f_name; }
Object(void) const142 		const sswf::TagBaseID *	Object(void) const { return f_object; }
143 
144 	private:
145 		const char *		f_name;		// name of the object
146 		sswf::TagBaseID *	f_object;	// only objects with an ID and TagImport are necessary
147 	};
148 
SaveState(void)149 					SaveState(void)
150 					{
151 						f_parent = 0;
152 						f_d = 0;
153 						f_last_label = 0;
154 						f_function_level = 0;
155 						f_memory_manager = 0;
156 						f_actions = 0;
157 					}
~SaveState()158 	virtual				~SaveState() {}
159 
160 	void				SetLabel(sswf::TagBase *object, const char *def_label);
161 	void				RecordRef(sswf::TagBaseID *object, const char *import_name = 0);
162 	const sswf::TagBaseID *		FindRef(const char *name, const char *type);
163 
164 	sswf::TagHeader			f_header;	// the header
165 	sswf::TagBase *			f_parent;	// the current parent (header or sprite)
166 	const struct data_common_t *	f_d;		// the data to be analyzed
167 	const struct data_common_t *	f_current_cd;	// the currently analyzed data
168 	const char *			f_last_label;	// last label found
169 
170 	// actions related
171 	unsigned long			f_function_level;// when > 0, we're inside a function (note that a function can include another since a function can define a function member to an object)
172 	sswf::MemoryManager *		f_memory_manager;// where the actions need to be attached
173 	sswf::Vectors *			f_actions;	// used to save a list of actions
174 
175 private:
176 	sswf::Vectors			f_refs;		// a list of names & objects (struct object_item_t)
177 };
178 
179 
180 typedef	int			(*save_child_func)(SaveState& state);
181 
182 struct tag_list_t {
183 	enum node_type_t	type;
184 	save_child_func		func;
185 };
186 
187 
188 
SetLabel(sswf::TagBase * object,const char * def_label=0)189 void SaveState::SetLabel(sswf::TagBase *object, const char *def_label = 0)
190 {
191 	// NOTE: labels are used for the Goto's and WaitForFrame's
192 	//	 within the SWF library; that's it
193 	if(f_d->name_len > 0) {
194 		object->SetLabel(f_d->name);
195 	}
196 	else if(f_last_label != 0) {
197 		const_cast<struct data_common_t *>(f_d)->label = f_last_label;
198 		object->SetLabel(f_last_label);
199 	}
200 	else if(def_label != 0) {
201 		const_cast<struct data_common_t *>(f_d)->label = def_label;
202 		object->SetLabel(def_label);
203 	}
204 	f_last_label = 0;		// use once only
205 }
206 
207 
RecordRef(sswf::TagBaseID * object,const char * import_name)208 void SaveState::RecordRef(sswf::TagBaseID *object, const char *import_name)
209 {
210 	ObjectItem		*tl;
211 	char			*path, *p;
212 
213 	SetLabel(object);
214 
215 	// save only those which have a name otherwise we
216 	// cannot have a reference anyway!
217 	if(f_d->name_len > 0 || f_d->label != 0) {
218 		if(f_d->node->data == NULL) {
219 			// TODO: this is not enough since each parent
220 			//	 node may likely have a dynamic name!
221 			f_d->node->data = const_cast<data_common_t *>(f_d);
222 			path = node_path(f_d->node, 0);
223 			f_d->node->data = NULL;
224 		}
225 		else {
226 			path = node_path(f_d->node, 0);
227 		}
228 		if(import_name != 0) {
229 			path = sswf_strcat3(p = path, ".", import_name);
230 			sswf_free(p);
231 		}
232 		tl = new ObjectItem(path, object);	// NOTE: the name isn't duplicated!
233 		MemAttach(tl, sizeof(ObjectItem), "reference structure in sswf_save.c++");
234 		f_refs.Set(-1, tl);		// append this new entry
235 	}
236 }
237 
238 
FindRef(const char * name,const char * type)239 const sswf::TagBaseID *SaveState::FindRef(const char *name, const char *type)
240 {
241 	const ObjectItem	*tl;
242 	const sswf::TagBaseID	*obj;
243 	int			max;
244 
245 	max = f_refs.Count();
246 	while(max > 0) {
247 		max--;
248 		tl = dynamic_cast<const ObjectItem *>(f_refs.Get(max));
249 		// TODO: a reference to an imported item is accepted as is...
250 		if(strcmp(tl->Name(), name) == 0 || strcmp(tl->Name(), "imported") == 0) {
251 			obj = tl->Object();
252 			/*
253 			if(strcmp(obj->Name(), "import-id") == 0) {
254 				dynamic_cast<TagImportID *>(obj)->SelectIdentification(name);
255 			}
256 			*/
257 			if(type != 0 && strcmp(obj->Name(), type) != 0) {
258 				fprintf(stderr, "ERROR: reference to \"%s\" needs to be to an object of type: %s.\n", name, type);
259 				errcnt++;
260 				return 0;
261 			}
262 			return obj;
263 		}
264 	}
265 
266 	fflush(stdout);
267 	fprintf(stderr, "ERROR: the named reference \"%s\" was not found.\n", name);
268 	errcnt++;
269 
270 	return 0;
271 }
272 
273 
274 
275 
276 /*
277  * Lists & blocks call this function so their children are saved
278  * as if included as is in the sequence.
279  */
280 static int		save_child(SaveState& state);
281 
282 
283 
284 
save_action_branch(SaveState & state,sswf::Action::action_t action,const struct data_list_t * list)285 static sswf::Action *save_action_branch(SaveState& state, sswf::Action::action_t action, const struct data_list_t *list)
286 {
287 	const struct data_common_t	*cd;
288 	sswf::ActionBranch		*branch;
289 	int				idx, max;
290 
291 	branch = new sswf::ActionBranch(state.f_parent, action);
292 	if(branch == 0) {
293 		return 0;
294 	}
295 
296 	max = list->count;
297 	for(idx = 0; idx < max; idx++) {
298 		cd = dc_item(list, idx);
299 		if(cd->type == NODE_TYPE_STRING) {
300 			branch->SetLabel(cd->name);
301 		}
302 		else {
303 			assert(0, "unknown data type (%d) for an action LABEL", cd->type);
304 			/*NOTREACHED*/
305 		}
306 	}
307 
308 	return branch;
309 }
310 
311 
312 
save_action_call_frame(SaveState & state,sswf::Action::action_t,const struct data_list_t *)313 static sswf::Action *save_action_call_frame(SaveState& state, sswf::Action::action_t /*action*/, const struct data_list_t * /*list*/)
314 {
315 	return new sswf::ActionCallFrame(state.f_parent);
316 }
317 
318 
319 
save_action_dictionary(SaveState & state,sswf::Action::action_t action,const struct data_list_t * list)320 static sswf::Action *save_action_dictionary(SaveState& state, sswf::Action::action_t action, const struct data_list_t *list)
321 {
322 	const struct data_common_t	*cd;
323 	sswf::ActionDictionary		*dictionary;
324 	int				idx, max;
325 
326 	dictionary = new sswf::ActionDictionary(state.f_parent);
327 	if(dictionary == 0) {
328 		return 0;
329 	}
330 
331 	max = list->count;
332 	for(idx = 0; idx < max; idx++) {
333 		cd = dc_item(list, idx);
334 		if(cd->type == NODE_TYPE_STRING) {
335 			dictionary->AddString(cd->name);
336 		}
337 		else {
338 			assert(0, "unknown data type (%d) for a DICTIONARY action, expected a string", cd->type);
339 			/*NOTREACHED*/
340 		}
341 	}
342 
343 	return dictionary;
344 }
345 
save_action_goto(SaveState & state,sswf::Action::action_t action,const struct data_list_t * list)346 static sswf::Action *save_action_goto(SaveState& state, sswf::Action::action_t action, const struct data_list_t *list)
347 {
348 	struct data_common_t	*cd;
349 	sswf::ActionGoto	*goto_frame;
350 	sswf::ActionPushData	*push_data;
351 	int			idx, max, play;
352 	char			*frame_name;
353 
354 	play = -1;		/* undefined */
355 	frame_name = 0;
356 	max = list->count;
357 	for(idx = 0; idx < max; idx++) {
358 		cd = dc_item(list, idx);
359 		if(list->offset[idx] < 0) {
360 			/* we've got the play flag */
361 			play = ((struct data_goto_play_t *) cd)->play != 0.0 ? 1 : 0;
362 		}
363 		else if(cd->type == NODE_TYPE_STRING){
364 			/* there is a frame name */
365 			frame_name = cd->name;
366 		}
367 		else {
368 			assert(0, "unknown data type (%d) for a GOTO action", cd->type);
369 			/*NOTREACHED*/
370 		}
371 	}
372 
373 	if(frame_name == 0 || action == sswf::Action::ACTION_GOTO_EXPRESSION) {
374 		if(frame_name != 0) {
375 			/* we need to push this string on the stack */
376 			push_data = new sswf::ActionPushData(state.f_parent);
377 			/* this action won't automatically be registered otherwise! */
378 			state.f_memory_manager->MemAttach(push_data, sizeof(sswf::Action), "a PUSH DATA action object for a DoAction or a Button");
379 			push_data->AddString(frame_name);
380 			state.f_actions->Set(-1, push_data);
381 		}
382 		goto_frame = new sswf::ActionGoto(state.f_parent, sswf::Action::ACTION_GOTO_EXPRESSION);
383 		if(goto_frame != 0) {
384 			goto_frame->SetPlay(play != 0);
385 		}
386 	}
387 	else {
388 		if(action == sswf::Action::ACTION_UNKNOWN) {
389 			action = sswf::Action::ACTION_GOTO_FRAME;
390 		}
391 		goto_frame = new sswf::ActionGoto(state.f_parent, action);
392 		if(goto_frame != 0) {
393 			goto_frame->SetFrameName(frame_name);
394 			if(play == 1) {
395 				/* we stack the action right now and add a PLAY instruction right after */
396 				state.f_memory_manager->MemAttach(goto_frame, sizeof(sswf::Action), "an action object for a DoAction or a Button");
397 				state.f_actions->Set(-1, goto_frame);
398 				return new sswf::Action(state.f_parent, sswf::Action::ACTION_PLAY);
399 			}
400 		}
401 	}
402 
403 	return goto_frame;
404 }
405 
save_action_label(SaveState & state,sswf::Action::action_t,const struct data_list_t * list)406 static sswf::Action *save_action_label(SaveState& state, sswf::Action::action_t /*action*/, const struct data_list_t *list)
407 {
408 	const struct data_common_t	*cd;
409 	sswf::ActionLabel		*label;
410 	int				idx, max;
411 
412 	label = new sswf::ActionLabel(state.f_parent);
413 	if(label == 0) {
414 		return 0;
415 	}
416 
417 	max = list->count;
418 	for(idx = 0; idx < max; idx++) {
419 		cd = dc_item(list, idx);
420 		if(cd->type == NODE_TYPE_STRING) {
421 			label->SetLabel(cd->name);
422 		}
423 		else {
424 			assert(0, "unknown data type (%d) for a action LABEL", cd->type);
425 			/*NOTREACHED*/
426 		}
427 	}
428 
429 	return label;
430 }
431 
save_action_pushdata(SaveState & state,sswf::Action::action_t action,const struct data_list_t * list)432 static sswf::Action *save_action_pushdata(SaveState& state, sswf::Action::action_t action, const struct data_list_t *list)
433 {
434 	const struct data_common_t	*cd;
435 	const struct data_push_data_t	*data;
436 	sswf::ActionPushData		*push_data;
437 	int				idx, max;
438 	const property_t		*p;
439 	const char			*name;
440 
441 	push_data = new sswf::ActionPushData(state.f_parent);
442 	if(push_data == 0) {
443 		return 0;
444 	}
445 
446 	max = list->count;
447 	for(idx = 0; idx < max; idx++) {
448 		cd = dc_item(list, idx);
449 		if(list->offset[idx] < 0) {
450 			data = (const struct data_push_data_t *) cd;
451 			switch(static_cast<enum push_data_t>(data->type)) {
452 			case PUSHDATA_INTEGER:
453 				push_data->AddInteger((long) rint(data->value));
454 				break;
455 
456 			case PUSHDATA_DOUBLE:
457 				push_data->AddDouble(data->value);
458 				break;
459 
460 			case PUSHDATA_FLOAT:
461 				push_data->AddFloat((float) data->value);
462 				break;
463 
464 			case PUSHDATA_BOOLEAN:
465 				push_data->AddBoolean(data->value != 0);
466 				break;
467 
468 			case PUSHDATA_REGISTER:
469 				push_data->AddRegister((unsigned char) rint(data->value));
470 				break;
471 
472 			case PUSHDATA_LOOKUP:
473 				push_data->AddLookup((unsigned short) rint(data->value));
474 				break;
475 
476 			case PUSHDATA_NULL:
477 				push_data->AddNull();
478 				break;
479 
480 			case PUSHDATA_UNDEFINED:
481 				push_data->AddUndefined();
482 				break;
483 
484 			case PUSHDATA_PROPERTY:
485 				idx++;
486 				assert(idx < max, "a PROPERTY was specified without a string");
487 				cd = dc_item(list, idx);
488 				name = cd->name;
489 				p = direct_properties;
490 				while(p->name != NULL) {
491 					if(strcmp_action(name, p->name) == 0) {
492 						/* we found the property - add it in Flash V4.0 compatible mode */
493 						push_data->AddFloat((float) p->value);
494 						break;
495 					}
496 					p++;
497 				}
498 				if(p->name == NULL) {
499 					fprintf(stderr, "ERROR: cannot find property \"%s\".\n", cd->name);
500 					errcnt++;
501 				}
502 				break;
503 
504 			case PUSHDATA_STRING:
505 				idx++;
506 				assert(idx < max, "a PROPERTY was specified without a string");
507 				cd = dc_item(list, idx);
508 				if(cd->name_len == 0) {
509 					// in this case cd->name doesn't always point to a '\0'
510 					push_data->AddString("");
511 				}
512 				else {
513 					push_data->AddString(cd->name);
514 				}
515 				break;
516 
517 			}
518 		}
519 		else {
520 			assert(0, "unknown data type (%d) for a PUSH DATA action", cd->type);
521 			/*NOTREACHED*/
522 		}
523 	}
524 
525 	return push_data;
526 }
527 
528 
save_action_store_register(SaveState & state,sswf::Action::action_t action,const struct data_list_t * list)529 static sswf::Action *save_action_store_register(SaveState& state, sswf::Action::action_t action, const struct data_list_t *list)
530 {
531 	struct data_common_t		*cd;
532 	const struct data_register_t	*data;
533 	sswf::ActionStoreRegister	*store_register;
534 	int				idx, max, reg;
535 
536 	store_register = new sswf::ActionStoreRegister(state.f_parent);
537 	if(store_register == 0) {
538 		return 0;
539 	}
540 
541 	max = list->count;
542 	for(idx = 0; idx < max; idx++) {
543 		cd = dc_item(list, idx);
544 		if(list->offset[idx] < 0) {
545 			data = (const struct data_register_t *) cd;
546 			reg = (int) rint(data->reg);
547 			if(reg < 0
548 			|| (reg >= 4 && state.f_function_level == 0)
549 			|| (reg > 255)) {
550 				fprintf(stderr, "ERROR: invalid register number. Outside a function, only registers 0, 1, 2 and 3 are valid. Inside a function, registers 0 to 255 are valid in a version 7 movie.\n");
551 				errcnt++;
552 			}
553 			store_register->SetRegister((unsigned char) reg);
554 		}
555 		else {
556 			assert(0, "unknown data type (%d) for a STORE REGISTER action", cd->type);
557 			/*NOTREACHED*/
558 		}
559 	}
560 
561 	return store_register;
562 }
563 
564 
save_action_set_target(SaveState & state,sswf::Action::action_t action,const struct data_list_t * list)565 static sswf::Action *save_action_set_target(SaveState& state, sswf::Action::action_t action, const struct data_list_t *list)
566 {
567 	struct data_common_t	*cd;
568 	sswf::ActionSetTarget	*set_target;
569 	sswf::Action		*a;
570 	const char		*target_name;
571 	int			idx, max;
572 
573 	target_name = 0;
574 	if(list != 0) {
575 		max = list->count;
576 		for(idx = 0; idx < max; idx++) {
577 			cd = dc_item(list, idx);
578 			if(cd->type == NODE_TYPE_STRING) {
579 				if(cd->name_len == 0) {
580 					target_name = "";
581 				}
582 				else {
583 					target_name = cd->name;
584 				}
585 			}
586 			else {
587 				assert(0, "unknown data type (%d) for a SET TARGET action", cd->type);
588 				/*NOTREACHED*/
589 			}
590 		}
591 	}
592 
593 	if(target_name == 0) {
594 		a = new sswf::Action(state.f_parent, sswf::Action::ACTION_SET_TARGET2);
595 	}
596 	else {
597 		a = set_target = new sswf::ActionSetTarget(state.f_parent);
598 		if(set_target != 0) {
599 			set_target->SetTarget(target_name);
600 		}
601 	}
602 
603 	return a;
604 }
605 
606 
save_action_url(SaveState & state,sswf::Action::action_t action,const struct data_list_t * list)607 static sswf::Action *save_action_url(SaveState& state, sswf::Action::action_t action, const struct data_list_t *list)
608 {
609 	struct data_common_t	*cd;
610 	sswf::ActionURL		*url;
611 	const char		*url_name, *target_name;
612 	int			idx, max;
613 
614 	url_name = 0;
615 	target_name = 0;
616 	if(list != 0) {
617 		max = list->count;
618 		for(idx = 0; idx < max; idx++) {
619 			cd = dc_item(list, idx);
620 			if(cd->type == NODE_TYPE_STRING && cd->name_len > 0) {
621 				if(idx == 0) {
622 					url_name = cd->name;
623 				}
624 				else {
625 					target_name = cd->name;
626 				}
627 			}
628 			else {
629 				assert(0, "unknown data type (%d) for a URL action", cd->type);
630 				/*NOTREACHED*/
631 			}
632 		}
633 	}
634 	// if no string is specified
635 	// then we are in the case of a URL2 without variables
636 	url = new sswf::ActionURL(state.f_parent,
637 			url_name != 0 && target_name != 0 ? sswf::Action::ACTION_URL : sswf::Action::ACTION_URL2);
638 	if(url == 0) {
639 		return 0;
640 	}
641 
642 	if(url_name != 0) {
643 		if(target_name != 0) {
644 			// both strings defined, assume a direct URL (not URL2)
645 			url->SetURL(url_name, target_name);
646 		}
647 		else {
648 			// only one string, check for the method
649 			if(strcasecmp(url_name, "GET") == 0) {
650 				url->SetMethod(sswf::ActionURL::URL_METHOD_GET);
651 			}
652 			else if(strcasecmp(url_name, "POST") == 0) {
653 				url->SetMethod(sswf::ActionURL::URL_METHOD_GET);
654 			}
655 			else if(strncasecmp(url_name, "NOVAR", 5) == 0) {
656 				url->SetMethod(sswf::ActionURL::URL_METHOD_NOVARIABLE);
657 			}
658 			else {
659 fprintf(stderr, "ERROR: unknown method for a URL instruction; we currently accept GET, POST and NOVAR[IABLE].\n");
660 				errcnt++;
661 			}
662 		}
663 	}
664 	//assert(url_name != 0 && target_name != 0, "one of the url or target was not defined for a URL action");
665 
666 	return url;
667 }
668 
669 
670 static int save_actions(SaveState& state);
save_action_wait_for_frame(SaveState & state,sswf::Action::action_t action,const struct data_list_t * list)671 static sswf::Action *save_action_wait_for_frame(SaveState& state, sswf::Action::action_t action, const struct data_list_t *list)
672 {
673 	const struct data_common_t	*cd, *save;
674 	sswf::Vectors			*previous_actions;
675 	sswf::ActionWaitForFrame	*wff;
676 	int				idx, max;
677 	const char			*frame_name;
678 
679 // we've got to determine the destination frame name first so we can
680 // know whether we need a static or dynamic WaitForFrame tag.
681 	frame_name = 0;
682 	list = dc_list(state.f_current_cd);
683 	max = list->count;
684 	for(idx = 0; idx < max; idx++) {
685 		cd = dc_item(list, idx);
686 		// use the 1st non-null string as the name of the destination frame
687 		if(cd->type == NODE_TYPE_STRING && cd->name_len > 0) {
688 			frame_name = cd->name;
689 			break;
690 		}
691 	}
692 
693 	wff = new sswf::ActionWaitForFrame(state.f_parent,
694 			frame_name == 0 ? sswf::Action::ACTION_WAIT_FOR_FRAME2
695 					: sswf::Action::ACTION_WAIT_FOR_FRAME);
696 	if(wff == 0) {
697 		return 0;
698 	}
699 
700 	if(frame_name != 0) {
701 		wff->SetFrameName(frame_name);
702 	}
703 
704 	save = state.f_d;
705 	previous_actions = state.f_actions;
706 	state.f_d = state.f_current_cd;
707 	state.f_actions = dynamic_cast<sswf::Action *>(wff)->SubList();
708 	save_actions(state);
709 	state.f_d = save;
710 	state.f_actions = previous_actions;
711 
712 	return wff;
713 }
714 
715 
716 
action_set_func_name_n_params(sswf::ActionFunction * func,const char * s)717 static int action_set_func_name_n_params(sswf::ActionFunction *func, const char *s)
718 {
719 	char		*p, *e, *a, c, *end;
720 	int		reg;
721 
722 	while(isspace(*s)) {
723 		s++;
724 	}
725 
726 	// make a copy since we cannot modify the input string
727 	p = func->StrDup(s);
728 
729 	e = p;
730 	while(*e != '\0' && *e != '(' && *e != ')' && *e != ',' && !isspace(*e)) {
731 		e++;
732 	}
733 	c = *e;
734 	*e = '\0';
735 
736 	// set the function name (only the name here)
737 	// Note that the name can be empty and that's fine
738 	func->SetName(p);
739 
740 	while(c != '\0' && c != ')') {
741 		do {
742 			e++;
743 		} while(isspace(*e));
744 		end = 0;
745 		a = e;
746 		while(*e != '\0' && *e != ')' && *e != ',' && !isspace(*e)) {
747 			if(*e == ':') {
748 				end = e;
749 			}
750 			e++;
751 		}
752 		if(a == e) {
753 			// empty parameter names are not accepted - this happens
754 			// when there is one or more spaces before the ')' or
755 			// simple when there isn't any parameter
756 			break;
757 		}
758 		c = *e;
759 		*e = '\0';
760 		if(end != 0) {
761 			*end = '\0';
762 			reg = atol(end + 1);
763 			if(reg < 1 || reg > 255) {
764 				fprintf(stderr, "ERROR: %d is an invalid register specification for a function parameter (the register number must be between 1 and 255 inclusive).\n", reg);
765 				errcnt++;
766 				reg = 6;		// set a somewhat valid number
767 			}
768 		}
769 		else {
770 			reg = -1;
771 		}
772 		if(strcmp(a, "_registers") == 0) {
773 			func->SetRegistersCount(reg);
774 		}
775 		else {
776 			func->AddParameter(a, reg);	// add one argument name
777 		}
778 	}
779 
780 	return 0;
781 }
782 
783 
784 
785 
action_version_func_name_n_params(const char * s)786 static int action_version_func_name_n_params(const char *s)
787 {
788 	unsigned char	version;
789 	const char	*param, *end;
790 	long		l;
791 
792 	version = 5;
793 
794 // skip spaces at the start
795 	while(isspace(*s)) {
796 		s++;
797 	}
798 
799 // skip the function name; this has no effect on the version
800 	while(*s != '\0' && *s != '(' && *s != ')' && *s != ',' && !isspace(*s)) {
801 		s++;
802 	}
803 
804 // go through the list of parameters
805 	while(*s != '\0' && *s != ')') {
806 		do {
807 			s++;
808 		} while(isspace(*s));
809 		param = s;
810 		if(*s == '/') {
811 			// a suppress register is version 7+
812 			version = 7;
813 			s++;
814 		}
815 		end = 0;
816 		while(*s != '\0' && *s != ')' && *s != ',' && !isspace(*s)) {
817 			if(*s == ':' && end == 0) {
818 				// a register specification is version 7+
819 				end = s;
820 				version = 7;
821 			}
822 			s++;
823 		}
824 		if(param == s) {
825 			// empty parameter names are not accepted - this happens
826 			// when there is one or more spaces before the ')' or
827 			// simple when there isn't any parameter
828 			break;
829 		}
830 		l = end - param;
831 		if((l ==  4 && strncmp(param, "this",       l) == 0)
832 		|| (l ==  5 && strncmp(param, "super",      l) == 0)
833 		|| (l ==  5 && strncmp(param, "_root",      l) == 0)
834 		|| (l ==  7 && strncmp(param, "_parent",    l) == 0)
835 		|| (l ==  7 && strncmp(param, "_global",    l) == 0)
836 		|| (l ==  9 && strncmp(param, "arguments",  l) == 0)
837 		|| (l == 10 && strncmp(param, "_registers", l) == 0)) {	// to specify the max # of registers
838 			version = 7;
839 		}
840 	}
841 
842 	return version;
843 }
844 
845 
846 
847 
action_set_catch_identifier(sswf::ActionTry * try_action,const char * s)848 static int action_set_catch_identifier(sswf::ActionTry *try_action, const char *s)
849 {
850 	char		*p;
851 	const char	*e;
852 
853 	while(isspace(*s)) {
854 		s++;
855 	}
856 
857 	e = s;
858 	while(isxdigit(*e)) {
859 		e++;
860 	}
861 
862 	while(isspace(*e)) {
863 		e++;
864 	}
865 
866 	if(*e == '\0') {
867 		// this is a register number
868 		try_action->SetIdentifier(strtol(s, (char **) &e, 0));
869 		return 0;
870 	}
871 
872 	// this is a variable name
873 	p = try_action->StrDup(s);
874 	e = p;
875 	while(!isspace(*p) && *p != '\0') {
876 		p++;
877 	}
878 	*p = '\0';
879 
880 	try_action->SetIdentifier(e);
881 
882 	return 0;
883 }
884 
885 
886 
887 
888 typedef	sswf::Action *	(*action_setup_t)(SaveState& state, sswf::Action::action_t action, const struct data_list_t *list);
889 
890 
891 struct action_table_t {
892 	const char *		name;
893 	sswf::Action::action_t	action;
894 	action_setup_t		func;
895 };
896 
897 
save_actions(SaveState & state)898 static int save_actions(SaveState& state)
899 {
900 	static const action_table_t	actions[] = {
901 		{
902 			"ADD",
903 			sswf::Action::ACTION_ADD_TYPED,
904 			0
905 		},
906 		{
907 			"ADD.CAST",
908 			sswf::Action::ACTION_ADD,
909 			0
910 		},
911 		{
912 			"AND",
913 			sswf::Action::ACTION_AND,
914 			0
915 		},
916 		{
917 			"BRANCH",
918 			sswf::Action::ACTION_BRANCH_ALWAYS,
919 			save_action_branch
920 		},
921 		{
922 			"BRANCH.ALWAYS",
923 			sswf::Action::ACTION_BRANCH_ALWAYS,
924 			save_action_branch
925 		},
926 		{
927 			"BRANCH.IF.TRUE",
928 			sswf::Action::ACTION_BRANCH_IF_TRUE,
929 			save_action_branch
930 		},
931 		{
932 			"CALL.FRAME",
933 			sswf::Action::ACTION_CALL_FRAME,
934 			save_action_call_frame
935 		},
936 		{
937 			"CALL.FUNCTION",
938 			sswf::Action::ACTION_CALL_FUNCTION,
939 			0
940 		},
941 		{
942 			"CALL.METHOD",
943 			sswf::Action::ACTION_CALL_METHOD,
944 			0
945 		},
946 		{
947 			"CAST.OBJECT",
948 			sswf::Action::ACTION_CAST_OBJECT,
949 			0
950 		},
951 		{
952 			"CHR",
953 			sswf::Action::ACTION_CHR,
954 			0
955 		},
956 		{
957 			"CONCATENATE",
958 			sswf::Action::ACTION_CONCATENATE,
959 			0
960 		},
961 		{
962 			"CONCATENATE.STRING",
963 			sswf::Action::ACTION_CONCATENATE,
964 			0
965 		},
966 		{
967 			"CONSTANT.POOL",
968 			sswf::Action::ACTION_DECLARE_DICTIONARY,
969 			save_action_dictionary
970 		},
971 		{
972 			"DECLARE.ARRAY",
973 			sswf::Action::ACTION_DECLARE_ARRAY,
974 			0
975 		},
976 		{
977 			"DECLARE.LOCAL.VARIABLE",
978 			sswf::Action::ACTION_DECLARE_LOCAL_VARIABLE,
979 			0
980 		},
981 		{
982 			"DECLARE.OBJECT",
983 			sswf::Action::ACTION_DECLARE_OBJECT,
984 			0
985 		},
986 		{
987 			"DECREMENT",
988 			sswf::Action::ACTION_DECREMENT,
989 			0
990 		},
991 		{
992 			"DELETE",
993 			sswf::Action::ACTION_DELETE,
994 			0
995 		},
996 		{
997 			"DICTIONARY",
998 			sswf::Action::ACTION_DECLARE_DICTIONARY,
999 			save_action_dictionary
1000 		},
1001 		{
1002 			"DIVIDE",
1003 			sswf::Action::ACTION_DIVIDE,
1004 			0
1005 		},
1006 		{
1007 			"DUPLICATE",
1008 			sswf::Action::ACTION_DUPLICATE,
1009 			0
1010 		},
1011 		{
1012 			"DUPLICATE.SPRITE",
1013 			sswf::Action::ACTION_DUPLICATE_SPRITE,
1014 			0
1015 		},
1016 		{
1017 			"ENUMERATE",
1018 			sswf::Action::ACTION_ENUMERATE,
1019 			0
1020 		},
1021 		{
1022 			"ENUMERATE.OBJECT",
1023 			sswf::Action::ACTION_ENUMERATE_OBJECT,
1024 			0
1025 		},
1026 		{
1027 			"EQUAL",
1028 			sswf::Action::ACTION_EQUAL_TYPED,
1029 			0
1030 		},
1031 		{
1032 			"EQUAL.CAST",
1033 			sswf::Action::ACTION_EQUAL,
1034 			0
1035 		},
1036 		{
1037 			"EXTENDS",
1038 			sswf::Action::ACTION_EXTENDS,
1039 			0
1040 		},
1041 		{
1042 			"FSCOMMAND2",
1043 			sswf::Action::ACTION_FSCOMMAND2,
1044 			0
1045 		},
1046 		{
1047 			"GET.MEMBER",
1048 			sswf::Action::ACTION_GET_MEMBER,
1049 			0
1050 		},
1051 		{
1052 			"GET.PROPERTY",
1053 			sswf::Action::ACTION_GET_PROPERTY,
1054 			0
1055 		},
1056 		{
1057 			"GET.TARGET",
1058 			sswf::Action::ACTION_GET_TARGET,
1059 			0
1060 		},
1061 		{
1062 			"GET.TIMER",
1063 			sswf::Action::ACTION_GET_TIMER,
1064 			0
1065 		},
1066 		{
1067 			"GET.VARIABLE",
1068 			sswf::Action::ACTION_GET_VARIABLE,
1069 			0
1070 		},
1071 		{
1072 			"GOTO",
1073 			sswf::Action::ACTION_UNKNOWN,
1074 			save_action_goto
1075 		},
1076 		{
1077 			"GOTO.EXPRESSION",
1078 			sswf::Action::ACTION_GOTO_EXPRESSION,
1079 			save_action_goto
1080 		},
1081 		{
1082 			"GOTO.FRAME",
1083 			sswf::Action::ACTION_GOTO_FRAME,
1084 			save_action_goto
1085 		},
1086 		{
1087 			"GOTO.LABEL",
1088 			sswf::Action::ACTION_GOTO_LABEL,
1089 			save_action_goto
1090 		},
1091 		{
1092 			"GREATER.THAN",
1093 			sswf::Action::ACTION_GREATER_THAN_TYPED,
1094 			0
1095 		},
1096 		{
1097 			"IF.TRUE",
1098 			sswf::Action::ACTION_BRANCH_IF_TRUE,
1099 			save_action_branch
1100 		},
1101 		{
1102 			"IMPLEMENTS",
1103 			sswf::Action::ACTION_IMPLEMENTS,
1104 			0
1105 		},
1106 		{
1107 			"INCREMENT",
1108 			sswf::Action::ACTION_INCREMENT,
1109 			0
1110 		},
1111 		{
1112 			"INSTANCE.OF",
1113 			sswf::Action::ACTION_INSTANCE_OF,
1114 			0
1115 		},
1116 		{
1117 			"INT",
1118 			sswf::Action::ACTION_INTEGRAL_PART,
1119 			0
1120 		},
1121 		{
1122 			"INTEGRAL.PART",
1123 			sswf::Action::ACTION_INTEGRAL_PART,
1124 			0
1125 		},
1126 		{
1127 			"LESS.THAN",
1128 			sswf::Action::ACTION_LESS_THAN_TYPED,
1129 			0
1130 		},
1131 		{
1132 			"LESS.THAN.CAST",
1133 			sswf::Action::ACTION_LESS_THAN,
1134 			0
1135 		},
1136 		{
1137 			"LOGICAL.AND",
1138 			sswf::Action::ACTION_LOGICAL_AND,
1139 			0
1140 		},
1141 		{
1142 			"LOGICAL.NOT",
1143 			sswf::Action::ACTION_LOGICAL_NOT,
1144 			0
1145 		},
1146 		{
1147 			"LOGICAL.OR",
1148 			sswf::Action::ACTION_LOGICAL_OR,
1149 			0
1150 		},
1151 		{
1152 			"MB.CHR",
1153 			sswf::Action::ACTION_MBCHR,
1154 			0
1155 		},
1156 		{
1157 			"MB.ORD",
1158 			sswf::Action::ACTION_MBORD,
1159 			0
1160 		},
1161 		{
1162 			"MB.STRING.LENGTH",
1163 			sswf::Action::ACTION_MBSTRING_LENGTH,
1164 			0
1165 		},
1166 		{
1167 			"MODULO",
1168 			sswf::Action::ACTION_MODULO,
1169 			0
1170 		},
1171 		{
1172 			"MULTIPLY",
1173 			sswf::Action::ACTION_MULTIPLY,
1174 			0
1175 		},
1176 		{
1177 			"NEW",
1178 			sswf::Action::ACTION_NEW,
1179 			0
1180 		},
1181 		{
1182 			"NEW.METHOD",
1183 			sswf::Action::ACTION_NEW_METHOD,
1184 			0
1185 		},
1186 		{
1187 			"NEXT.FRAME",
1188 			sswf::Action::ACTION_NEXT_FRAME,
1189 			0
1190 		},
1191 		{
1192 			"NUMBER",
1193 			sswf::Action::ACTION_NUMBER,
1194 			0
1195 		},
1196 		{
1197 			"OR",
1198 			sswf::Action::ACTION_OR,
1199 			0
1200 		},
1201 		{
1202 			"ORD",
1203 			sswf::Action::ACTION_ORD,
1204 			0
1205 		},
1206 		{
1207 			"PLAY",
1208 			sswf::Action::ACTION_PLAY,
1209 			0
1210 		},
1211 		{
1212 			"POP",
1213 			sswf::Action::ACTION_POP,
1214 			0
1215 		},
1216 		{
1217 			"PREVIOUS.FRAME",
1218 			sswf::Action::ACTION_PREVIOUS_FRAME,
1219 			0
1220 		},
1221 		{
1222 			"PUSH.DATA",
1223 			sswf::Action::ACTION_PUSH_DATA,
1224 			save_action_pushdata
1225 		},
1226 		{
1227 			"RANDOM",
1228 			sswf::Action::ACTION_RANDOM,
1229 			0
1230 		},
1231 		{
1232 			"REMOVE.SPRITE",
1233 			sswf::Action::ACTION_REMOVE_SPRITE,
1234 			0
1235 		},
1236 		{
1237 			"RETURN",
1238 			sswf::Action::ACTION_RETURN,
1239 			0
1240 		},
1241 		{
1242 			"SET.LOCAL.VARIABLE",
1243 			sswf::Action::ACTION_SET_LOCAL_VARIABLE,
1244 			0
1245 		},
1246 		{
1247 			"SET.MEMBER",
1248 			sswf::Action::ACTION_SET_MEMBER,
1249 			0
1250 		},
1251 		{
1252 			"SET.PROPERTY",
1253 			sswf::Action::ACTION_SET_PROPERTY,
1254 			0
1255 		},
1256 		{
1257 			"SET.TARGET",
1258 			sswf::Action::ACTION_SET_TARGET2,	/* there are two SET TARGETs! */
1259 			save_action_set_target
1260 		},
1261 		{
1262 			"SET.VARIABLE",
1263 			sswf::Action::ACTION_SET_VARIABLE,
1264 			0
1265 		},
1266 		{
1267 			"SHIFT.LEFT",
1268 			sswf::Action::ACTION_SHIFT_LEFT,
1269 			0
1270 		},
1271 		{
1272 			"SHIFT.RIGHT",
1273 			sswf::Action::ACTION_SHIFT_RIGHT,
1274 			0
1275 		},
1276 		{
1277 			"SHIFT.RIGHT.UNSIGNED",
1278 			sswf::Action::ACTION_SHIFT_RIGHT_UNSIGNED,
1279 			0
1280 		},
1281 		{
1282 			"SHL",
1283 			sswf::Action::ACTION_SHIFT_LEFT,
1284 			0
1285 		},
1286 		{
1287 			"SHR",
1288 			sswf::Action::ACTION_SHIFT_RIGHT,
1289 			0
1290 		},
1291 		{
1292 			"START.DRAG",
1293 			sswf::Action::ACTION_START_DRAG,
1294 			0
1295 		},
1296 		{
1297 			"STOP",
1298 			sswf::Action::ACTION_STOP,
1299 			0
1300 		},
1301 		{
1302 			"STOP.DRAG",
1303 			sswf::Action::ACTION_STOP_DRAG,
1304 			0
1305 		},
1306 		{
1307 			"STOP.SOUND",
1308 			sswf::Action::ACTION_STOP_SOUND,
1309 			0
1310 		},
1311 		{
1312 			"STORE.REGISTER",
1313 			sswf::Action::ACTION_STORE_REGISTER,
1314 			save_action_store_register
1315 		},
1316 		{
1317 			"STRICT.EQUAL",
1318 			sswf::Action::ACTION_STRICT_EQUAL,
1319 			0
1320 		},
1321 		{
1322 			"STRING",
1323 			sswf::Action::ACTION_STRING,
1324 			0
1325 		},
1326 		{
1327 			"STRING.EQUAL",
1328 			sswf::Action::ACTION_STRING_EQUAL,
1329 			0
1330 		},
1331 		{
1332 			"STRING.GREATER",
1333 			sswf::Action::ACTION_STRING_GREATER_THAN,
1334 			0
1335 		},
1336 		{
1337 			"STRING.LENGTH",
1338 			sswf::Action::ACTION_STRING_LENGTH,
1339 			0
1340 		},
1341 		{
1342 			"STRING.LESS.THAN",
1343 			sswf::Action::ACTION_STRING_LESS_THAN,
1344 			0
1345 		},
1346 		{
1347 			"SUB.MBSTRING",
1348 			sswf::Action::ACTION_SUB_MBSTRING,
1349 			0
1350 		},
1351 		{
1352 			"SUB.STRING",
1353 			sswf::Action::ACTION_SUB_STRING,
1354 			0
1355 		},
1356 		{	// TODO: this and the SUB.STRING are not ordered!
1357 			"SUBSTRACT",
1358 			sswf::Action::ACTION_SUBTRACT,
1359 			0
1360 		},
1361 		{	// TODO: this and the SUB.STRING are not ordered!
1362 			"SUBTRACT",
1363 			sswf::Action::ACTION_SUBTRACT,
1364 			0
1365 		},
1366 		{
1367 			"SWAP",
1368 			sswf::Action::ACTION_SWAP,
1369 			0
1370 		},
1371 		{
1372 			"THROW",
1373 			sswf::Action::ACTION_THROW,
1374 			0
1375 		},
1376 		{
1377 			"TOGGLE.QUALITY",
1378 			sswf::Action::ACTION_TOGGLE_QUALITY,
1379 			0
1380 		},
1381 		{
1382 			"TRACE",
1383 			sswf::Action::ACTION_TRACE,
1384 			0
1385 		},
1386 		{
1387 			"TYPE.OF",
1388 			sswf::Action::ACTION_TYPE_OF,
1389 			0
1390 		},
1391 		{
1392 			"URL",
1393 			sswf::Action::ACTION_URL,
1394 			save_action_url
1395 		},
1396 		{
1397 			"USHR",
1398 			sswf::Action::ACTION_SHIFT_RIGHT_UNSIGNED,
1399 			0
1400 		},
1401 		{
1402 			"WAIT.FOR.FRAME",
1403 			sswf::Action::ACTION_WAIT_FOR_FRAME,
1404 			save_action_wait_for_frame
1405 		},
1406 		{
1407 			"XOR",
1408 			sswf::Action::ACTION_XOR,
1409 			0
1410 		}
1411 	};
1412 	const int			max_actions = sizeof(actions) / sizeof(action_table_t);
1413 
1414 	const struct data_common_t	*cd, *save;
1415 	const struct data_list_t	*list, *sub_list;
1416 	const char			*name;
1417 	int				r, i, j, p, cnt, idx, max, ec;
1418 	sswf::Action			*a;
1419 	sswf::ActionFunction		*func;
1420 	sswf::ActionTry			*try_action;
1421 	sswf::Vectors			*previous_actions;
1422 
1423 #if DEBUG
1424 	// ensures the list of actions is sorted
1425 	static bool check = true;
1426 	if(check) {
1427 		check = false;
1428 		i = max_actions - 1;
1429 		while(i > 0) {
1430 			i--;
1431 			assert(strcasecmp(actions[i + 1].name, actions[i].name) > 0,
1432 				"actions table improperly sorted in \"sswf_save.c++: save_actions()\" (%s > %s)",
1433 							actions[i].name, actions[i + 1].name);
1434 		}
1435 	}
1436 #endif
1437 
1438 	list = dc_list(state.f_d);
1439 	max = list->count;
1440 	for(idx = 0; idx < max; idx++) {
1441 		cd = dc_item(list, idx);
1442 		state.f_current_cd = cd;
1443 		a = 0;
1444 		switch(cd->type) {
1445 		case NODE_SUBTYPE_ACTION:
1446 			assert(cd->name_len != 0, "an action must always have a name");
1447 			/* cd is a named action */
1448 
1449 			i = 0;
1450 			j = max_actions;
1451 			do {
1452 				p = i + (j - i) / 2;
1453 				r = strcmp_action(cd->name, actions[p].name);
1454 
1455 //printf("Compare action [%s] & [%s] -> %d\n", cd->name, actions[p].name, r);
1456 
1457 				if(r == 0) {
1458 					/* we found it! */
1459 found_it:
1460 					if(actions[p].func == 0) {
1461 						a = new sswf::Action(state.f_parent, actions[p].action);
1462 					}
1463 					else {
1464 						if(cd->length - cd->name_len == sizeof(struct data_common_t)) {
1465 							sub_list = 0;		// empty list
1466 						}
1467 						else {
1468 							sub_list = dc_list(cd);
1469 						}
1470 						a = (*actions[p].func)(state, actions[p].action, sub_list);
1471 					}
1472 					break;
1473 				}
1474 				if(r > 0) {
1475 					i = p + 1;
1476 				}
1477 				else {
1478 					j = p;
1479 				}
1480 			} while(i < j);
1481 			if(a == 0 && i >= j) {
1482 				/*
1483 				 * This should never happen since the sswf_node.c already checks for valid actions
1484 				 * thus the error is most probably because the name of the action includes a '.'
1485 				 */
1486 				/* check 3 entries before, then 3 after */
1487 				j = p;
1488 				for(cnt = 0; p > 0 && cnt < 3; cnt++) {
1489 					p--;
1490 					r = strcmp_action(cd->name, actions[p].name);
1491 					if(r == 0) {
1492 						goto found_it;
1493 					}
1494 				}
1495 				for(cnt = 0, p = j; p < max_actions - 1 && cnt < 3; cnt++) {
1496 					p++;
1497 					r = strcmp_action(cd->name, actions[p].name);
1498 					if(r == 0) {
1499 						goto found_it;
1500 					}
1501 				}
1502 				assert(0, "cannot find action \"%s\" in sswf_save.c++ -- need fixing\n", cd->name);
1503 				/*NOTREACHED*/
1504 			}
1505 			break;
1506 
1507 		case NODE_SUBTYPE_LABEL:
1508 			/* ha! a label for the branch instructions and such */
1509 			a = save_action_label(state, sswf::Action::ACTION_LABEL, dc_list(cd));
1510 			break;
1511 
1512 		case NODE_SUBTYPE_FUNCTION:
1513 			/* This was wrong, a function without a name is put on the stack
1514 			 * so later it can be added to an object as a function member.
1515 			 * It is named at that time.
1516 			if(cd->name_len == 0) {
1517 				fprintf(stderr, "ERROR: a function must have a name.\n");
1518 				errcnt++;
1519 				return 1;
1520 			}
1521 			 */
1522 			// In case of a function we need to know if any of the
1523 			// actions within it have a reference to a register > 3.
1524 			// If so, we need to use a version 7 function definition.
1525 			{
1526 			sswf::Vectors actions;
1527 
1528 			save = state.f_d;
1529 			previous_actions = state.f_actions;
1530 			state.f_function_level++;
1531 			state.f_d = cd;
1532 			state.f_actions = &actions;	//a->SubList();
1533 			ec = save_actions(state);
1534 			state.f_d = save;
1535 			state.f_actions = previous_actions;
1536 			if(ec != 0) {
1537 				return 1;
1538 			}
1539 
1540 			// determine the version now
1541 			if(cd->name_len == 0) {
1542 				name = "";
1543 			}
1544 			else {
1545 				name = cd->name;
1546 			}
1547 			i = action_version_func_name_n_params(name);
1548 			if(i < 7 && sswf::Action::GetMaximumRegister(actions) >= 4) {
1549 				i = 7;
1550 			}
1551 
1552 			if(i == 7) {
1553 				// Function2
1554 				func = new sswf::ActionFunction(state.f_parent, sswf::Action::ACTION_DECLARE_FUNCTION2);
1555 			}
1556 			else {
1557 				// Function[1]
1558 				func = new sswf::ActionFunction(state.f_parent);
1559 			}
1560 			if(func == 0) {
1561 				break;
1562 			}
1563 			if(action_set_func_name_n_params(func, name) != 0) {
1564 				delete func;
1565 				return 1;
1566 			}
1567 			// Okay, now we're ready to copy the child actions in the function
1568 			j = actions.Count();
1569 			for(i = 0; i < j; i++) {
1570 				func->AddAction(dynamic_cast<sswf::Action *>(actions.Get(i)));
1571 			}
1572 			a = func;
1573 			}
1574 			break;
1575 
1576 		case NODE_SUBTYPE_TRY:
1577 			a = try_action = new sswf::ActionTry(state.f_parent);
1578 			if(try_action == 0) {
1579 				break;
1580 			}
1581 			save = state.f_d;
1582 			previous_actions = state.f_actions;
1583 			state.f_d = cd;
1584 			state.f_actions = try_action->SubListTry();
1585 			ec = save_actions(state);
1586 			state.f_d = save;
1587 			state.f_actions = previous_actions;
1588 			if(ec != 0) {
1589 				delete a;
1590 				return 1;
1591 			}
1592 
1593 			idx++;
1594 			if(idx >= max) {
1595 				delete a;
1596 				fprintf(stderr, "ERROR: invalid TRY without any CATCH and FINALLY.\n");
1597 				errcnt++;
1598 				return 1;
1599 			}
1600 
1601 			cd = dc_item(list, idx);
1602 			state.f_current_cd = cd;
1603 			if(cd->type != NODE_SUBTYPE_CATCH && cd->type != NODE_SUBTYPE_FINALLY) {
1604 				delete a;
1605 				fprintf(stderr, "ERROR: invalid TRY without any CATCH and FINALLY.\n");
1606 				errcnt++;
1607 				return 1;
1608 			}
1609 
1610 			if(cd->type == NODE_SUBTYPE_CATCH) {
1611 				if(cd->name_len == 0) {
1612 					delete a;
1613 					fprintf(stderr, "ERROR: a catch must have a variable name or a register number specified\n");
1614 					errcnt++;
1615 					return 1;
1616 				}
1617 				if(action_set_catch_identifier(try_action, cd->name) != 0) {
1618 					delete a;
1619 					return 1;
1620 				}
1621 
1622 				save = state.f_d;
1623 				previous_actions = state.f_actions;
1624 				state.f_d = cd;
1625 				state.f_actions = try_action->SubListCatch();
1626 				ec = save_actions(state);
1627 				state.f_d = save;
1628 				state.f_actions = previous_actions;
1629 				if(ec != 0) {
1630 					delete a;
1631 					return 1;
1632 				}
1633 
1634 				idx++;
1635 				if(idx >= max) {
1636 					break;
1637 				}
1638 
1639 				cd = dc_item(list, idx);
1640 				state.f_current_cd = cd;
1641 			}
1642 
1643 			if(cd->type == NODE_SUBTYPE_FINALLY) {
1644 				save = state.f_d;
1645 				previous_actions = state.f_actions;
1646 				state.f_d = cd;
1647 				state.f_actions = try_action->SubListFinally();
1648 				ec = save_actions(state);
1649 				state.f_d = save;
1650 				state.f_actions = previous_actions;
1651 				if(ec != 0) {
1652 					delete a;
1653 					return 1;
1654 				}
1655 			}
1656 			else {
1657 				// in this case we had a CATCH and no FINALLY
1658 				idx--;
1659 			}
1660 			break;
1661 
1662 		case NODE_SUBTYPE_CATCH:
1663 			fprintf(stderr, "ERROR: a CATCH was found without a TRY.\n");
1664 			errcnt++;
1665 			break;
1666 
1667 		case NODE_SUBTYPE_FINALLY:
1668 			fprintf(stderr, "ERROR: a FINALLY was found without a TRY.\n");
1669 			errcnt++;
1670 			break;
1671 
1672 		case NODE_SUBTYPE_WITH:
1673 			a = new sswf::ActionWith(state.f_parent);
1674 			if(a == 0) {
1675 				break;
1676 			}
1677 			save = state.f_d;
1678 			previous_actions = state.f_actions;
1679 			state.f_d = cd;
1680 			state.f_actions = a->SubList();
1681 			ec = save_actions(state);
1682 			state.f_d = save;
1683 			state.f_actions = previous_actions;
1684 			if(ec != 0) {
1685 				return 1;
1686 			}
1687 			break;
1688 
1689 		/* in lists of actions we also accept lists! */
1690 		case NODE_SUBTYPE_BLOCK:
1691 		case NODE_SUBTYPE_LIST:
1692 			save = state.f_d;
1693 			state.f_d = cd;
1694 			ec = save_actions(state);
1695 			state.f_d = save;
1696 			if(ec != 0) {
1697 				return 1;
1698 			}
1699 			break;
1700 
1701 		// buttons also accept states and who knows what later!
1702 		default:
1703 			// do nothing here at this time
1704 			break;
1705 
1706 		}
1707 		if(a != 0) {
1708 			state.f_memory_manager->MemAttach(a, sizeof(sswf::Action), "an action object for a DoAction or a Button");
1709 			state.f_actions->Set(-1, a);
1710 		}
1711 	}
1712 
1713 	return 0;
1714 }
1715 
1716 
1717 
save_on_event(SaveState & state,sswf::TagBase * parent,const struct data_common_t * events)1718 static sswf::Event *save_on_event(SaveState& state, sswf::TagBase *parent, const struct data_common_t *events)
1719 {
1720 	sswf::Event			*event;
1721 	int				idx, max, ec;
1722 	const struct data_common_t	*cd, *save, *str;
1723 	const struct data_list_t	*list;
1724 	const struct data_on_event_t	*evt;
1725 
1726 	event = new sswf::Event();
1727 	parent->MemAttach(event, sizeof(sswf::Event), "event & action object");
1728 
1729 	list = dc_list(events);
1730 	max = list->count;
1731 	for(idx = 0; idx < max; idx++) {
1732 		if(list->offset[idx] < 0) {
1733 			cd = dc_item(list, idx);
1734 			evt = (const struct data_on_event_t *) cd;
1735 			idx++;
1736 			assert(idx < max, "expected a string to follow an ON EVENT item");
1737 			str = dc_item(list, idx);
1738 			assert(str->type == NODE_TYPE_STRING, "expected a string to follow an ON EVENT item");
1739 			if(str->name_len > 0) {
1740 				switch(evt->type) {
1741 				case ON_EVENT_TYPE_EVENT:
1742 					event->SetEvents(sswf::Event::StringToEvents(str->name));
1743 					break;
1744 
1745 				case ON_EVENT_TYPE_KEY:
1746 					event->SetKey(sswf::Event::StringToKeyCode(str->name));
1747 					break;
1748 
1749 				default:
1750 					assert(0, "unknown ON EVENT type");
1751 					/*NOTREACHED*/
1752 
1753 				}
1754 			}
1755 		}
1756 	}
1757 
1758 	save = state.f_d;
1759 	state.f_d = events;
1760 	state.f_memory_manager = event;
1761 	state.f_actions = &event->Actions();
1762 	ec = save_actions(state);
1763 	state.f_d = save;
1764 
1765 	if(ec != 0) {
1766 		delete event;
1767 		return 0;
1768 	}
1769 
1770 	return event;
1771 }
1772 
1773 
save_set_matrix(sswf::Matrix & matrix,const struct data_matrix_t * mx)1774 static void save_set_matrix(sswf::Matrix& matrix, const struct data_matrix_t *mx)
1775 {
1776 	if(mx->sy == -1E+128) {
1777 		matrix.SetScale(mx->sx);
1778 	}
1779 	else {
1780 		matrix.SetScale(mx->sx, mx->sy);
1781 	}
1782 	matrix.SetRotate(mx->angle);
1783 	matrix.SetTranslate(PIXEL_TO_TWIPS(mx->tx), PIXEL_TO_TWIPS(mx->ty));
1784 	matrix.SetSkew(mx->skew0, mx->skew1);
1785 }
1786 
save_button(SaveState & state)1787 static int save_button(SaveState& state)
1788 {
1789 	sswf::TagButton			*button;
1790 	sswf::SRectangle		rect;
1791 	sswf::State			s(state.f_header);
1792 	sswf::Matrix			matrix;
1793 	sswf::Event			*event;
1794 	const sswf::TagBaseID *		obj;
1795 	int				m, i, max, idx, ec;
1796 	const struct data_list_t	*list, *sub_list;
1797 	const struct data_common_t	*cd, *sub;
1798 	const struct data_button_t	*b;
1799 	const struct data_button_flag_t	*f;
1800 	const struct data_rect_t	*r;
1801 	const struct data_matrix_t	*mx;
1802 	const char			*obj_name;
1803 
1804 	button = new sswf::TagButton(state.f_parent);
1805 	if(button == 0) {
1806 		return -1;
1807 	}
1808 
1809 	state.f_memory_manager = button;
1810 	state.f_actions = &button->Actions();
1811 
1812 	ec = save_actions(state);
1813 	if(ec != 0) {
1814 		return 1;
1815 	}
1816 
1817 	list = dc_list(state.f_d);
1818 	max = list->count;
1819 	for(idx = 0; idx < max; idx++) {
1820 		cd = dc_item(list, idx);
1821 		if(list->offset[idx] < 0) {
1822 			f = (struct data_button_flag_t *) cd;
1823 			button->SetMenu(f->menu != 0.0);
1824 		}
1825 		else {
1826 			switch(cd->type) {
1827 			case NODE_SUBTYPE_RECT:
1828 				/* transform the data into a rectangle */
1829 				r = dc_rect(cd);
1830 				rect.SetReorder(PIXEL_TO_TWIPS(r->min_x), PIXEL_TO_TWIPS(r->max_x),
1831 						PIXEL_TO_TWIPS(r->min_y), PIXEL_TO_TWIPS(r->max_y));
1832 				/* save it in the button */
1833 				button->SetGrid(rect);
1834 				break;
1835 
1836 			case NODE_SUBTYPE_ON_EVENT:
1837 				event = save_on_event(state, button, cd);
1838 				if(event == 0) {
1839 					return -1;
1840 				}
1841 				button->AddEvent(event);
1842 				break;
1843 
1844 			case NODE_SUBTYPE_STATE:
1845 				sub_list = dc_list(cd);
1846 				/* cd is a state */
1847 				s.Reset();
1848 				m = sub_list->count;
1849 				for(i = 0; i < m; i++) {
1850 					sub = dc_item(sub_list, i);
1851 					if(sub_list->offset[i] < 0) {
1852 						b = (struct data_button_t *) sub;
1853 						s.SetFlags(static_cast<unsigned char>(b->state));
1854 						s.SetLayer(static_cast<unsigned short>(b->layer));
1855 					}
1856 					else {
1857 						switch(sub->type) {
1858 						case NODE_SUBTYPE_REFERENCE:
1859 							obj = state.FindRef(sub->name, 0);
1860 							if(obj != 0) {
1861 								obj_name = obj->Name();
1862 								if(strcmp(obj_name, "edit")     == 0
1863 								|| strcmp(obj_name, "imported") == 0
1864 								|| strcmp(obj_name, "shape")    == 0
1865 								|| strcmp(obj_name, "sprite")   == 0
1866 								|| strcmp(obj_name, "text")     == 0) {
1867 									s.SetObjectID(obj->Identification());
1868 								}
1869 								else {
1870 fprintf(stderr, "ERROR: a reference to \"%s\" needs to be an object of type: edit, shape, sprite or text (currently: \"%s\").\n", cd->name, obj_name);
1871 									errcnt++;
1872 								}
1873 							}
1874 							break;
1875 
1876 						case NODE_SUBTYPE_MATRIX:
1877 							mx = dc_matrix(sub);
1878 							save_set_matrix(matrix, mx);
1879 							s.SetMatrix(matrix);
1880 							break;
1881 
1882 						default:
1883 							/* to avoid warnings */
1884 							assert(0, "unknown data type (%d) for a button state object", cd->type);
1885 							/*NOTREACHED*/
1886 
1887 						}
1888 					}
1889 				}
1890 				button->SetState(s);
1891 				break;
1892 
1893 			default:	// ignore others, these are actions
1894 				break;
1895 
1896 			}
1897 		}
1898 	}
1899 
1900 	state.RecordRef(button);
1901 
1902 	return 0;
1903 }
1904 
1905 
1906 
1907 
save_edit_text_setup(SaveState & state,sswf::TagEditText * edit_text,const struct data_list_t * list)1908 static int save_edit_text_setup(SaveState& state, sswf::TagEditText *edit_text, const struct data_list_t *list)
1909 {
1910 	const sswf::TagBaseID		*obj;
1911 	sswf::Color			color;
1912 	int				idx, max;
1913 	const struct data_common_t	*cd;
1914 	const struct data_color_t	*c;
1915 	const struct data_text_setup_t	*setup;
1916 
1917 	setup = 0;		// makes the reference crash if still undefined (should never happen)
1918 	max = list->count;
1919 	for(idx = 0; idx < max; idx++) {
1920 		cd = dc_item(list, idx);
1921 		// we skip offsets in case we get any
1922 		if(list->offset[idx] < 0) {
1923 			setup = reinterpret_cast<const struct data_text_setup_t *>(cd);
1924 		}
1925 		else {
1926 			switch(cd->type) {
1927 			case NODE_SUBTYPE_COLOR:
1928 				c = dc_color(cd);
1929 				color.Set(CLAMPED_BYTE_COLOR(c->red), CLAMPED_BYTE_COLOR(c->green),
1930 								CLAMPED_BYTE_COLOR(c->blue), CLAMPED_BYTE_COLOR(c->alpha));
1931 				edit_text->SetColor(color);
1932 				break;
1933 
1934 			case NODE_SUBTYPE_REFERENCE:
1935 				assert(setup != 0, "found font reference before font setup structure");
1936 				obj = state.FindRef(cd->name, "font");
1937 				if(obj != 0) {
1938 					edit_text->SetFont(dynamic_cast<const sswf::TagFont *>(obj), PIXEL_TO_TWIPS(setup->height));
1939 				}
1940 				break;
1941 
1942 			default:
1943 				/* to avoid warnings */
1944 				assert(0, "unknown data type (%d) for a text setup", cd->type);
1945 				/*NOTREACHED*/
1946 
1947 			}
1948 		}
1949 	}
1950 
1951 	return 0;
1952 }
1953 
1954 
1955 
save_edit_text(SaveState & state)1956 static int save_edit_text(SaveState& state)
1957 {
1958 	sswf::TagEditText		*edit_text;
1959 	sswf::SRectangle		rect;
1960 	const struct data_list_t	*list;
1961 	const struct data_common_t	*cd, *str;
1962 	const struct data_edit_text_t	*ed;
1963 	const struct data_rect_t	*r;
1964 	int				idx, max, ec;
1965 
1966 	edit_text = new sswf::TagEditText(state.f_parent);
1967 	if(edit_text == 0) {
1968 		return -1;
1969 	}
1970 	state.RecordRef(edit_text);
1971 
1972 	list = dc_list(state.f_d);
1973 	max = list->count;
1974 	for(idx = 0; idx < max; idx++) {
1975 		cd = dc_item(list, idx);
1976 		if(list->offset[idx] < 0) {
1977 			switch(* (long *) cd) {		// switch on the type
1978 			case EDIT_TEXT_TYPE_LAYOUT:
1979 				ed = reinterpret_cast<const struct data_edit_text_t *>(cd);
1980 				if(ed->margin_left != -1E+128) {
1981 					edit_text->SetMargins(PIXEL_TO_TWIPS(ed->margin_left),
1982 							PIXEL_TO_TWIPS(ed->margin_right));
1983 				}
1984 				if(ed->indent != -1E+128) {
1985 					edit_text->SetIndent(PIXEL_TO_TWIPS(ed->indent));
1986 				}
1987 				if(ed->leading != -1E+128) {
1988 					edit_text->SetLeading(PIXEL_TO_TWIPS(ed->leading));
1989 				}
1990 				if(ed->max_length != -1E+128) {
1991 					edit_text->SetMaxLength(static_cast<long>(ed->max_length));
1992 				}
1993 				edit_text->SetWordWrap(ed->word_wrap!= 0.0);
1994 				edit_text->SetMultiline(ed->multiline != 0.0);
1995 				edit_text->SetPassword(ed->password != 0.0);
1996 				edit_text->SetReadOnly(ed->readonly != 0.0);
1997 				edit_text->SetNoSelect(ed->no_select != 0.0);
1998 				edit_text->SetBorder(ed->border != 0.0);
1999 				edit_text->SetOutline(ed->outline != 0.0);
2000 				edit_text->SetHTML(ed->html != 0.0);
2001 				edit_text->SetAutoSize(ed->auto_size != 0.0);
2002 				if(ed->thickness != -1E+128) {
2003 					edit_text->SetThickness(ed->thickness);
2004 					edit_text->SetSharpness(ed->sharpness);
2005 				}
2006 				if(ed->renderer != -1E+128) {
2007 					edit_text->SetRenderer(static_cast<sswf::TagCSMTextSettings::csm_text_renderer_t>(static_cast<int>(ed->renderer)));
2008 				}
2009 				if(ed->grid_fit != -1E+128) {
2010 					edit_text->SetGridFit(static_cast<sswf::TagCSMTextSettings::csm_text_gridfit_t>(static_cast<int>(ed->grid_fit)));
2011 				}
2012 				break;
2013 
2014 			case EDIT_TEXT_TYPE_VARIABLE:
2015 				idx++;
2016 				assert(idx < max, "expected the string for the \"EditText\" variable name");
2017 				str = dc_item(list, idx);
2018 				assert(str->type == NODE_TYPE_STRING, "expected a string item for the \"EditText\" variable name");
2019 				if(str->name_len > 0) {
2020 					edit_text->SetVariableName(str->name);
2021 				}
2022 				if(idx + 1 < max) {
2023 					str = dc_item(list, idx + 1);
2024 					if(str->type == NODE_TYPE_STRING) {
2025 						// we also have the initial text here
2026 						idx++;
2027 						if(str->name_len > 0) {
2028 							edit_text->SetText(str->name);
2029 						}
2030 					}
2031 				}
2032 				break;
2033 
2034 			case EDIT_TEXT_TYPE_INITIAL_TEXT:
2035 				idx++;
2036 				assert(idx < max, "expected the string for the \"EditText\" initial text");
2037 				str = dc_item(list, idx);
2038 				assert(str->type == NODE_TYPE_STRING, "expected a string item for the \"EditText\" initial text");
2039 				if(str->name_len > 0) {
2040 					edit_text->SetText(str->name);
2041 				}
2042 				break;
2043 
2044 			case EDIT_TEXT_TYPE_USED_GLYPHS:
2045 				idx++;
2046 				assert(idx < max, "expected the string for the \"EditText\" used glyphs");
2047 				str = dc_item(list, idx);
2048 				assert(str->type == NODE_TYPE_STRING, "expected a string item for the \"EditText\" used glyphs");
2049 				if(str->name_len > 0) {
2050 					edit_text->SetUsedGlyphs(str->name);
2051 				}
2052 				break;
2053 
2054 			case EDIT_TEXT_TYPE_USED_STRING:
2055 				idx++;
2056 				assert(idx < max, "expected the string for the \"EditText\" used string");
2057 				str = dc_item(list, idx);
2058 				assert(str->type == NODE_TYPE_STRING, "expected a string item for the \"EditText\" used string");
2059 				if(str->name_len > 0) {
2060 					edit_text->AddUsedString(str->name);
2061 				}
2062 				break;
2063 
2064 			case EDIT_TEXT_TYPE_ALIGNMENT:
2065 				idx++;
2066 				assert(idx < max, "expected the string for the \"EditText\" alignment");
2067 				str = dc_item(list, idx);
2068 				assert(str->type == NODE_TYPE_STRING, "expected a string item for the \"EditText\" alignment");
2069 				if(str->name_len > 0) {
2070 					// TODO: we need to know what alignments are supported!
2071 					if(strcasecmp(str->name, "left") == 0) {
2072 						edit_text->SetAlign(sswf::TagEditText::EDIT_TEXT_ALIGNMENT_LEFT);
2073 					}
2074 					else if(strcasecmp(str->name, "right") == 0) {
2075 						edit_text->SetAlign(sswf::TagEditText::EDIT_TEXT_ALIGNMENT_RIGHT);
2076 					}
2077 					else if(strcasecmp(str->name, "center") == 0) {
2078 						edit_text->SetAlign(sswf::TagEditText::EDIT_TEXT_ALIGNMENT_CENTER);
2079 					}
2080 					else if(strcasecmp(str->name, "justify") == 0) {
2081 						edit_text->SetAlign(sswf::TagEditText::EDIT_TEXT_ALIGNMENT_JUSTIFY);
2082 					}
2083 					else {
2084 fprintf(stderr, "ERROR: invalid alignment \"%s\", only \"left\", \"right\", \"center\" or \"justify\" are understood.\n", str->name);
2085 						errcnt++;
2086 					}
2087 				}
2088 				break;
2089 
2090 			default:
2091 				assert(0, "unknown font type (%ld)", * (long *) cd);
2092 				/*NOTREACHED*/
2093 
2094 			}
2095 		}
2096 		else switch(cd->type) {
2097 		case NODE_SUBTYPE_RECT:
2098 			/* transform the data into a rectangle */
2099 			r = dc_rect(cd);
2100 			rect.SetReorder(PIXEL_TO_TWIPS(r->min_x), PIXEL_TO_TWIPS(r->max_x),
2101 					PIXEL_TO_TWIPS(r->min_y), PIXEL_TO_TWIPS(r->max_y));
2102 			/* save it in the edit text */
2103 			edit_text->SetBounds(rect);
2104 			break;
2105 
2106 		case NODE_SUBTYPE_TEXT_SETUP:
2107 			ec = save_edit_text_setup(state, edit_text, dc_list(cd));
2108 			if(ec != 0) {
2109 				return ec;
2110 			}
2111 			break;
2112 
2113 		default:
2114 			/* to avoid warnings */
2115 			assert(0, "unknown data type (%d) for an edit text object", cd->type);
2116 			/*NOTREACHED*/
2117 
2118 		}
2119 	}
2120 
2121 	return 0;
2122 }
2123 
2124 
save_do_action(SaveState & state)2125 static int save_do_action(SaveState& state)
2126 {
2127 	sswf::TagDoAction		*do_action;
2128 	const sswf::TagBaseID		*obj;
2129 	const struct data_common_t	*cd, *ascd;
2130 	const struct data_list_t	*list, *aslst;
2131 	int				ec, max, idx;
2132 	int				sprite_identification;
2133 	const char			*actionscript;
2134 	bool				has_action, has_actionscript;
2135 	unsigned long			actionscript_line;
2136 	const char *			actionscript_filename;
2137 
2138 	has_action = false;
2139 	has_actionscript = false;
2140 	sprite_identification = -1;
2141 	actionscript = 0;
2142 	actionscript_line = 0;
2143 	actionscript_filename = 0;
2144 	list = dc_list(state.f_d);
2145 	max = list->count;
2146 	for(idx = 0; idx < max; idx++) {
2147 		cd = dc_item(list, idx);
2148 		if(list->offset[idx] >= 0) {		// position, depth & clipping
2149 			switch(cd->type) {
2150 			case NODE_SUBTYPE_REFERENCE:
2151 				obj = state.FindRef(cd->name, "sprite");
2152 				if(obj != 0) {
2153 					sprite_identification = obj->Identification();
2154 				}
2155 				break;
2156 
2157 			// skip actions here, these are properly parsed in
2158 			// the save_actions() function below
2159 			case NODE_SUBTYPE_ACTION:
2160 			case NODE_SUBTYPE_LABEL:
2161 			case NODE_SUBTYPE_FUNCTION:
2162 			case NODE_SUBTYPE_WITH:
2163 			case NODE_SUBTYPE_TRY:
2164 			case NODE_SUBTYPE_CATCH:
2165 			case NODE_SUBTYPE_FINALLY:
2166 			case NODE_SUBTYPE_BLOCK:
2167 			case NODE_SUBTYPE_LIST:
2168 				has_action = true;
2169 				break;
2170 
2171 			case NODE_SUBTYPE_ACTION_SCRIPT:
2172 				if(has_actionscript) {
2173 fprintf(stderr, "ERROR: found two or more actionscripts in the same DO ACTION\n");
2174 					errcnt++;
2175 				}
2176 				else {
2177 					has_actionscript = true;
2178 					actionscript_line = cd->node->line;
2179 					actionscript_filename = cd->node->filename;
2180 					aslst = dc_list(cd);
2181 					ascd = dc_item(aslst, 0);
2182 					assert(ascd->type == NODE_TYPE_STRING, "an action script can only be represented by a string");
2183 					if(ascd->name_len > 0) {
2184 						actionscript = ascd->name;
2185 					}
2186 				}
2187 				break;
2188 
2189 			default:
2190 				assert(0, "unknown data type (%d - \"%s\") for a do action", cd->type, node_type_names[cd->type].name);
2191 				/*NOTREACHED*/
2192 
2193 			}
2194 		}
2195 	}
2196 
2197 	if(has_action && has_actionscript) {
2198 fprintf(stderr, "ERROR: found actions and an actionscript in the same DO ACTION\n");
2199 		errcnt++;
2200 		return 1;
2201 	}
2202 
2203 	if(has_actionscript) {
2204 		// we want to compile & assemble this one
2205 		assert(actionscript != 0, "expected the action script variable to be set when ready to use it");
2206 		sswf::asas::Compiler *compiler = new sswf::asas::Compiler();
2207 		sswf::as::NodePtr program;
2208 		sswf::as::Options options;
2209 //fprintf(stderr, "Start the compiler at line #%ld.\n", actionscript_line);
2210 
2211 #ifdef SSWF_INTERNAL_ASC
2212 		// must be done before the call to Compile()
2213 		sswf::asc::AscInputRetriever retriever;
2214 		compiler->SetInputRetriever(retriever);
2215 #endif
2216 
2217 		compiler->SetOptions(options);
2218 		ec = compiler->Compile(program, actionscript, actionscript_line, actionscript_filename);
2219 //fprintf(stderr, "Compiler returned %d errors!\n", ec);
2220 		if(ec == 0) {
2221 //fprintf(stderr, "And now the assembler.\n");
2222 			sswf::asas::Assembler *assembler = new sswf::asas::Assembler();
2223 			assembler->SetOptions(options);
2224 			ec = assembler->AssembleClasses(program, *state.f_parent, has_action);
2225 			if(ec == 0 && has_action) {
2226 				do_action = new sswf::TagDoAction(state.f_parent);
2227 				if(do_action == 0) {
2228 					return -1;
2229 				}
2230 				state.SetLabel(do_action);
2231 				if(sprite_identification != -1) {
2232 					do_action->SetSprite(sprite_identification);
2233 				}
2234 				ec = assembler->Assemble(program, *do_action, &do_action->Actions());
2235 			}
2236 			if(ec != 0) {
2237 				fprintf(stderr, "ERROR: the assembler failed.\n");
2238 			}
2239 			delete assembler;
2240 		}
2241 		else {
2242 			fprintf(stderr, "ERROR: the compiler failed.\n");
2243 		}
2244 		delete compiler;
2245 //fprintf(stderr, "Everything is fine here?! (ec = %d)\n", ec);
2246 		if(ec != 0) {
2247 			errcnt += ec;
2248 			return 1;
2249 		}
2250 		return 0;
2251 	}
2252 
2253 	do_action = new sswf::TagDoAction(state.f_parent);
2254 	if(do_action == 0) {
2255 		return -1;
2256 	}
2257 	state.SetLabel(do_action);
2258 	if(sprite_identification != -1) {
2259 		do_action->SetSprite(sprite_identification);
2260 	}
2261 
2262 	state.f_memory_manager = do_action;
2263 	state.f_actions = &do_action->Actions();
2264 
2265 	ec = save_actions(state);
2266 	if(ec != 0) {
2267 		return 1;
2268 	}
2269 
2270 	return 0;
2271 }
2272 
2273 
save_end(SaveState & state)2274 static int save_end(SaveState& state)
2275 {
2276 	sswf::TagEnd		*end;
2277 
2278 	end = new sswf::TagEnd(state.f_parent);
2279 	if(end == 0) {
2280 		return -1;
2281 	}
2282 
2283 	// NOTE: at this time having the same label multiple times is
2284 	//	 accepted, otherwise it should be marked as being a
2285 	//	 default to avoid duplication errors
2286 	state.SetLabel(end, "end");
2287 
2288 	return 0;
2289 }
2290 
2291 
2292 
2293 
save_export(SaveState & state)2294 static int save_export(SaveState& state)
2295 {
2296 	sswf::TagExport			*export_tag;
2297 	const sswf::TagBaseID		*obj;
2298 	const sswf::TagFont		*font;
2299 	const struct data_common_t	*cd, *str, *glyphs;
2300 	const struct data_list_t	*list;
2301 	const char			*used_glyphs;
2302 	int				max, idx;
2303 
2304 	export_tag = new sswf::TagExport(state.f_parent);
2305 	if(export_tag == 0) {
2306 		return -1;
2307 	}
2308 	state.SetLabel(export_tag);
2309 
2310 	list = dc_list(state.f_d);
2311 	max = list->count;
2312 	for(idx = 0; idx < max; idx++) {
2313 		cd = dc_item(list, idx);
2314 		if(list->offset[idx] >= 0) {		// reference + external name
2315 			switch(cd->type) {
2316 			case NODE_SUBTYPE_REFERENCE:
2317 				idx++;
2318 				assert(idx < max, "expected the string for the object name");
2319 				str = dc_item(list, idx);
2320 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2321 				assert(str->name_len != 0, "a reference name cannot be an empty string in export");
2322 				obj = state.FindRef(cd->name, 0);
2323 				if(obj != 0) {
2324 					// Fonts need to have their glyphs marked used to be incorporated
2325 					used_glyphs = 0;
2326 					font = dynamic_cast<const sswf::TagFont *>(obj);
2327 					if(font != 0) {
2328 						// how do we know whether it is part of this one or the next?
2329 						idx++;
2330 						if(idx < max) {
2331 							glyphs = dc_item(list, idx);
2332 							assert(glyphs->type == NODE_TYPE_STRING, "expected a string item for the \"EditText\" used glyphs");
2333 							if(glyphs->name_len > 0) {
2334 								used_glyphs = glyphs->name;
2335 							}
2336 						}
2337 					}
2338 					export_tag->SetObject(obj->Identification(), str->name, used_glyphs);
2339 				}
2340 				break;
2341 
2342 			default:
2343 				assert(0, "unknown data type (%d - \"%s\") for an export", cd->type, node_type_names[cd->type].name);
2344 				/*NOTREACHED*/
2345 
2346 			}
2347 		}
2348 	}
2349 
2350 
2351 
2352 	return 0;
2353 }
2354 
2355 
2356 
2357 
set_font_type(sswf::TagFont * font,const char * type)2358 static void set_font_type(sswf::TagFont *font, const char *type)
2359 {
2360 	if(strcasecmp(type, "ascii") == 0 || strcasecmp(type, "ansii") == 0) {
2361 		font->SetType(sswf::TagFont::FONT_TYPE_ASCII);
2362 		return;
2363 	}
2364 	if(strcasecmp(type, "unicode") == 0) {
2365 		font->SetType(sswf::TagFont::FONT_TYPE_UNICODE);
2366 		return;
2367 	}
2368 	if(strcasecmp(type, "shiftjis") == 0) {
2369 		font->SetType(sswf::TagFont::FONT_TYPE_SHIFTJIS);
2370 		return;
2371 	}
2372 	if(strcasecmp(type, "italic") == 0) {
2373 		font->SetItalic(true);
2374 		return;
2375 	}
2376 	if(strcasecmp(type, "bold") == 0) {
2377 		font->SetBold(true);
2378 		return;
2379 	}
2380 	/* the user can force the WIDE flag -- not sure why... */
2381 	if(strcasecmp(type, "wide") == 0) {
2382 		font->SetWide(true);
2383 		return;
2384 	}
2385 
2386 	fprintf(stderr, "ERROR: don't understand font type \"%s\".\n", type);
2387 	errcnt++;
2388 }
2389 
2390 
font_wide_char(int len,const char * str,sswf::sswf_ucs4_t * kern)2391 static sswf::sswf_ucs4_t font_wide_char(int len, const char *str, sswf::sswf_ucs4_t *kern)
2392 {
2393 	sswf::sswf_ucs4_t	*s, c[2];
2394 	size_t			sz;
2395 
2396 	if(len == 0 || str == 0) {
2397 		return 0;
2398 	}
2399 
2400 	if(*str == '\0') {
2401 		return 0;
2402 	}
2403 
2404 	if(*str != '\\') {
2405 		sz = sizeof(c);
2406 		s = c;
2407 		if(sswf::mbtowc(str, len, s, sz) != 0) {
2408 			return 0;
2409 		}
2410 		if(kern != 0) {
2411 			// if it is a kerning definition, we want two chars
2412 			if(sz != 0) {
2413 				return 0;
2414 			}
2415 			*kern = c[1];
2416 		}
2417 		else {
2418 			// if not a kerning definition, we want only one char
2419 			if(sz == 0) {
2420 				return 0;
2421 			}
2422 		}
2423 		return c[0];
2424 	}
2425 
2426 	/* a stand alone backslash? */
2427 	if(str[1] == '\0') {
2428 		return (int) '\\';
2429 	}
2430 
2431 /* LEGACY CODE, THE NEW CODE ALLOWS FOR WIDE CHARS IN SOURCE FILES
2432  * AND THAT SHOULD BE USED INSTEAD (i.e. \x276 is prefered to the
2433  * old \\x276)
2434  * NOTE: the character '\x276' are automatically transformed in
2435  *	 the sswf_lexical.c++ file; the following will take care
2436  *	 of '\\x276' since the lexical will have transformed the
2437  *	 '\\...' into '\...'.
2438  */
2439 	if(str[1] != 'x' && str[1] != 'X') {
2440 		return 0;
2441 	}
2442 
2443 	/* we have a wide character definition alright */
2444 	return strtol(str + 2, NULL, 16);
2445 }
2446 
2447 
save_font(SaveState & state)2448 static int save_font(SaveState& state)
2449 {
2450 	sswf::TagFont			*font;
2451 	const sswf::TagBaseID		*obj;
2452 	sswf::TagFont::font_language_t	lang;
2453 	const struct data_list_t	*list;
2454 	const struct data_common_t	*cd, *str, *ref;
2455 	const struct data_font_t	*f;
2456 	const struct data_font_advance_t*a;
2457 	const struct data_font_kerning_t*k;
2458 	const char			*s;
2459 	long				ascent, descent, leading_height;
2460 	int				idx, max, len;
2461 	sswf::sswf_ucs4_t		c, c2;
2462 
2463 	font = new sswf::TagFont(state.f_parent);
2464 	if(font == 0) {
2465 		return -1;
2466 	}
2467 	state.RecordRef(font);
2468 
2469 	list = dc_list(state.f_d);
2470 	max = list->count;
2471 	for(idx = 0; idx < max; idx++) {
2472 		cd = dc_item(list, idx);
2473 		if(list->offset[idx] < 0) {
2474 			switch(* (long *) cd) {		// switch on the type
2475 			case FONT_TYPE_LAYOUT:
2476 				// font information
2477 				f = (const struct data_font_t *) cd;
2478 				if(f->ascent != -1E+128 || f->descent != -1E+128 || f->leading_height != -1E+128) {
2479 					ascent = f->ascent == -1E+128 ? font->DefaultAscent() : (long) PIXEL_TO_TWIPS(f->ascent);
2480 					descent = f->descent == -1E+128 ? font->DefaultDescent() : (long) PIXEL_TO_TWIPS(f->descent);
2481 					leading_height = f->leading_height == -1E+128 ? font->DefaultLeadingHeight() : (long) PIXEL_TO_TWIPS(f->leading_height);
2482 					font->SetLayout(ascent, descent, leading_height);
2483 				}
2484 				if(f->advance != -1E+128) {
2485 					font->SetDefaultAdvance(PIXEL_TO_TWIPS(f->advance));
2486 				}
2487 				if(f->space != -1E+128) {
2488 					font->SetSpaceAdvance(PIXEL_TO_TWIPS(f->space));
2489 				}
2490 				break;
2491 
2492 			case FONT_TYPE_ADVANCE:
2493 				// this is when we have a character name, shape reference and specific advance
2494 				idx++;
2495 				assert(idx < max, "expected the character in a string");
2496 				str = dc_item(list, idx);
2497 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2498 				// TODO: the characters larger than 0xFFFF must be supported for
2499 				// chinese, korean and other asian fonts...
2500 				len = strlen(str->name);
2501 				c = font_wide_char(len, str->name, 0);
2502 				if(c == 0) {
2503 					if(len == 0) {
2504 						s = "";
2505 					}
2506 					else {
2507 						s = str->name;
2508 					}
2509 					fprintf(stderr, "ERROR: a character definition requires a string of exactly 1 character (\"%s\" -", s);
2510 					while(*s != '\0') {
2511 						fprintf(stderr, " 0x%02X", (int) *s);
2512 						s++;
2513 					}
2514 					fprintf(stderr, " - refused).\n");
2515 					errcnt++;
2516 					break;
2517 				}
2518 				idx++;
2519 				assert(idx < max, "expected a reference to a shape (not present)");
2520 				ref = dc_item(list, idx);
2521 				assert(ref->type == NODE_SUBTYPE_REFERENCE, "expected a reference to a shape (invalid type: %d)", ref->type);
2522 				obj = state.FindRef(ref->name, "shape");
2523 				if(obj == 0) {
2524 					break;
2525 				}
2526 				a = (const struct data_font_advance_t *) cd;
2527 				if(a->x == -1E+128) {
2528 					font->AddGlyph(c, obj);
2529 				}
2530 				else {
2531 					font->AddGlyph(c, obj, PIXEL_TO_TWIPS(a->x));
2532 				}
2533 				break;
2534 
2535 			case FONT_TYPE_LANGUAGE:
2536 				idx++;
2537 				assert(idx < max, "expected the string for the font language");
2538 				str = dc_item(list, idx);
2539 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2540 				if(str->name_len > 0) {
2541 					lang = sswf::TagFont::StringToLanguage(str->name);
2542 					if(lang < 0 || lang >= sswf::TagFont::FONT_LANGUAGE_max) {
2543 fprintf(stderr, "ERROR: language \"%s\" is unknown or is not supported.\n", str->name);
2544 						errcnt++;
2545 					}
2546 					else {
2547 						font->SetLanguage(lang);
2548 					}
2549 				}
2550 				break;
2551 
2552 			case FONT_TYPE_NAME:
2553 				idx++;
2554 				assert(idx < max, "expected the string for the font name");
2555 				str = dc_item(list, idx);
2556 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2557 				if(str->name_len > 0) {
2558 					font->SetName(str->name);
2559 				}
2560 				break;
2561 
2562 			case FONT_TYPE_DISPLAY_NAME:
2563 				idx++;
2564 				assert(idx < max, "expected the string for the font display name");
2565 				str = dc_item(list, idx);
2566 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2567 				if(str->name_len > 0) {
2568 					font->SetDisplayName(str->name);
2569 				}
2570 				break;
2571 
2572 			case FONT_TYPE_COPYRIGHT:
2573 				idx++;
2574 				assert(idx < max, "expected the string for the font copyright");
2575 				str = dc_item(list, idx);
2576 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2577 				if(str->name_len > 0) {
2578 					font->SetCopyright(str->name);
2579 				}
2580 				break;
2581 
2582 			case FONT_TYPE_TYPE:
2583 				idx++;
2584 				assert(idx < max, "expected one or more strings to describ the font type");
2585 				str = dc_item(list, idx);
2586 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2587 				if(str->name_len > 0) {
2588 					set_font_type(font, str->name);
2589 				}
2590 				/* check for more strings */
2591 				while(idx + 1 < max) {
2592 					str = dc_item(list, idx + 1);
2593 					if(str->type != NODE_TYPE_STRING) {
2594 						break;
2595 					}
2596 					idx++;
2597 					if(str->name_len > 0) {
2598 						set_font_type(font, str->name);
2599 					}
2600 				}
2601 				break;
2602 
2603 			case FONT_TYPE_KERNING:
2604 				idx++;
2605 				assert(idx < max, "expected the kerning letters in a string");
2606 				str = dc_item(list, idx);
2607 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2608 				// TODO: the characters larger than 0xFFFF must be supported for
2609 				// chinese, korean and other asian fonts...
2610 				len = strlen(str->name);
2611 				c = font_wide_char(len, str->name, &c2);
2612 				if(c == 0) {
2613 fprintf(stderr, "ERROR: a kerning definition requires a string of exactly 2 characters (\"%s\" refused).\n", str->name);
2614 					errcnt++;
2615 					break;
2616 				}
2617 				k = (const struct data_font_kerning_t *) cd;
2618 				font->AddKern(c, c2, PIXEL_TO_TWIPS(k->x));
2619 				break;
2620 
2621 			default:
2622 				assert(0, "unknown font type (%ld)", * (long *) cd);
2623 				/*NOTREACHED*/
2624 
2625 			}
2626 		}
2627 		// else ... skip all the others since all are preceeded by a structure
2628 	}
2629 
2630 	return 0;
2631 }
2632 
2633 
save_frame_label(SaveState & state)2634 static int save_frame_label(SaveState& state)
2635 {
2636 	sswf::TagFrameLabel		*frame_label;
2637 
2638 	frame_label = new sswf::TagFrameLabel(state.f_parent);
2639 	if(frame_label == 0) {
2640 		return -1;
2641 	}
2642 
2643 	assert(state.f_d->name_len > 0, "a frame label must have a name");
2644 	frame_label->SetLabel(state.f_d->name);
2645 	frame_label->SetFrameLabel(state.f_d->name);
2646 
2647 	return 0;
2648 }
2649 
2650 
2651 
2652 
2653 
save_image(SaveState & state)2654 static int save_image(SaveState& state)
2655 {
2656 	sswf::TagImage			*image;
2657 	const struct data_image_t	*f;
2658 	const struct data_common_t	*cd, *mask;
2659 	const struct data_list_t	*list;
2660 	int				idx, max;
2661 	const char			*mask_name;
2662 
2663 	image = new sswf::TagImage(state.f_parent);
2664 	if(image == 0) {
2665 		return -1;
2666 	}
2667 	state.RecordRef(image);
2668 
2669 	list = dc_list(state.f_d);
2670 	max = list->count;
2671 	for(idx = 0; idx < max; idx++) {
2672 		cd = dc_item(list, idx);
2673 		if(list->offset[idx] < 0) {
2674 			// format
2675 			f = (const struct data_image_t *) cd;
2676 			switch(static_cast<enum image_format_t>(f->format)) {
2677 			case IMAGE_FORMAT_LOSSLESS:
2678 				image->SetFormat(sswf::TagImage::IMAGE_FORMAT_LOSSLESS_BEST);
2679 				break;
2680 
2681 			case IMAGE_FORMAT_LOSSLESS_8:
2682 				image->SetFormat(sswf::TagImage::IMAGE_FORMAT_LOSSLESS_8);
2683 				break;
2684 
2685 			case IMAGE_FORMAT_LOSSLESS_16:
2686 				image->SetFormat(sswf::TagImage::IMAGE_FORMAT_LOSSLESS_16);
2687 				break;
2688 
2689 			case IMAGE_FORMAT_LOSSLESS_32:
2690 				image->SetFormat(sswf::TagImage::IMAGE_FORMAT_LOSSLESS_32);
2691 				break;
2692 
2693 			case IMAGE_FORMAT_JPEG:
2694 				image->SetFormat(sswf::TagImage::IMAGE_FORMAT_JPEG);
2695 				if(f->quality != -1E+128) {
2696 					image->SetQuality((long) rint(f->quality * 100.0));
2697 				}
2698 				break;
2699 
2700 			}
2701 		}
2702 		else if(cd->type == NODE_TYPE_STRING) {
2703 			// image name
2704 			mask_name = 0;
2705 			if(idx + 1 < max) {
2706 				idx++;
2707 				mask = dc_item(list, idx);
2708 				if(mask->type == NODE_TYPE_STRING) {
2709 					// there is a mask definition as well
2710 					mask_name = mask->name;
2711 				}
2712 				else {
2713 					idx--;
2714 				}
2715 			}
2716 			if(image->SetFilename(cd->name, mask_name) != 0) {
2717 				fprintf(stderr, "ERROR: cannot read image \"%s\" (or mask \"%s\"). Are these targa or JPEG files?\n",
2718 						cd->name, mask_name == 0 ? "<no mask>" : mask_name);
2719 				errcnt++;
2720 				return -1;
2721 			}
2722 		}
2723 		else {
2724 			assert(0, "unknown data type (%d) for an image", cd->type);
2725 		}
2726 	}
2727 
2728 	return 0;
2729 }
2730 
2731 
save_import(SaveState & state)2732 static int save_import(SaveState& state)
2733 {
2734 	sswf::TagImport			*import;
2735 	TagImportID			*import_id;
2736 	const struct data_import_t	*imp;
2737 	const struct data_common_t	*cd, *str, *type;
2738 	const struct data_list_t	*list;
2739 	int				max, idx;
2740 	const char			*type_name;
2741 	sswf::sswf_id_t			id;
2742 
2743 	import = new sswf::TagImport(state.f_parent);
2744 	if(import == 0) {
2745 		return -1;
2746 	}
2747 	state.SetLabel(import);
2748 
2749 	list = dc_list(state.f_d);
2750 	max = list->count;
2751 	for(idx = 0; idx < max; idx++) {
2752 		cd = dc_item(list, idx);
2753 		if(list->offset[idx] < 0) {
2754 			imp = (const struct data_import_t *) cd;
2755 			switch(imp->type) {
2756 			case IMPORT_TYPE_URL:
2757 				idx++;
2758 				assert(idx < max, "expected a string with the external name");
2759 				str = dc_item(list, idx);
2760 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2761 				assert(str->name_len != 0 && str->name[0] != '\0', "a movie URL reference name cannot be an empty string in import");
2762 				import->SetURL(str->name);
2763 				break;
2764 
2765 			case IMPORT_TYPE_FILENAME:
2766 				idx++;
2767 				assert(idx < max, "expected a string with the SSWF script filename");
2768 				str = dc_item(list, idx);
2769 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2770 				assert(str->name_len != 0 && str->name[0] != '\0', "a script filename cannot be empty");
2771 				// TODO: how can we really deal with this now?!?
2772 				// we may want to look into doing the 'using <filename>;'
2773 				// first and reuse that for this purpose
2774 				import->SetFilename(str->name);
2775 				break;
2776 
2777 			case IMPORT_TYPE_NAME:
2778 				idx++;
2779 				assert(idx < max, "expected a string with the external name reference");
2780 				str = dc_item(list, idx);
2781 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2782 				assert(str->name_len != 0 && str->name[0] != '\0', "a reference name cannot be empty in an IMPORT");
2783 
2784 				// if there is a 2nd string, that's the type of the item
2785 				type_name = "imported";
2786 				if(idx + 1 < max && list->offset[idx + 1] >= 0) {
2787 					type = dc_item(list, idx + 1);
2788 					if(type->type == NODE_TYPE_STRING) {
2789 						idx++;
2790 						assert(type->name_len != 0 && type->name[0] != '\0', "a reference type cannot be empty in an IMPORT");
2791 						type_name = type->name;
2792 					}
2793 				}
2794 
2795 				import->AddName(str->name, type_name);
2796 
2797 				// we also need to add a reference here
2798 				// Note that the name needs to include the cd->name too
2799 				// (....<import tag name>.<cd->name>)
2800 				id = import->HasName(str->name);
2801 				import_id = new TagImportID(*import, id, type_name);
2802 				state.RecordRef(import_id, str->name);
2803 				break;
2804 
2805 			default:
2806 				assert(0, "undefined import type");
2807 				/*NOTREACHED*/
2808 
2809 			}
2810 		}
2811 		else {
2812 			assert(0, "unknown data type (%d - \"%s\") for an IMPORT object", cd->type, node_type_names[cd->type].name);
2813 			/*NOTREACHED*/
2814 		}
2815 	}
2816 
2817 	return 0;
2818 }
2819 
2820 
save_metadata(SaveState & state)2821 static int save_metadata(SaveState& state)
2822 {
2823 	sswf::TagMetadata		*metadata;
2824 	const struct data_metadata_t	*met;
2825 	const struct data_common_t	*cd, *str;
2826 	const struct data_list_t	*list;
2827 	int				max, idx;
2828 
2829 	metadata = new sswf::TagMetadata(state.f_parent);
2830 	if(metadata == 0) {
2831 		return -1;
2832 	}
2833 
2834 	if(state.f_d->length - state.f_d->name_len == sizeof(struct data_common_t)) {
2835 		// use default
2836 		return 0;
2837 	}
2838 
2839 	list = dc_list(state.f_d);
2840 	max = list->count;
2841 	for(idx = 0; idx < max; idx++) {
2842 		cd = dc_item(list, idx);
2843 		if(list->offset[idx] < 0) {
2844 			met = (const struct data_metadata_t *) cd;
2845 			switch(met->type) {
2846 			case METADATA_TYPE_FILENAME:
2847 				idx++;
2848 				assert(idx < max, "expected a string for the filename");
2849 				str = dc_item(list, idx);
2850 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2851 				if(str->name_len != 0) {
2852 					metadata->SetFilename(str->name);
2853 				}
2854 				break;
2855 
2856 			case METADATA_TYPE_METADATA:
2857 				idx++;
2858 				assert(idx < max, "expected a string of metadata");
2859 				str = dc_item(list, idx);
2860 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2861 				if(str->name_len != 0) {
2862 					metadata->SetMetadata(str->name);
2863 				}
2864 				break;
2865 
2866 			case METADATA_TYPE_TITLE:
2867 				idx++;
2868 				assert(idx < max, "expected a string for the movie title");
2869 				str = dc_item(list, idx);
2870 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2871 				if(str->name_len != 0) {
2872 					metadata->SetTitle(str->name);
2873 				}
2874 				break;
2875 
2876 			case METADATA_TYPE_DESCRIPTION:
2877 				idx++;
2878 				assert(idx < max, "expected a string for the movie description");
2879 				str = dc_item(list, idx);
2880 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2881 				if(str->name_len != 0) {
2882 					metadata->SetDescription(str->name);
2883 				}
2884 				break;
2885 
2886 			case METADATA_TYPE_AUTHOR:
2887 				idx++;
2888 				assert(idx < max, "expected a string for the movie author");
2889 				str = dc_item(list, idx);
2890 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2891 				if(str->name_len != 0) {
2892 					metadata->SetAuthor(str->name);
2893 				}
2894 				break;
2895 
2896 			case METADATA_TYPE_PUBLISHER:
2897 				idx++;
2898 				assert(idx < max, "expected a string for the movie publisher");
2899 				str = dc_item(list, idx);
2900 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2901 				if(str->name_len != 0) {
2902 					metadata->SetPublisher(str->name);
2903 				}
2904 				break;
2905 
2906 			case METADATA_TYPE_COPYRIGHT:
2907 				idx++;
2908 				assert(idx < max, "expected a string for the movie copyright");
2909 				str = dc_item(list, idx);
2910 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2911 				if(str->name_len != 0) {
2912 					metadata->SetCopyright(str->name);
2913 				}
2914 				break;
2915 
2916 			case METADATA_TYPE_URL:
2917 				idx++;
2918 				assert(idx < max, "expected a string for the movie about URL");
2919 				str = dc_item(list, idx);
2920 				assert(str->type == NODE_TYPE_STRING, "expected a string item");
2921 				if(str->name_len != 0) {
2922 					metadata->SetURL(str->name);
2923 				}
2924 				break;
2925 
2926 			default:
2927 				assert(0, "undefined metadata type");
2928 				/*NOTREACHED*/
2929 
2930 			}
2931 		}
2932 		else {
2933 			assert(0, "unknown data type (%d - \"%s\") for a METADATA object", cd->type, node_type_names[cd->type].name);
2934 			/*NOTREACHED*/
2935 		}
2936 	}
2937 
2938 	return 0;
2939 }
2940 
2941 
save_place_object(SaveState & state)2942 static int save_place_object(SaveState& state)
2943 {
2944 	sswf::TagPlace				*place;
2945 	sswf::TagSetTabIndex			*set_tab_index;
2946 	sswf::Matrix				matrix;
2947 	sswf::ColorTransform			color_transform;
2948 	sswf::Event				*event;
2949 	sswf::BlendMode				blend_mode;
2950 	const sswf::TagBaseID			*obj;
2951 	const struct data_common_t		*cd, *str;
2952 	const struct data_list_t		*list, *sub_list;
2953 	const struct data_place_object_t	*place_object;
2954 	const struct data_matrix_t		*m;
2955 	const struct data_color_transform_t	*c;
2956 	const struct data_color_t		*col;
2957 	int					idx, max;
2958 	long					v, d, clip;
2959 	const char				*obj_name;
2960 
2961 	place = new sswf::TagPlace(state.f_parent);
2962 	if(place == 0) {
2963 		return -1;
2964 	}
2965 	state.SetLabel(place);
2966 
2967 	if(state.f_d->type == NODE_SUBTYPE_REPLACE_OBJECT) {
2968 		// we don't want the move flag to be set in this case
2969 		place->Replace();
2970 	}
2971 
2972 	list = dc_list(state.f_d);
2973 	max = list->count;
2974 	for(idx = 0; idx < max; idx++) {
2975 		cd = dc_item(list, idx);
2976 		if(list->offset[idx] < 0) {		// position, depth, clipping, tab index & bitmap type
2977 			place_object = (const struct data_place_object_t *) cd;
2978 			switch(place_object->type) {		// switch on the type
2979 			case PLACE_OBJECT_TYPE_VALUE:
2980 				d = (long) rint(place_object->depth);
2981 				assert(d >= 0 && d <= 65535, "invalid depth parameter");
2982 				place->SetDepth(d);
2983 				if(place_object->clip != -1E+128) {
2984 					clip = (long) rint(place_object->clip);
2985 					assert(clip >= 1 && clip <= 65535, "invalid clip depth parameter");
2986 					assert(clip + d <= 65535, "invalid clip depth parameter");
2987 					place->SetClip(clip + d);
2988 				}
2989 				if(place_object->position >= 0.0) {
2990 					// in our script language we expect a position from 0.0 to 1.0
2991 					v = (long) rint(place_object->position * 65535.0);
2992 					if(v > 65535) {
2993 						v = 65535;
2994 					}
2995 					place->SetMorphPosition(v);
2996 				}
2997 				if(place_object->tab_index != -1E+128) {
2998 					// ha! the person also wants to have a SetTabIndex tag
2999 					set_tab_index = new sswf::TagSetTabIndex(state.f_parent);
3000 					if(set_tab_index == 0) {
3001 						return -1;
3002 					}
3003 					state.SetLabel(set_tab_index);
3004 					set_tab_index->SetDepth(d);
3005 					v = (long) rint(place_object->tab_index);
3006 					assert(v >= 0 && v <= 65535, "invalid tab index parameter");
3007 					set_tab_index->SetIndex(v);
3008 				}
3009 				if(place_object->bitmap_caching != 0.0) {
3010 					// at this time I'm assuming you need to set it to "true"...
3011 					place->SetBitmapCaching(1);
3012 				}
3013 				break;
3014 
3015 			case PLACE_OBJECT_TYPE_NAME:
3016 				idx++;
3017 				assert(idx < max, "expected the string for the \"PlaceObject\" name");
3018 				str = dc_item(list, idx);
3019 				assert(str->type == NODE_TYPE_STRING, "expected a string item for the \"PlaceObject\" name");
3020 				if(str->name_len > 0) {
3021 					place->SetName(str->name);
3022 					//printf("String = [%s]\n", str->name);
3023 				}
3024 				break;
3025 
3026 			case PLACE_OBJECT_TYPE_BLEND_MODE:
3027 				idx++;
3028 				assert(idx < max, "expected the string for the \"PlaceObject\" blend mode");
3029 				str = dc_item(list, idx);
3030 				assert(str->type == NODE_TYPE_STRING, "expected a string item for the \"PlaceObject\" blend mode");
3031 				if(str->name_len > 0) {
3032 					if(blend_mode.SetBlendModeByName(str->name)) {
3033 						place->SetBlendMode(blend_mode);
3034 					}
3035 					else {
3036 fprintf(stderr, "ERROR: in a PLACE object, unknown blend mode \"%s\".\n", str->name);
3037 					}
3038 					//printf("Blend Mode = [%s]\n", str->name);
3039 				}
3040 				break;
3041 
3042 			}
3043 		}
3044 		else {
3045 			/* all sub-data except the rectangle but that way cd points at the right place then */
3046 			sub_list = dc_list(cd);
3047 			switch(cd->type) {
3048 			case NODE_SUBTYPE_REFERENCE:
3049 				obj = state.FindRef(cd->name, 0);
3050 				if(obj != 0) {
3051 					obj_name = obj->Name();
3052 					if(strcmp(obj_name, "button")   == 0
3053 					|| strcmp(obj_name, "edit")     == 0
3054 					|| strcmp(obj_name, "imported") == 0
3055 					|| strcmp(obj_name, "shape")    == 0
3056 					|| strcmp(obj_name, "sprite")   == 0
3057 					|| strcmp(obj_name, "text")     == 0) {
3058 						place->SetObjectID(obj->Identification());
3059 					}
3060 					else {
3061 fprintf(stderr, "ERROR: in a PLACE object, the reference to \"%s\" needs to be to an object of type: button, edit text, imported, shape, sprite or text (current type \"%s\").\n", cd->name, obj_name);
3062 						errcnt++;
3063 					}
3064 				}
3065 				break;
3066 
3067 			case NODE_SUBTYPE_MATRIX:
3068 				m = (const struct data_matrix_t *) sub_list;
3069 				save_set_matrix(matrix, m);
3070 				place->SetMatrix(matrix);
3071 				break;
3072 
3073 			case NODE_SUBTYPE_COLOR_TRANSFORM:
3074 				c = (const struct data_color_transform_t *) sub_list;
3075 				color_transform.SetAdd(c->add_red, c->add_green, c->add_blue, c->add_alpha);
3076 				color_transform.SetMult(c->mult_red, c->mult_green, c->mult_blue, c->mult_alpha);
3077 				place->SetColorTransform(color_transform);
3078 				break;
3079 
3080 			case NODE_SUBTYPE_COLOR:
3081 				col = (const struct data_color_t *) sub_list;
3082 				color_transform.SetAdd(col->red, col->green, col->blue, col->alpha);
3083 				color_transform.SetMult(0, 0, 0, 0);
3084 				place->SetColorTransform(color_transform);
3085 				break;
3086 
3087 			case NODE_SUBTYPE_ON_EVENT:
3088 				event = save_on_event(state, place, cd);
3089 				if(event == 0) {
3090 					return -1;
3091 				}
3092 				place->AddEvent(event);
3093 				break;
3094 
3095 			default:
3096 				/* to avoid warnings */
3097 				assert(0, "unknown data type (%d) for a place object", cd->type);
3098 				/*NOTREACHED*/
3099 
3100 			}
3101 		}
3102 	}
3103 
3104 	return 0;
3105 }
3106 
3107 
3108 
save_scene_frame_data(SaveState & state)3109 static int save_scene_frame_data(SaveState& state)
3110 {
3111 	sswf::TagSceneFrameData		*scene_frame_data;
3112 	const struct data_common_t	*cd;
3113 	const struct data_list_t	*list;
3114 	int				max, idx;
3115 
3116 	scene_frame_data = new sswf::TagSceneFrameData(state.f_parent);
3117 	if(scene_frame_data == 0) {
3118 		return -1;
3119 	}
3120 
3121 	list = dc_list(state.f_d);
3122 	max = list->count;
3123 	for(idx = 0; idx < max; idx++) {
3124 		cd = dc_item(list, idx);
3125 		if(cd->type == NODE_TYPE_STRING) {
3126 			// set the filename
3127 			scene_frame_data->SetFileData(cd->name);
3128 		}
3129 		else {
3130 			assert(0, "unknown data type (%d - \"%s\") for a SCENE & FRAME DATA object", cd->type, node_type_names[cd->type].name);
3131 			/*NOTREACHED*/
3132 		}
3133 	}
3134 
3135 	return 0;
3136 }
3137 
3138 
save_remove(SaveState & state)3139 static int save_remove(SaveState& state)
3140 {
3141 	const sswf::TagBaseID		*obj;
3142 	sswf::TagRemove			*remove;
3143 	const struct data_common_t	*cd;
3144 	const struct data_list_t	*list;
3145 	const struct data_remove_t	*depth;
3146 	int				idx, max;
3147 
3148 	remove = new sswf::TagRemove(state.f_parent);
3149 	if(remove == 0) {
3150 		return -1;
3151 	}
3152 	state.SetLabel(remove);
3153 
3154 	list = dc_list(state.f_d);
3155 	max = list->count;
3156 	for(idx = 0; idx < max; idx++) {
3157 		cd = dc_item(list, idx);
3158 		if(list->offset[idx] < 0) {
3159 			depth = (const struct data_remove_t *) cd;
3160 			remove->SetDepth(static_cast<int>(depth->depth));
3161 		}
3162 		else {
3163 			switch(cd->type) {
3164 			case NODE_SUBTYPE_REFERENCE:
3165 				obj = state.FindRef(cd->name, 0);
3166 				if(obj != 0) {
3167 					if(strcmp(obj->Name(), "button")   == 0
3168 					|| strcmp(obj->Name(), "edit")     == 0
3169 					|| strcmp(obj->Name(), "imported") == 0
3170 					|| strcmp(obj->Name(), "shape")    == 0
3171 					|| strcmp(obj->Name(), "sprite")   == 0
3172 					|| strcmp(obj->Name(), "text")     == 0) {
3173 						remove->SetObjectID(obj->Identification());
3174 					}
3175 					else {
3176 fprintf(stderr, "ERROR: in a REMOVE object, the reference to \"%s\" needs to be to an object of type: button, edit text, imported, shape, sprite or text.\n", cd->name);
3177 						errcnt++;
3178 					}
3179 				}
3180 				break;
3181 
3182 			default:
3183 				/* to avoid warnings */
3184 				assert(0, "unknown data type (%d) for a remove", cd->type);
3185 				/*NOTREACHED*/
3186 
3187 			}
3188 		}
3189 	}
3190 
3191 	return 0;
3192 }
3193 
3194 
3195 
3196 
save_script_limits(SaveState & state)3197 static int save_script_limits(SaveState& state)
3198 {
3199 	sswf::TagScriptLimits			*sl;
3200 	const struct data_script_limits_t	*script_limits;
3201 
3202 	sl = new sswf::TagScriptLimits(state.f_parent);
3203 	if(sl == 0) {
3204 		return -1;
3205 	}
3206 	state.SetLabel(sl);
3207 
3208 	script_limits = dc_script_limits(state.f_d);
3209 	sl->SetMaxRecursionDepth(static_cast<int>(ceil(script_limits->max_recursion_depth)));
3210 	sl->SetTimeoutSeconds(static_cast<int>(ceil(script_limits->timeout_seconds)));
3211 
3212 	return 0;
3213 }
3214 
3215 
3216 
save_set_background_color(SaveState & state)3217 static int save_set_background_color(SaveState& state)
3218 {
3219 	sswf::TagSetBackgroundColor	*sbc;
3220 	struct data_list_t		*list;
3221 	struct data_color_t		*col;
3222 	struct data_common_t		*cd;
3223 
3224 	sbc = new sswf::TagSetBackgroundColor(state.f_parent);
3225 	if(sbc == 0) {
3226 		return -1;
3227 	}
3228 	state.SetLabel(sbc);
3229 
3230 	// get to the color data and put it in the sbc object
3231 	list = dc_list(state.f_d);
3232 	if(list->count == 0) {
3233 		// keep the default (white)
3234 		return 0;
3235 	}
3236 
3237 	// a direct color definition?
3238 	if(list->offset[0] < 0) {
3239 		// only RGB is defined in this case
3240 		col = dc_item_color(list, 0);
3241 	}
3242 	else {
3243 		// RGBA is defined here - we don't check the alpha it was done before
3244 		cd = dc_item(list, 0);
3245 		col = dc_color(cd);
3246 	}
3247 
3248 	sbc->GetColor().Set(CLAMPED_BYTE_COLOR(col->red), CLAMPED_BYTE_COLOR(col->green), CLAMPED_BYTE_COLOR(col->blue));
3249 
3250 	return 0;
3251 }
3252 
3253 
3254 
save_set_tab_index(SaveState & state)3255 static int save_set_tab_index(SaveState& state)
3256 {
3257 	sswf::TagSetTabIndex			*sti;
3258 	const struct data_set_tab_index_t	*set_tab_index;
3259 
3260 	sti = new sswf::TagSetTabIndex(state.f_parent);
3261 	if(sti == 0) {
3262 		return -1;
3263 	}
3264 	state.SetLabel(sti);
3265 
3266 	set_tab_index = dc_set_tab_index(state.f_d);
3267 	sti->SetDepth(static_cast<int>(rint(set_tab_index->depth)));
3268 	sti->SetIndex(static_cast<int>(rint(set_tab_index->index)));
3269 
3270 	return 0;
3271 }
3272 
3273 
3274 
save_find_shape(SaveState & state)3275 static const struct data_common_t *save_find_shape(SaveState& state)
3276 {
3277 	sswf::TagBase			*child;
3278 	const struct data_common_t	*cd;
3279 
3280 	// note: a shape is a Define and it cannot be in a sprite
3281 	child = state.f_header.Children();
3282 	while(child != 0) {
3283 		if(child->f_userdata != 0) {
3284 			cd = (const struct data_common_t *) child->f_userdata;
3285 			if(cd->length == state.f_d->length) {
3286 				if(memcmp(cd, state.f_d, state.f_d->length) == 0) {
3287 					// ha! it already exists, do insert it again
3288 					return cd;
3289 				}
3290 			}
3291 		}
3292 		child = child->Next();
3293 	}
3294 
3295 	return 0;
3296 }
3297 
3298 
3299 
3300 
save_shape_line(SaveState & state,sswf::TagShape * shape,const struct data_list_t * list)3301 static int save_shape_line(SaveState& state, sswf::TagShape *shape, const struct data_list_t *list)
3302 {
3303 	sswf::Color			color;
3304 	sswf::Style			style(state.f_header);
3305 	const struct data_common_t	*cd;
3306 	const struct data_line_style_t	*w;
3307 	const struct data_color_t	*col, *col_to;
3308 	int				idx, max;
3309 	double				width, to_width;
3310 	bool				morph;
3311 
3312 	col = 0;
3313 	col_to = 0;
3314 	morph = false;
3315 	width = 1;
3316 	to_width = 1;
3317 	w = 0;
3318 
3319 /* empty lines still have 1 entry since the width is already included! */
3320 	assert(list != 0, "a list always includes at least the default width");
3321 
3322 	max = list->count;
3323 	for(idx = 0; idx < max; idx++) {
3324 		cd = dc_item(list, idx);
3325 		if(list->offset[idx] < 0) {
3326 			// we got the width and such
3327 			w = (const struct data_line_style_t *) cd;
3328 			width = w->width;
3329 			if(w->to_width != -1.0) {
3330 				morph = true;
3331 				to_width = w->to_width;
3332 			}
3333 			else {
3334 				to_width = width;
3335 			}
3336 		}
3337 		else {
3338 			// here we have a color
3339 			if(col == 0) {
3340 				col = dc_color(cd);
3341 			}
3342 			else {
3343 				col_to = dc_color(cd);
3344 				morph = true;
3345 			}
3346 		}
3347 	}
3348 
3349 	if(col == 0) {		// empty line style -> no line style!
3350 		style.SetType(sswf::Style::STYLE_TYPE_NO_LINE);
3351 	}
3352 	else {
3353 		color.Set(CLAMPED_BYTE_COLOR(col->red), CLAMPED_BYTE_COLOR(col->green),
3354 				CLAMPED_BYTE_COLOR(col->blue), CLAMPED_BYTE_COLOR(col->alpha));
3355 		style.SetLine(0, (unsigned short) PIXEL_TO_TWIPS(width), color);
3356 		if(morph) {
3357 			if(col_to != 0) {
3358 				color.Set(CLAMPED_BYTE_COLOR(col_to->red), CLAMPED_BYTE_COLOR(col_to->green),
3359 						CLAMPED_BYTE_COLOR(col_to->blue), CLAMPED_BYTE_COLOR(col_to->alpha));
3360 			}
3361 			style.SetLine(1, (unsigned short) PIXEL_TO_TWIPS(to_width), color);
3362 		}
3363 
3364 		// ensure a correct type (and also that so far everything went well)
3365 		style.SetType(sswf::Style::STYLE_TYPE_LINE);
3366 
3367 		if(w != 0) {
3368 			if(static_cast<sswf::Style::cap_t>(static_cast<int>(w->cap_start)) != sswf::Style::STYLE_LINE_CAP_SAME) {
3369 				style.SetLineCaps(static_cast<sswf::Style::cap_t>(static_cast<int>(w->cap_start)),
3370 							static_cast<sswf::Style::cap_t>(static_cast<int>(w->cap_end)));
3371 			}
3372 			if(static_cast<sswf::Style::join_t>(static_cast<int>(w->join)) != sswf::Style::STYLE_LINE_JOIN_UNKNOWN) {
3373 				style.SetLineJoin(static_cast<sswf::Style::join_t>(static_cast<int>(w->join)), w->miter);
3374 			}
3375 			if(w->hscale != -1.0) {
3376 				if(w->vscale == -1.0) {
3377 					style.SetLineScale(w->hscale != 0.0, w->hscale != 0.0);
3378 				}
3379 				else {
3380 					style.SetLineScale(w->hscale != 0.0, w->vscale != 0.0);
3381 				}
3382 			}
3383 			if(w->pixel_hinting != -1.0) {
3384 				style.SetLinePixelHinting(w->pixel_hinting != 0.0);
3385 			}
3386 			if(w->no_close != -1.0) {
3387 				style.SetLineNoClose(w->no_close != 0.0);
3388 			}
3389 		}
3390 	}
3391 
3392 	shape->AddStyle(style);
3393 
3394 	return 0;
3395 }
3396 
3397 
3398 
save_shape_fill(SaveState & state,sswf::TagShape * shape,const struct data_list_t * list,sswf::TagShape::fill_t fill_select)3399 static int save_shape_fill(SaveState& state, sswf::TagShape *shape, const struct data_list_t *list, sswf::TagShape::fill_t fill_select)
3400 {
3401 	sswf::Color			color;
3402 	sswf::Matrix			matrix;
3403 	sswf::Style			style(state.f_header);
3404 	const sswf::TagBaseID *		obj;
3405 	const struct data_color_t	*c;
3406 	const struct data_matrix_t	*m;
3407 	const struct data_gradient_t	*g;
3408 	const struct data_common_t	*cd;
3409 	const struct data_list_t	*sub_list;
3410 	float				focal;
3411 	int				idx, max, sub_idx, sub_max, colidx, matidx, gradient, graidx, gramat;
3412 
3413 	if(list == 0) {
3414 		style.SetType(sswf::Style::STYLE_TYPE_NO_FILL);
3415 	}
3416 	else {
3417 		colidx = 0;
3418 		matidx = 0;
3419 		max = list->count;
3420 		for(idx = 0; idx < max; idx++) {
3421 			cd = dc_item(list, idx);
3422 			switch(cd->type) {
3423 			case NODE_TYPE_STRING:		/* the type */
3424 				if(strcmp(cd->name, "clipped") == 0) {
3425 					style.SetType(sswf::Style::STYLE_TYPE_BITMAP_CLIPPED);
3426 				}
3427 				else if(strcmp(cd->name, "tilled") == 0) {
3428 					style.SetType(sswf::Style::STYLE_TYPE_BITMAP_TILLED);
3429 				}
3430 				else if(strcmp(cd->name, "hard-edge clipped") == 0) {
3431 					style.SetType(sswf::Style::STYLE_TYPE_BITMAP_HARDEDGE_CLIPPED);
3432 				}
3433 				else if(strcmp(cd->name, "hard-edge tilled") == 0) {
3434 					style.SetType(sswf::Style::STYLE_TYPE_BITMAP_HARDEDGE_TILLED);
3435 				}
3436 				else if(strcmp(cd->name, "solid") == 0) {
3437 					style.SetType(sswf::Style::STYLE_TYPE_SOLID);
3438 				}
3439 				else if(strcmp(cd->name, "radial") == 0) {
3440 					style.SetType(sswf::Style::STYLE_TYPE_GRADIENT_RADIAL);
3441 				}
3442 				else if(strcmp(cd->name, "linear") == 0) {
3443 					style.SetType(sswf::Style::STYLE_TYPE_GRADIENT_LINEAR);
3444 				}
3445 				else if(strcmp(cd->name, "focal") == 0) {
3446 					style.SetType(sswf::Style::STYLE_TYPE_GRADIENT_FOCAL);
3447 				}
3448 				else if(strcmp(cd->name, "reset") == 0) {
3449 					style.SetType(sswf::Style::STYLE_TYPE_NO_FILL);
3450 				}
3451 				else {
3452 fprintf(stderr, "ERROR: invalid fill style type (%s).\n", cd->name);
3453 					errcnt++;
3454 				}
3455 				break;
3456 
3457 			case NODE_SUBTYPE_COLOR:
3458 				c = dc_color(cd);
3459 				color.Set(CLAMPED_BYTE_COLOR(c->red), CLAMPED_BYTE_COLOR(c->green),
3460 								CLAMPED_BYTE_COLOR(c->blue), CLAMPED_BYTE_COLOR(c->alpha));
3461 				style.SetColor(colidx, color);
3462 				colidx = 1;
3463 				break;
3464 
3465 			case NODE_SUBTYPE_GRADIENT:
3466 				if(cd->name_len != 0) {
3467 					if(strcasecmp(cd->name, "linear") == 0) {
3468 						style.SetType(sswf::Style::STYLE_TYPE_GRADIENT_LINEAR);
3469 					}
3470 					else if(strcasecmp(cd->name, "radial") == 0) {
3471 						style.SetType(sswf::Style::STYLE_TYPE_GRADIENT_RADIAL);
3472 					}
3473 					else {
3474 fprintf(stderr, "ERROR: invalid gradient type (%s); expected linear or radial.\n", cd->name);
3475 						errcnt++;
3476 					}
3477 				}
3478 				sub_list = dc_list(cd);
3479 				sub_max = sub_list->count;
3480 				gradient = 0;
3481 				gramat = 0;
3482 				sub_idx = 0;
3483 				while(sub_idx < sub_max) {
3484 					cd = dc_item(sub_list, sub_idx);
3485 					if(sub_list->offset[sub_idx] < 0) {
3486 						g = (const struct data_gradient_t *) cd;
3487 						if(g->type == GRADIENT_TYPE_POSITION) {
3488 							sub_idx++;
3489 							assert(sub_idx < sub_max, "a gradient is always expected to be defined with a color");
3490 							cd = dc_item(sub_list, sub_idx);
3491 							c = dc_color(cd);
3492 							color.Set(CLAMPED_BYTE_COLOR(c->red), CLAMPED_BYTE_COLOR(c->green),
3493 											CLAMPED_BYTE_COLOR(c->blue), CLAMPED_BYTE_COLOR(c->alpha));
3494 							graidx = (int) rint(g->position * 255.0);
3495 							if(graidx > 255) {
3496 								graidx = 255;
3497 							}
3498 							else if(graidx < 0) {
3499 								graidx = 0;
3500 							}
3501 							style.SetGradient(gradient, graidx, color);
3502 							if(g->to_pos != -1E+128) {
3503 								sub_idx++;
3504 								assert(sub_idx < sub_max, "a morph gradient is always expected to be defined with two colors");
3505 								cd = dc_item(sub_list, sub_idx);
3506 								c = dc_color(cd);
3507 								color.Set(CLAMPED_BYTE_COLOR(c->red), CLAMPED_BYTE_COLOR(c->green),
3508 											CLAMPED_BYTE_COLOR(c->blue), CLAMPED_BYTE_COLOR(c->alpha));
3509 								graidx = (int) rint(g->to_pos * 255.0);
3510 								if(graidx > 255) {
3511 									graidx = 255;
3512 								}
3513 								else if(graidx < 0) {
3514 									graidx = 0;
3515 								}
3516 								style.SetGradient(gradient + sswf::Style::MAX_GRADIENTS, graidx, color);
3517 							}
3518 							if(gradient < sswf::Style::MAX_GRADIENTS - 1) {
3519 								gradient++;
3520 							}
3521 						}
3522 						else if(g->type == GRADIENT_TYPE_FOCAL) {
3523 							focal = g->position;
3524 							if(focal > 1.0f) {
3525 								focal = 1.0f;
3526 							}
3527 							else if(focal < -1.0f) {
3528 								focal = -1.0f;
3529 							}
3530 							style.SetGradientFocal(focal);
3531 						}
3532 					}
3533 					else if(cd->type == NODE_SUBTYPE_MATRIX) {
3534 						m = dc_matrix(cd);
3535 						save_set_matrix(matrix, m);
3536 						style.SetMatrix(gramat, matrix);
3537 						gramat = 1;
3538 					}
3539 					else {
3540 						assert(0, "unknown data type (%d) for a gradient", cd->type);
3541 						/*NOTREACHED*/
3542 					}
3543 					sub_idx++;
3544 				}
3545 				break;
3546 
3547 			case NODE_SUBTYPE_REFERENCE:
3548 				// TODO...
3549 				if(strcmp(cd->name, "clipping") == 0) {
3550 					/* this is a very special case where we want to have -1 for the ID */
3551 					style.SetClipping();
3552 				}
3553 				else {
3554 					obj = state.FindRef(cd->name, "image");
3555 					if(obj != 0) {
3556 						// valid reference to an image!
3557 						style.SetBitmap(obj->Identification());
3558 					}
3559 				}
3560 				break;
3561 
3562 			case NODE_SUBTYPE_MATRIX:
3563 				m = dc_matrix(cd);
3564 				save_set_matrix(matrix, m);
3565 				style.SetMatrix(matidx, matrix);
3566 				matidx = 1;
3567 				break;
3568 
3569 			default:
3570 				/* to avoid warnings */
3571 				assert(0, "unknown data type (%d) for a shape", cd->type);
3572 				/*NOTREACHED*/
3573 
3574 			}
3575 		}
3576 	}
3577 
3578 	shape->AddStyle(style, fill_select);
3579 
3580 	return 0;
3581 }
3582 
3583 
3584 
save_shape_edges(sswf::TagShape * shape,const struct data_list_t * list,long * x,long * y,long start_x,long start_y,sswf::TagShape::morph_t morph_mode)3585 static int save_shape_edges(sswf::TagShape *shape, const struct data_list_t *list, long *x, long *y, long start_x, long start_y, sswf::TagShape::morph_t morph_mode)
3586 {
3587 	const struct data_edges_t	*e;
3588 	int				idx, max;
3589 	long				x1, y1, x2, y2;
3590 	double				s, c;
3591 
3592 	/* angle == 0.0 by default */
3593 	s = 0.0;
3594 	c = 1.0;
3595 	max = list->count;
3596 	for(idx = 0; idx < max; idx++) {
3597 		assert(list->offset[idx] < 0, "only direct structures are expected in edges arrays");
3598 		e = dc_item_edges(list, idx);
3599 		if(e->type == EDGE_TYPE_ROTATE) {
3600 			s = sin(e->delta_x1);
3601 			c = cos(e->delta_x1);
3602 			continue;
3603 		}
3604 		x1 = (long) rint(PIXEL_TO_TWIPS(e->delta_x1 * c - e->delta_y1 * s));
3605 		y1 = (long) rint(PIXEL_TO_TWIPS(e->delta_y1 * c + e->delta_x1 * s));
3606 		if(e->delta_x2 == -1E+128 && e->delta_y2 == -1E+128) {
3607 			// in this case we have a line
3608 			if(e->type == EDGE_TYPE_CLOSE) {
3609 				shape->AddEdge(morph_mode, start_x - *x, start_y - *y);
3610 				*x = start_x;
3611 				*y = start_y;
3612 			}
3613 			else {
3614 				shape->AddEdge(morph_mode, x1, y1);
3615 				*x += x1;
3616 				*y += y1;
3617 			}
3618 		}
3619 		else {
3620 			x2 = (long) rint(PIXEL_TO_TWIPS(e->delta_x2 * c - e->delta_y2 * s));
3621 			y2 = (long) rint(PIXEL_TO_TWIPS(e->delta_y2 * c + e->delta_x2 * s));
3622 			if(e->type == EDGE_TYPE_CLOSE) {
3623 				shape->AddEdge(morph_mode, start_x - *x - x1, start_y - *y - y1, x1, y1);
3624 				*x = start_x;
3625 				*y = start_y;
3626 			}
3627 			else {
3628 				shape->AddEdge(morph_mode, x2, y2, x1, y1);
3629 				*x += x1 + x2;
3630 				*y += y1 + y2;
3631 			}
3632 		}
3633 	}
3634 
3635 	return 0;
3636 }
3637 
3638 
3639 
save_shape_points(sswf::TagShape * shape,const struct data_list_t * list,long * x,long * y,long start_x,long start_y,sswf::TagShape::morph_t morph_mode)3640 static int save_shape_points(sswf::TagShape *shape, const struct data_list_t *list, long *x, long *y, long start_x, long start_y, sswf::TagShape::morph_t morph_mode)
3641 {
3642 	const struct data_points_t	*e;
3643 	int				idx, max;
3644 	long				x1, y1, x2, y2;
3645 	double				s, c;
3646 
3647 	/* angle == 0.0 by default */
3648 	s = 0.0;
3649 	c = 1.0;
3650 	max = list->count;
3651 	for(idx = 0; idx < max; idx++) {
3652 		assert(list->offset[idx] < 0, "only direct structures are expected in points arrays");
3653 		e = dc_item_points(list, idx);
3654 		if(e->type == EDGE_TYPE_ROTATE) {
3655 			s = sin(e->x1);
3656 			c = cos(e->x1);
3657 			continue;
3658 		}
3659 		x1 = (long) rint(PIXEL_TO_TWIPS(e->x1 * c - e->y1 * s));
3660 		y1 = (long) rint(PIXEL_TO_TWIPS(e->y1 * c + e->x1 * s));
3661 		if(e->x2 == -1E+128 && e->y2 == -1E+128) {
3662 			// in this case we have a line
3663 			if(e->type == EDGE_TYPE_CLOSE) {
3664 				shape->AddEdge(morph_mode, start_x - *x, start_y - *y);
3665 				*x = start_x;
3666 				*y = start_y;
3667 			}
3668 			else {
3669 				shape->AddEdge(morph_mode, x1 - *x, y1 - *y);
3670 				*x = x1;
3671 				*y = y1;
3672 			}
3673 		}
3674 		else {
3675 			x2 = (long) rint(PIXEL_TO_TWIPS(e->x2 * c - e->y2 * s));
3676 			y2 = (long) rint(PIXEL_TO_TWIPS(e->y2 * c - e->x2 * s));
3677 			if(e->type == EDGE_TYPE_CLOSE) {
3678 				shape->AddEdge(morph_mode, start_x - x1, start_y - y1, x1 - *x, y1 - *y);
3679 				*x = start_x;
3680 				*y = start_y;
3681 			}
3682 			else {
3683 				shape->AddEdge(morph_mode, x2 - x1, y2 - y1, x1 - *x, y1 - *y);
3684 				*x = x2;
3685 				*y = y2;
3686 			}
3687 		}
3688 	}
3689 
3690 	return 0;
3691 }
3692 
3693 
3694 
3695 struct save_shape_info {
3696 	sswf::TagShape *	shape;
3697 	bool			sb;
3698 	bool			so;
3699 	int			rect_cnt;
3700 	sswf::TagShape::fill_t	fill_select;
3701 	sswf::TagShape::morph_t	morph_mode;
3702 	long			x;
3703 	long			y;
3704 	long			start_x;
3705 	long			start_y;
3706 };
3707 
3708 
3709 
save_shape_list(SaveState & state,save_shape_info & info,const struct data_list_t * list)3710 static int save_shape_list(SaveState& state, save_shape_info& info, const struct data_list_t *list)
3711 {
3712 	sswf::SRectangle		rect;
3713 	const struct data_common_t	*cd;
3714 	const struct data_list_t	*sub_list;
3715 	const struct data_rect_t	*r;
3716 	const struct data_move_t	*move;
3717 	int				idx, max;
3718 
3719 	max = list->count;
3720 	for(idx = 0; idx < max; idx++) {
3721 		cd = dc_item(list, idx);
3722 		if(list->offset[idx] < 0) {
3723 			// switch on the type which happens to be the fill selection
3724 			switch(((const struct data_fill_style_t *) cd)->select) {
3725 			case 0:
3726 				info.fill_select = sswf::TagShape::SHAPE_FILL_EVEN;
3727 				break;
3728 
3729 			case 1:
3730 				info.fill_select = sswf::TagShape::SHAPE_FILL_ODD;
3731 				break;
3732 
3733 			case 2:
3734 				info.sb = ((const struct data_shape_t *) cd)->show != 0.0;
3735 				break;
3736 
3737 			case 3:
3738 				move = (const struct data_move_t *) cd;
3739 				info.start_x = info.x = (long) rint(PIXEL_TO_TWIPS(move->tx));
3740 				info.start_y = info.y = (long) rint(PIXEL_TO_TWIPS(move->ty));
3741 				info.shape->AddMove(info.morph_mode, info.x, info.y);
3742 				break;
3743 
3744 			case 4:
3745 				info.so = ((const struct data_shape_t *) cd)->show != 0.0;
3746 				break;
3747 
3748 			case 5:
3749 				// mode is a double and cl cannot cast that to
3750 				// an emuneration type without an error...
3751 				// so we force an int cast in between
3752 				info.morph_mode = (sswf::TagShape::morph_t) (int) ((const struct data_morph_t *) cd)->mode;
3753 				break;
3754 
3755 			}
3756 		}
3757 		else {
3758 			/* all sub-data except the rectangle but that way sub_list points at the right place then */
3759 			if(cd->length - cd->name_len == sizeof(struct data_common_t)) {
3760 				sub_list = 0;		// empty list
3761 			}
3762 			else {
3763 				sub_list = dc_list(cd);
3764 			}
3765 			switch(cd->type) {
3766 			case NODE_SUBTYPE_RECT:
3767 				/* transform the data into a rectangle */
3768 				r = (const data_rect_t *) sub_list;
3769 				/* there should be at most 2 rectangles but we still ensure a good index
3770 				 * at all times for our own sake...
3771 				 */
3772 				rect.SetReorder(PIXEL_TO_TWIPS(r->min_x), PIXEL_TO_TWIPS(r->max_x),
3773 						PIXEL_TO_TWIPS(r->min_y), PIXEL_TO_TWIPS(r->max_y));
3774 				/* save it in the shape */
3775 				info.shape->SetBounds(info.rect_cnt, rect);
3776 				info.rect_cnt = 1;
3777 				break;
3778 
3779 			case NODE_SUBTYPE_FILL_STYLE:
3780 				save_shape_fill(state, info.shape, sub_list, info.fill_select);
3781 				info.fill_select = sswf::TagShape::SHAPE_FILL_EVEN;
3782 				break;
3783 
3784 			case NODE_SUBTYPE_LINE_STYLE:
3785 				save_shape_line(state, info.shape, sub_list);
3786 				break;
3787 
3788 			case NODE_SUBTYPE_EDGES:
3789 				save_shape_edges(info.shape, sub_list, &info.x, &info.y, info.start_x, info.start_y, info.morph_mode);
3790 				break;
3791 
3792 			case NODE_SUBTYPE_POINTS:
3793 				save_shape_points(info.shape, sub_list, &info.x, &info.y, info.start_x, info.start_y, info.morph_mode);
3794 				break;
3795 
3796 			case NODE_SUBTYPE_LIST:
3797 			case NODE_SUBTYPE_BLOCK:
3798 				save_shape_list(state, info, sub_list);
3799 				break;
3800 
3801 			default:
3802 				/* to avoid warnings */
3803 				assert(0, "unknown data type (%d) for a shape", cd->type);
3804 				/*NOTREACHED*/
3805 
3806 			}
3807 		}
3808 	}
3809 
3810 	return 0;
3811 }
3812 
3813 
save_shape(SaveState & state)3814 static int save_shape(SaveState& state)
3815 {
3816 	int				ec;
3817 	bool				is_glyph;
3818 	save_shape_info			info;
3819 	const struct data_common_t	*cd;
3820 
3821 	is_glyph = state.f_d->type == NODE_SUBTYPE_GLYPH;
3822 
3823 	if(!is_glyph) {		// not sure this is right, but I think it is...
3824 		cd = save_find_shape(state);
3825 		if(cd != 0) {
3826 			// ha! it already exists, don't insert it again
3827 			return 0;
3828 		}
3829 	}
3830 
3831 	info.shape = new sswf::TagShape(state.f_parent);
3832 	if(info.shape == 0) {
3833 		return -1;
3834 	}
3835 	state.RecordRef(info.shape);
3836 
3837 	if(is_glyph) {
3838 		info.shape->Glyph();
3839 	}
3840 
3841 	// save the data pointer so we can compare shapes quickly later
3842 	info.shape->f_userdata = const_cast<data_common_t *>(state.f_d);
3843 
3844 	info.sb = false;
3845 	info.so = false;
3846 	info.rect_cnt = 0;
3847 	info.fill_select = sswf::TagShape::SHAPE_FILL_EVEN;
3848 	info.morph_mode = sswf::TagShape::MORPH_MODE_SHAPE0;
3849 	info.start_x = info.x = 0;		// current position kept in x/y so we can use Edges or Points
3850 	info.start_y = info.y = 0;
3851 
3852 	ec = save_shape_list(state, info, dc_list(state.f_d));
3853 
3854 	/* now we know for sure whether the user wants to show the bounds and/or origin of this shape */
3855 	info.shape->ShowBounds(show_bounds || info.sb);
3856 	info.shape->ShowOrigin(show_origin || info.so);
3857 
3858 	return ec;
3859 }
3860 
3861 
save_show_frame(SaveState & state)3862 static int save_show_frame(SaveState& state)
3863 {
3864 	sswf::TagShowFrame		*sf;
3865 	const struct data_show_frame_t	*show_frame;
3866 	int				cnt;
3867 
3868 	show_frame = dc_show_frame(state.f_d);
3869 	cnt = (int) rint(show_frame->wait) - 1;
3870 
3871 	/*
3872 	 * The first one only is given a label so we do it outside the
3873 	 * loop - also in this way we make sure we have at least one
3874 	 * show frame inserted
3875 	 */
3876 	sf = new sswf::TagShowFrame(state.f_parent);
3877 	// this tag is not returned so we have to register it here
3878 	state.SetLabel(sf);
3879 
3880 	while(cnt > 0) {
3881 		cnt--;
3882 		sf = new sswf::TagShowFrame(state.f_parent);
3883 		// the following tags cannot have labels, only the 1st
3884 		// one can.
3885 	}
3886 
3887 	return 0;
3888 }
3889 
3890 
3891 
save_sound(SaveState & state)3892 static int save_sound(SaveState& state)
3893 {
3894 	sswf::TagSound			*sound;
3895 	int				idx, max;
3896 	const struct data_list_t	*list;
3897 	const struct data_common_t	*cd, *str;
3898 	const struct data_sound_t	*snd, *flags;
3899 
3900 	sound = new sswf::TagSound(state.f_parent);
3901 	if(sound == 0) {
3902 		return -1;
3903 	}
3904 	state.RecordRef(sound);
3905 
3906 	flags = 0;
3907 	list = dc_list(state.f_d);
3908 	max = list->count;
3909 	for(idx = 0; idx < max; idx++) {
3910 		cd = dc_item(list, idx);
3911 		if(list->offset[idx] < 0) {
3912 			// we simply define snd with this and use it
3913 			// once we get out of the loop; there should
3914 			// be only one anyway
3915 			snd = (struct data_sound_t *) cd;
3916 			switch(snd->type) {
3917 			case SOUND_TYPE_SETUP:
3918 				flags = snd;
3919 				break;
3920 
3921 			case SOUND_TYPE_FILENAME:
3922 				idx++;
3923 				assert(idx < max, "expected a string for the sound filename");
3924 				str = dc_item(list, idx);
3925 				assert(str->type == NODE_TYPE_STRING, "expected an object of type string as the sound filename");
3926 				if(str->name_len > 0) {
3927 					if(sound->SetFilename(str->name) != 0) {
3928 						// TODO: for these we need a better decimation of the actual error
3929 						// (i.e. whether the file exists, the format isn't supported, the compression
3930 						// isn't supported, the # of channels, etc.)
3931 fprintf(stderr, "ERROR: cannot read sound file \"%s\". Is this an uncompressed WAVE file or an MP3?\n", str->name);
3932 						errcnt++;
3933 						return -1;
3934 					}
3935 				}
3936 				break;
3937 
3938 			case SOUND_TYPE_FORMAT:
3939 				idx++;
3940 				assert(idx < max, "expected a string for the sound type");
3941 				str = dc_item(list, idx);
3942 				assert(str->type == NODE_TYPE_STRING, "expected an object of type string as the sound type");
3943 				if(str->name_len > 0) {
3944 					if(strcasecmp(str->name, "RAW") == 0) {
3945 						sound->SetFormat(sswf::TagSound::SOUND_FORMAT_RAW);
3946 						break;
3947 					}
3948 					else if(strcasecmp(str->name, "UNCOMPRESSED") == 0) {
3949 						sound->SetFormat(sswf::TagSound::SOUND_FORMAT_UNCOMPRESSED);
3950 						break;
3951 					}
3952 					else if(strcasecmp(str->name, "MP3") == 0) {
3953 						sound->SetFormat(sswf::TagSound::SOUND_FORMAT_MP3);
3954 						break;
3955 					}
3956 				}
3957 				fprintf(stderr, "ERROR: unknown/unsupported Flash sound compression \"%s\".\n", str->name);
3958 				errcnt++;
3959 				break;
3960 
3961 			}
3962 
3963 		}
3964 		else {
3965 			assert(0, "unknown data type (%d) for a sound", cd->type);
3966 			/*NOTREACHED*/
3967 		}
3968 	}
3969 
3970 	if(flags != 0) {
3971 		if(flags->mono) {
3972 			sound->SetMono();
3973 		}
3974 		if(flags->set_8bits) {
3975 			sound->Set8Bits();
3976 		}
3977 	}
3978 
3979 	return 0;
3980 }
3981 
3982 
3983 
save_sound_info(SaveState & state)3984 static int save_sound_info(SaveState& state)
3985 {
3986 	const sswf::TagBaseID		*sound;
3987 	const sswf::TagSound		*sound_ptr;
3988 	sswf::TagStartSound		*start_sound;
3989 	sswf::SoundInfo			*sound_info;
3990 	int				idx, max;
3991 	const struct data_list_t	*list;
3992 	const struct data_common_t	*cd;
3993 	const struct data_sound_info_t	*sndinf;
3994 	size_t				samples;
3995 	long				start, end, swap;
3996 
3997 	sound = NULL;
3998 	sndinf = NULL;
3999 	list = dc_list(state.f_d);
4000 	max = list->count;
4001 	for(idx = 0; idx < max; idx++) {
4002 		cd = dc_item(list, idx);
4003 		if(list->offset[idx] < 0) {
4004 			sndinf = (const struct data_sound_info_t *) cd;
4005 		}
4006 		else {
4007 			switch(cd->type) {
4008 			case NODE_SUBTYPE_REFERENCE:
4009 				sound = state.FindRef(cd->name, 0);
4010 				if(sound != 0) {
4011 					if(strcmp(sound->Name(), "sound") != 0
4012 					&& strcmp(sound->Name(), "imported") != 0) {
4013 fprintf(stderr, "ERROR: in a SOUND INFO object, the reference to \"%s\" needs to be to an object of type: sound.\n", cd->name);
4014 						errcnt++;
4015 						return 1;
4016 					}
4017 				}
4018 				break;
4019 
4020 			default:
4021 				/* to avoid warnings */
4022 				assert(0, "unknown data type (%d) for a sound info", cd->type);
4023 				/*NOTREACHED*/
4024 
4025 			}
4026 		}
4027 	}
4028 
4029 	if(sound == NULL) {
4030 		fprintf(stderr, "ERROR: a SOUND INFO needs to have a reference to an existing sound.\n");
4031 		errcnt++;
4032 		return 1;
4033 	}
4034 
4035 	/* now that we have all the info, initialize the sound info object */
4036 	// TODO: this is a memory leak
4037 	sound_info = new sswf::SoundInfo(state.f_header);
4038 
4039 	sound_info->SetSoundID(sound->Identification());
4040 
4041 	sound_ptr = dynamic_cast<const sswf::TagSound *>(sound);
4042 	if(sound_ptr == 0) {
4043 		// 100 Mb should be a large enough limit for now...
4044 		samples = 100 * 1024 * 1024;
4045 	}
4046 	else {
4047 		samples = sound_ptr->GetSamplesCount();
4048 		if(samples <= 0) {
4049 			fprintf(stderr, "ERROR: a SOUND INFO is referencing a SOUND object without any audio samples.\n");
4050 			errcnt++;
4051 			return 1;
4052 		}
4053 	}
4054 
4055 	if(sndinf == NULL) {
4056 		sound_info->SetLoop(1);
4057 		start = 0;
4058 		end = 0;
4059 	}
4060 	else {
4061 		sound_info->StopSound(sndinf->stop != 0.0);
4062 		sound_info->NoMultiple(sndinf->no_multiple != 0.0);
4063 		sound_info->SetLoop(sndinf->loop == -1E+128 ? 1 : (unsigned short) sndinf->loop);
4064 		start = (long) sndinf->start;
4065 		end = (long) sndinf->end;
4066 		if(sndinf->end == -1E+128) {
4067 			end = 0;
4068 		}
4069 		if(end >= (long) samples) {
4070 			end = samples - 1;
4071 		}
4072 		else if(end < 0) {
4073 			end = 0;
4074 		}
4075 		if(start < 0) {
4076 			start = 0;
4077 		}
4078 		if(start > end) {
4079 			// we cannot play backward (we could create a 2nd DEFINE_SOUND...)
4080 			swap = start;
4081 			start = end;
4082 			end = swap;
4083 		}
4084 	}
4085 	sound_info->SetRange(start, end);
4086 
4087 	start_sound = new sswf::TagStartSound(state.f_parent);
4088 	if(start_sound == 0) {
4089 		return -1;
4090 	}
4091 	start_sound->SetInfo(sound_info);
4092 
4093 	return 0;
4094 }
4095 
4096 
4097 
save_sprite(SaveState & state)4098 static int save_sprite(SaveState& state)
4099 {
4100 	sswf::TagBase			*parent;
4101 	sswf::TagSprite			*sprite;
4102 	const struct data_common_t	*sprite_info;
4103 	const struct data_list_t	*list;
4104 	int				idx, max, ec;
4105 
4106 	// note: though a sprite (like many other tags) cannot be in another sprite
4107 	// this is a bit doggy...
4108 	sprite = new sswf::TagSprite(state.f_parent);
4109 	if(sprite == 0) {
4110 		return -1;
4111 	}
4112 	state.RecordRef(sprite);
4113 
4114 	sprite_info = state.f_d;
4115 	parent = state.f_parent;		// save the current parent
4116 	state.f_parent = sprite;		// and make us the new one
4117 
4118 	ec = 0;
4119 	list = dc_list(state.f_d);
4120 	max = list->count;
4121 	for(idx = 0; idx < max && ec == 0; idx++) {
4122 		state.f_d = dc_item(list, idx);
4123 		ec = save_child(state);
4124 	}
4125 	state.f_parent = parent;
4126 	state.f_d = sprite_info;
4127 
4128 	return ec;
4129 
4130 }
4131 
4132 
4133 
save_text_setup(SaveState & state,sswf::TagText * text,const struct data_list_t * list)4134 static int save_text_setup(SaveState& state, sswf::TagText *text, const struct data_list_t *list)
4135 {
4136 	const sswf::TagBaseID		*obj;
4137 	sswf::Color			color;
4138 	int				idx, max;
4139 	const struct data_common_t	*cd;
4140 	const struct data_color_t	*c;
4141 	const struct data_text_setup_t	*setup;
4142 
4143 	setup = 0;		// makes the reference crash if still undefined (should never happen)
4144 	max = list->count;
4145 	for(idx = 0; idx < max; idx++) {
4146 		cd = dc_item(list, idx);
4147 		if(list->offset[idx] < 0) {
4148 			setup = (const struct data_text_setup_t *) cd;
4149 			if(idx != 0 || setup->x != 0 || setup->y != 0) {
4150 				// we got offsets (otherwise we just got some setups)
4151 				text->AddOffsets(PIXEL_TO_TWIPS(setup->x), PIXEL_TO_TWIPS(setup->y));
4152 			}
4153 		}
4154 		else {
4155 			switch(cd->type) {
4156 			case NODE_SUBTYPE_COLOR:
4157 				c = dc_color(cd);
4158 				color.Set(CLAMPED_BYTE_COLOR(c->red), CLAMPED_BYTE_COLOR(c->green),
4159 								CLAMPED_BYTE_COLOR(c->blue), CLAMPED_BYTE_COLOR(c->alpha));
4160 				text->AddColor(color);
4161 				break;
4162 
4163 			case NODE_SUBTYPE_REFERENCE:
4164 				assert(setup != 0, "found font reference before font setup structure");
4165 				obj = state.FindRef(cd->name, "font");
4166 				if(obj != 0) {
4167 					text->AddFont(dynamic_cast<const sswf::TagFont *>(obj), PIXEL_TO_TWIPS(setup->height));
4168 				}
4169 				break;
4170 
4171 			default:
4172 				/* to avoid warnings */
4173 				assert(0, "unknown data type (%d) for a text setup", cd->type);
4174 				/*NOTREACHED*/
4175 
4176 			}
4177 		}
4178 	}
4179 
4180 	return 0;
4181 }
4182 
4183 
4184 
save_text(SaveState & state)4185 static int save_text(SaveState& state)
4186 {
4187 	sswf::TagText			*text;
4188 	sswf::SRectangle		rect;
4189 	sswf::Matrix			matrix;
4190 	const struct data_common_t	*cd, *str;
4191 	const struct data_list_t	*list;
4192 	const struct data_rect_t	*r;
4193 	const struct data_matrix_t	*mx;
4194 	const struct data_text_t	*txt;
4195 	int				idx, max, ec;
4196 
4197 	text = new sswf::TagText(state.f_parent);
4198 	if(text == 0) {
4199 		return -1;
4200 	}
4201 	state.RecordRef(text);
4202 
4203 	list = dc_list(state.f_d);
4204 	max = list->count;
4205 	for(idx = 0; idx < max; idx++) {
4206 		cd = dc_item(list, idx);
4207 		if(list->offset[idx] < 0) {
4208 			txt = reinterpret_cast<const struct data_text_t *>(cd);
4209 			switch(* (long *) cd) {		// switch on the type
4210 			case TEXT_TYPE_ADVANCE:
4211 				// this is a text entry with advance
4212 				idx++;
4213 				assert(idx < max, "expected a string following the advance information in this text");
4214 				str = dc_item(list, idx);
4215 				if(str->name_len > 0) {
4216 					if(txt->advance == -1E+128) {
4217 						text->AddText(str->name);
4218 					}
4219 					else {
4220 						text->AddText(str->name, PIXEL_TO_TWIPS(txt->advance));
4221 					}
4222 				}
4223 				break;
4224 
4225 			case TEXT_TYPE_INFO:
4226 				if(txt->thickness != -1E+128) {
4227 					text->SetThickness(txt->thickness);
4228 					text->SetSharpness(txt->sharpness);
4229 				}
4230 				if(txt->renderer != -1E+128) {
4231 					text->SetRenderer(static_cast<sswf::TagCSMTextSettings::csm_text_renderer_t>(static_cast<int>(txt->renderer)));
4232 				}
4233 				if(txt->grid_fit != -1E+128) {
4234 					text->SetGridFit(static_cast<sswf::TagCSMTextSettings::csm_text_gridfit_t>(static_cast<int>(txt->grid_fit)));
4235 				}
4236 				break;
4237 
4238 			default:
4239 				assert(0, "unknown font type (%ld)", * (long *) cd);
4240 				/*NOTREACHED*/
4241 
4242 			}
4243 		}
4244 		else {
4245 			/* all sub-data except the rectangle but that way cd points at the right place then */
4246 			switch(cd->type) {
4247 			case NODE_SUBTYPE_RECT:
4248 				/* transform the data into a rectangle */
4249 				r = dc_rect(cd);
4250 				rect.SetReorder(PIXEL_TO_TWIPS(r->min_x), PIXEL_TO_TWIPS(r->max_x),
4251 						PIXEL_TO_TWIPS(r->min_y), PIXEL_TO_TWIPS(r->max_y));
4252 				/* save it in the text */
4253 				text->SetBounds(rect);
4254 				break;
4255 
4256 			case NODE_SUBTYPE_MATRIX:
4257 				mx = dc_matrix(cd);
4258 				save_set_matrix(matrix, mx);
4259 				text->SetMatrix(matrix);
4260 				break;
4261 
4262 			case NODE_SUBTYPE_TEXT_SETUP:
4263 				ec = save_text_setup(state, text, dc_list(cd));
4264 				if(ec != 0) {
4265 					return ec;
4266 				}
4267 				break;
4268 
4269 			// NOTE: the NODE_TYPE_STRING is caught with the TEXT_TYPE_ADVANCE
4270 			default:
4271 				/* to avoid warnings */
4272 				assert(0, "unknown data type (%d) for a text", cd->type);
4273 				/*NOTREACHED*/
4274 
4275 			}
4276 		}
4277 	}
4278 
4279 	return 0;
4280 }
4281 
4282 
save_label(SaveState & state)4283 static int save_label(SaveState& state)
4284 {
4285 	const struct data_list_t	*list;
4286 	const struct data_common_t	*cd;
4287 
4288 	list = dc_list(state.f_d);
4289 	if(list->count > 0) {
4290 		cd = dc_item(list, 0);
4291 		assert(cd->type == NODE_TYPE_STRING, "a label can only accept a string");
4292 		if(cd->name_len > 0) {
4293 			state.f_last_label = cd->name;
4294 		}
4295 	}
4296 
4297 	return 0;
4298 }
4299 
4300 
save_list(SaveState & state)4301 static int save_list(SaveState& state)
4302 {
4303 	const struct data_list_t	*list;
4304 	const struct data_common_t	*save;
4305 	int				idx, ec;
4306 
4307 	// save all the children now that we have the proper header info
4308 	save = state.f_d;
4309 	list = dc_list(save);
4310 	ec = 0;
4311 	for(idx = 0; idx < (int) list->count && ec == 0; idx++) {
4312 		state.f_d = dc_item(list, idx);
4313 		ec = save_child(state);
4314 	}
4315 	state.f_d = save;
4316 
4317 	return ec;
4318 }
4319 
4320 
save_child(SaveState & state)4321 static int save_child(SaveState& state)
4322 {
4323 	static const struct tag_list_t	children[] = {
4324 		{
4325 			NODE_SUBTYPE_BLOCK,
4326 			save_list
4327 		},
4328 		{
4329 			NODE_SUBTYPE_BUTTON,
4330 			save_button
4331 		},
4332 		{
4333 			NODE_SUBTYPE_DO_ACTION,
4334 			save_do_action
4335 		},
4336 		{
4337 			NODE_SUBTYPE_EDIT_TEXT,
4338 			save_edit_text
4339 		},
4340 		{
4341 			NODE_SUBTYPE_END,
4342 			save_end
4343 		},
4344 		{
4345 			NODE_SUBTYPE_EXPORT,
4346 			save_export
4347 		},
4348 		{
4349 			NODE_SUBTYPE_FONT,
4350 			save_font
4351 		},
4352 		{
4353 			NODE_SUBTYPE_FRAME_LABEL,
4354 			save_frame_label
4355 		},
4356 		{
4357 			NODE_SUBTYPE_GLYPH,
4358 			save_shape
4359 		},
4360 		{
4361 			NODE_SUBTYPE_IMAGE,
4362 			save_image
4363 		},
4364 		{
4365 			NODE_SUBTYPE_IMPORT,
4366 			save_import
4367 		},
4368 		{
4369 			NODE_SUBTYPE_LABEL,
4370 			save_label
4371 		},
4372 		{
4373 			NODE_SUBTYPE_LIST,
4374 			save_list
4375 		},
4376 		{
4377 			NODE_SUBTYPE_METADATA,
4378 			save_metadata
4379 		},
4380 		{
4381 			NODE_SUBTYPE_PLACE_OBJECT,
4382 			save_place_object
4383 		},
4384 		{
4385 			NODE_SUBTYPE_REMOVE,
4386 			save_remove
4387 		},
4388 		{
4389 			NODE_SUBTYPE_REPLACE_OBJECT,
4390 			save_place_object
4391 		},
4392 		{
4393 			NODE_SUBTYPE_SCENE_FRAME_DATA,
4394 			save_scene_frame_data
4395 		},
4396 		{
4397 			NODE_SUBTYPE_SCRIPT_LIMITS,
4398 			save_script_limits
4399 		},
4400 		{
4401 			NODE_SUBTYPE_SET_BACKGROUND_COLOR,
4402 			save_set_background_color
4403 		},
4404 		{
4405 			NODE_SUBTYPE_SET_TAB_INDEX,
4406 			save_set_tab_index
4407 		},
4408 		{
4409 			NODE_SUBTYPE_SHAPE,
4410 			save_shape
4411 		},
4412 		{
4413 			NODE_SUBTYPE_SHOW_FRAME,
4414 			save_show_frame
4415 		},
4416 		{
4417 			NODE_SUBTYPE_SOUND,
4418 			save_sound
4419 		},
4420 		{
4421 			NODE_SUBTYPE_SOUND_INFO,
4422 			save_sound_info
4423 		},
4424 		{
4425 			NODE_SUBTYPE_SPRITE,
4426 			save_sprite
4427 		},
4428 		{
4429 			NODE_SUBTYPE_TEXT,
4430 			save_text
4431 		},
4432 
4433 		{		/* end the table */
4434 			NODE_SUBTYPE_UNKNOWN,
4435 			NULL
4436 		}
4437 	};
4438 	const struct tag_list_t		*c;
4439 
4440 	// search for this child
4441 	c = children;
4442 	do {
4443 		if(c->type == state.f_d->type) {
4444 			return (*c->func)(state);
4445 		}
4446 		c++;
4447 	} while(c->type != NODE_SUBTYPE_UNKNOWN);
4448 
4449 	return 0;
4450 }
4451 
4452 
save_data(const struct data_common_t * data,struct global_t * g)4453 int save_data(const struct data_common_t *data, struct global_t *g)
4454 {
4455 	SaveState			state;
4456 	const struct data_common_t	*d;
4457 	const struct data_list_t	*list;
4458 	int				idx, ec;
4459 	sswf::SRectangle		rect;
4460 	const struct data_rect_t	*frame_rect;
4461 	sswf::Data			result;
4462 	size_t				size;
4463 	void				*buffer;
4464 	FILE				*f;
4465 	const char			*name;
4466 
4467 	list = (const struct data_list_t *) ((char *) (data + 1) + data->name_len);
4468 
4469 	// search for the frame rectangle (the 1st rectangle)
4470 	rect.Set(-1000, 1000, -1000, 1000);	/* a default setup of 100 pixels in each direction */
4471 	for(idx = 0; idx < (int) list->count; idx++) {
4472 		// NOTE: (at least for now) the offsets cannot be negative in a sequence
4473 		d = dc_item(list, idx);
4474 		if(d->type == NODE_SUBTYPE_RECT) {
4475 			frame_rect = dc_rect(d);
4476 			rect.SetReorder(PIXEL_TO_TWIPS(frame_rect->min_x), PIXEL_TO_TWIPS(frame_rect->max_x),
4477 					PIXEL_TO_TWIPS(frame_rect->min_y), PIXEL_TO_TWIPS(frame_rect->max_y));
4478 			break;
4479 		}
4480 	}
4481 
4482 	state.f_header.SetOutputEncoding(g->f_output_encoding);
4483 	state.f_header.SetFrame(rect);
4484 	state.f_header.SetRate((float) g->f_frame_rate);
4485 	state.f_parent = &state.f_header;
4486 
4487 	if((g->f_flags & GLOBAL_FLAG_PROTECT) != 0) {
4488 		if(new sswf::TagProtect(state.f_parent) == 0) {
4489 			fprintf(stderr, "ERROR: cannot create the Protect tag.\n");
4490 			errcnt++;
4491 			return -1;
4492 		}
4493 	}
4494 	state.f_header.SetUseNetwork((g->f_flags & GLOBAL_FLAG_USE_NETWORK) != 0);
4495 	if((g->f_flags & GLOBAL_FLAG_COMPRESS) != 0) {
4496 		state.f_header.SetCompress();
4497 	}
4498 //printf("Version = %d (Max. %d)\n", g->f_version, g->f_maximum_version);
4499 	if(g->f_version > 0) {
4500 		state.f_header.SetVersion(g->f_version);
4501 	}
4502 	if(g->f_minimum_version > 0) {
4503 		state.f_header.SetMinimumVersion(g->f_minimum_version);
4504 	}
4505 	if(g->f_maximum_version > 0) {
4506 		state.f_header.SetMaximumVersion(g->f_maximum_version);
4507 	}
4508 
4509 #if 0
4510 {	// the following prevents the movie from being played back by macromedia...
4511 	sswf::TagInfo	*info;
4512 	char		*version;
4513 	int		v;
4514 
4515 	info = new sswf::TagInfo(state.f_parent);
4516 	if(info == 0) {
4517 		return -1;
4518 	}
4519 	// this is what I have in a movie...
4520 	//info->SetInfo("com.macromedia.generator.commands.MovieSetCommand width=\"100\" height=\"100\" rate=\"12\"");
4521 	// and here is what I wanted to do
4522 	// either way it doesn't work (a genereal error occurs)
4523 	info->SetInfo("com.SSWF.generator");
4524 	version = TO_STR(SSWF_VERSION);
4525 	v = strtol(version, &version, 10);
4526 	version++;
4527 	v = strtol(version, &version, 10) + v * 256;
4528 	version++;
4529 	v = strtol(version, NULL, 10) + v * 256;
4530 	info->SetVersion(v);	// in the other movie v == 8
4531 }
4532 #endif
4533 	{
4534 		sswf::TagProductInfo	*info;
4535 		const char		*version(TO_STR(SSWF_VERSION));
4536 		char			*min_string, *rel_string;
4537 		long			major, minor, release;
4538 #ifndef WIN32
4539 		struct tm		compile_date;
4540 #endif
4541 		time_t			compile_time;
4542 
4543 		info = new sswf::TagProductInfo(state.f_parent);
4544 		if(info == 0) {
4545 			return -1;
4546 		}
4547 		info->SetProduct(0xF055);
4548 		info->SetEdition(1);
4549 		major = strtol(version, &min_string, 10);
4550 		minor = strtol(min_string + 1, &rel_string, 10);
4551 		release = strtol(rel_string + 1, 0, 10);
4552 		info->SetVersion(major, minor);
4553 		info->SetBuild(((int64_t) major << 32) + (minor << 16) + release);
4554 
4555 #ifdef WIN32
4556 		/* under Win32, we currently cheat big time 8-) -- version 1.8.1 -- need a fix! */
4557 		compile_time = time(NULL);
4558 #else
4559 		/* the following works great under Linux */
4560 		strptime(__DATE__ " " __TIME__, "%b %d %Y %H:%M:%S", &compile_date);
4561 		compile_time = mktime(&compile_date);
4562 #endif
4563 		info->SetCompileDate(compile_time);	// needs to use __DATE__ & correct unit...
4564 	}
4565 
4566 	if(g->f_show_steps > 0) {
4567 		printf("+ Save each child in the TagHeader object\n");
4568 	}
4569 
4570 	// save all the children now that we have the proper header info
4571 	for(idx = 0; idx < (int) list->count; idx++) {
4572 		d = dc_item(list, idx);
4573 		if(d->type != NODE_SUBTYPE_RECT) {
4574 #if 0
4575 printf("Save child %p (%s)\n", d, d->name_len == 0 ? "<no name>" : d->name);
4576 #endif
4577 			if(d->name_len > 0) {
4578 				name = d->name;
4579 			}
4580 			else {
4581 				name = "<no name>";
4582 			}
4583 			if(g->f_show_steps > 1) {
4584 				printf("  + Saving child: \"%s\" (%p)\n", name, d);
4585 			}
4586 
4587 			state.f_d = d;
4588 			ec = save_child(state);
4589 			if(ec != 0) {
4590 				printf("ERROR: error #%d occured while saving the tag \"%s\".\n", ec, name);
4591 				errcnt++;
4592 				return ec;
4593 			}
4594 		}
4595 	}
4596 
4597 	if(g->f_show_steps > 0) {
4598 		printf("+ Save the TagHeader in \"%s\".\n", g->f_output_filename);
4599 	}
4600 
4601 	ec = state.f_header.Save(result);
4602 
4603 	// NOTE: even if there is an error, try to save what was generated so far; this
4604 	// enables for debugging of what could have generated a problem in the saving
4605 	// process!
4606 	result.Read(buffer, size);
4607 
4608 	f = fopen(g->f_output_filename, "wb");
4609 	if(f == 0) {
4610 		fprintf(stderr, "ERROR: cannot create file \"%s\". (errno: %d - %s)\n", g->f_output_filename, errno, strerror(errno));
4611 		errcnt++;
4612 		return -1;
4613 	}
4614 	fwrite(buffer, size, 1, f);
4615 	fclose(f);
4616 
4617 	if(ec != 0) {
4618 		fprintf(stderr, "ERROR: an error occured while saving the result (maybe a version problem?)\n");
4619 		errcnt++;
4620 	}
4621 
4622 	if(state.f_header.Version() < 8 && (g->f_flags & GLOBAL_FLAG_USE_NETWORK) == 0) {
4623 		fprintf(stderr, "WARNING: the \"use_network\" flag was set to false but the movie was saved in an SWF version V%d, which does not enforce that flag.\n",
4624 				(int) state.f_header.Version());
4625 	}
4626 
4627 	return ec;
4628 }
4629 
4630 
4631