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