OSDN Git Service

https://osdn.net/projects/swfed/scm/git/swfed/commits/a38e463ddaf7c6b915bdd94ee064a51...
[swfed/swfed.git] / src / swf_object.c
1 /*
2   +----------------------------------------------------------------------+
3   | Author: yoya@awm.jp                                                  |
4   +----------------------------------------------------------------------+
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h> // memcmp, strchr
10 #include <zlib.h>
11 #include "bitstream.h"
12 #include "swf_define.h"
13 #include "swf_tag.h"
14 #include "swf_tag_action.h"
15 #include "swf_tag_jpeg.h"
16 #include "swf_tag_lossless.h"
17 #include "swf_tag_shape.h"
18 #include "swf_tag_button.h"
19 #include "swf_tag_place.h"
20 #include "swf_tag_sprite.h"
21 #include "swf_action.h"
22 #include "swf_object.h"
23 #include "bitmap_util.h"
24 #include "trans_table.h"
25
26 static int _swf_object_remove_tag(swf_object_t *swf, swf_tag_t *tag);
27 static int _swf_object_remove_tag_in_sprite(swf_tag_sprite_detail_t *sprite, swf_tag_t *tag);
28 static int _swf_object_replace_tag(swf_object_t *swf,
29                                    swf_tag_t *old_tag, swf_tag_t *new_tag);
30 static void _swf_object_tag_close(swf_tag_t *tag_head);
31
32 swf_object_t *
33 swf_object_open(void) {
34     swf_object_t *swf;
35 #ifdef MALLOC_DEBUG
36     malloc_debug_start(); /* DEBUG XXX */
37 #endif // MALLOC_DEBUG
38 #ifdef BITSTREAM_DEBUG /* bitstream debug */
39     bitstream_debug_start();
40 #endif // BITSTREAM_DEBUG
41
42     swf = (swf_object_t *) calloc(sizeof(*swf), 1);
43     swf->tag_head = NULL;
44     swf->tag_tail = NULL;
45     //
46     swf->shape_adjust_mode = 0;
47     swf->compress_level = Z_DEFAULT_COMPRESSION;
48     return swf;
49 }
50
51 static void
52 _swf_object_tag_close(swf_tag_t *tag_head) {
53     swf_tag_t *tag, *next_tag;
54     for (tag = tag_head ; tag ; tag = next_tag) {
55         next_tag = tag->next;
56         swf_tag_destroy(tag);
57     }
58     return ;
59 }
60
61 void
62 swf_object_close(swf_object_t *swf) {
63     if (swf) {
64         _swf_object_tag_close(swf->tag_head);
65         swf->tag_head = NULL;
66         swf->tag_tail= NULL;
67         free(swf);
68     }
69 #ifdef MALLOC_DEBUG
70     malloc_debug_end(); /* DEBUG XXX */
71 #endif // MALLOC_DEBUG
72 #ifdef BITSTREAM_DEBUG /* bitstream debug */
73     bitstream_debug_end();
74 #endif // BITSTREAM_DEBUG
75     return ;
76 }
77
78 int
79 swf_object_input(swf_object_t *swf, unsigned char *data,
80                  unsigned long data_len) {
81     int result;
82     bitstream_t *bs;
83     swf_tag_t *tag, *prev_tag;
84     // delete old tag if twice call
85     _swf_object_tag_close(swf->tag_head);
86     
87     bs = bitstream_open();
88     bitstream_input(bs, data, data_len);
89     result = swf_header_parse(bs, &swf->header);
90     if (result) {
91         bitstream_close(bs);
92         return result;
93     }
94     if (memcmp(swf->header.magic, "FWS", 3) == 0) {
95         ; // OK
96     } else if (memcmp(swf->header.magic, "CWS", 3) == 0) {
97         int result;
98         unsigned char *old_buff_ref, *new_buff;
99         unsigned long origsize;
100         old_buff_ref = bitstream_buffer(bs, SWF_HEADER_SIZE);
101         origsize = swf->header.file_length - SWF_HEADER_SIZE;
102         new_buff = malloc(origsize);
103         result = uncompress(new_buff, &origsize, old_buff_ref, bs->data_len - SWF_HEADER_SIZE);
104         if (result != Z_OK) {
105             if (result == Z_MEM_ERROR) {
106                 fprintf(stderr, "swf_object_input: uncompress Z_MEM_ERROR: can't malloc\n");
107             } else if (result == Z_BUF_ERROR) {
108                 fprintf(stderr, "swf_object_input: uncompress Z_BUF_ERROR: not enough buff size\n");
109             } else {
110                 fprintf(stderr, "swf_object_input: uncompress failed by unknown reason\n");
111             }
112             free(new_buff);
113             bitstream_close(bs);
114             return 1; // FAILURE
115         }
116         bitstream_putstring(bs, new_buff, origsize);
117         free(new_buff);
118         bitstream_setpos(bs, SWF_HEADER_SIZE, 0);
119     } else {
120         fprintf(stderr, "swf_object_input: unknown magic %s\n", swf->header.magic);
121         bitstream_close(bs);
122         return 1; // FAILURE
123     }
124     result = swf_header_movie_parse(bs, &swf->header_movie);
125     if (result) {
126         bitstream_close(bs);
127         return result;
128     }
129     swf->tag_head = NULL;
130     prev_tag = NULL;
131     while(1) {
132         long pos;
133         bitstream_align(bs);
134         pos = bitstream_getbytepos(bs);
135         if ((pos == -1) || ((long) swf->header.file_length <= pos)) {
136             break;
137         }
138         tag = swf_tag_create(bs);
139         if (tag == NULL) {
140             break; // finish (no end tag in _root)
141         }
142         if (prev_tag == NULL) {
143             swf->tag_head = tag;
144             tag->prev = tag->next = NULL;
145         } else {
146             prev_tag->next = tag;
147             tag->prev = prev_tag;
148             tag->next = NULL;
149         }
150         swf->tag_tail = tag;
151         if (tag->code == 0) { // END Tag
152             break; // SUCCESS
153         }
154         prev_tag = tag;
155     }
156     bitstream_close(bs);
157     return 0;
158 }
159
160 unsigned char *
161 swf_object_output(swf_object_t *swf, unsigned long *length) {
162     int result;
163     swf_tag_t *tag = NULL;
164     unsigned char *data = NULL;
165     bitstream_t *bs = NULL;
166     if (swf == NULL) {
167         fprintf(stderr, "swf_object_output: swf == NULL\n");
168         return NULL;
169     }
170     if (length == NULL) {
171         fprintf(stderr, "swf_object_output: length == NULL\n");
172         return NULL;
173     }
174     *length = 0;
175     bs = bitstream_open();
176     result = swf_header_build(bs, &swf->header);
177     if (result) {
178         bitstream_close(bs);
179         return NULL;
180     }
181     result = swf_header_movie_build(bs, &swf->header_movie);
182     if (result) {
183         bitstream_close(bs);
184         return NULL;
185     }
186     for (tag = swf->tag_head ; tag ; tag = tag->next) {
187         swf_tag_build(bs, tag, swf); 
188     }
189     swf->header.file_length = bitstream_getbytepos(bs);
190     bitstream_setpos(bs, SWF_MAGIC_SIZE, 0);
191     bitstream_putbytesLE(bs, swf->header.file_length,
192                          SWF_FILE_LENGTH_SIZE);
193     if (memcmp(swf->header.magic, "FWS", SWF_MAGIC_SIZE) == 0) {
194         ; // OK
195     } else if (memcmp(swf->header.magic, "CWS", SWF_MAGIC_SIZE) == 0) {
196         int result;
197         unsigned long compsize, old_size;
198         unsigned char *new_buff, *old_buff_ref;
199         bitstream_setpos(bs, SWF_HEADER_SIZE, 0);
200         old_buff_ref = bitstream_buffer(bs, SWF_HEADER_SIZE);
201         old_size = bs->data_len - SWF_HEADER_SIZE;
202         compsize = old_size * 1.001 + 12; // increasing, rarely situation
203         new_buff = malloc(compsize);
204         result = compress2(new_buff, &compsize, old_buff_ref, old_size, swf->compress_level);
205         if (result != Z_OK) {
206             if (result == Z_MEM_ERROR) {
207                 fprintf(stderr, "swf_object_output: compress Z_MEM_ERROR: can't malloc\n");
208             } else if (result == Z_BUF_ERROR) {
209                 fprintf(stderr, "swf_object_output: compress Z_BUF_ERROR: not enough buff size\n");
210             } else {
211                 fprintf(stderr, "swf_object_output: compress failed by unknown reason\n");
212             }
213             bitstream_close(bs);
214             return NULL; // FAILURE
215         }
216         bitstream_putstring(bs, new_buff, compsize);
217         free(new_buff);
218     } else {
219         fprintf(stderr, "swf_object_output: unknown magic %s\n", swf->header.magic);
220         bitstream_close(bs);
221         return NULL; // FAILURE
222     }
223     data = bitstream_steal(bs, length);
224     bitstream_close(bs);
225     return data;
226 }
227
228 void
229 swf_object_print(swf_object_t *swf) {
230     int i;
231     swf_tag_t *tag;
232     swf_header_print(&swf->header);
233     swf_header_movie_print(&swf->header_movie);
234     
235     i = 0;
236     for (tag = swf->tag_head; tag ; tag = tag->next) {
237         printf("[%d] ", i);
238         swf_tag_print(tag, swf, 0);
239         if (tag->code == 0) { // END Tag
240             break;
241         }
242         i++;
243     }
244 }
245
246 /* --- */
247
248 int
249 swf_object_rebuild(swf_object_t *swf) {
250     swf_tag_t *tag;
251     int ret;
252     for (tag = swf->tag_head; tag ; tag = tag->next) {
253         ret = swf_tag_rebuild(tag, swf);
254         if (ret) {
255             return ret;
256         }
257     }
258     return 0;
259 }
260
261 void
262 swf_object_purge_contents(swf_object_t *swf) {
263     swf_tag_t *tag;
264     trans_table_t *refcid_trans_table;
265     if (swf == NULL) {
266         fprintf(stderr, "swf_object_purge_contents: swf == NULL\n");
267         return ;
268     }
269     refcid_trans_table = trans_table_open();
270     if (refcid_trans_table == NULL) {
271         fprintf(stderr, "swf_object_purge_contents: trans_table_open failed\n");
272         return ;
273     }
274     // scan from tail
275     for (tag = swf->tag_tail; tag ; tag = tag->prev) {
276         int cid;
277         int refcid = swf_tag_get_refcid(tag);
278         if (refcid > 0) {
279             // register ref id in control tag
280             trans_table_set(refcid_trans_table, refcid, TRANS_TABLE_RESERVE_ID);
281             continue;
282         }
283         cid = swf_tag_get_cid(tag);
284         if (cid <= 0) {
285             continue;
286         }
287         // contents tag routine is here.
288         if (trans_table_get(refcid_trans_table, cid) == TRANS_TABLE_RESERVE_ID) {
289             // no purge
290             if (isShapeTag(tag->code)) {
291                 int *bitmap_id_list, bitmap_id_list_num;
292                 bitmap_id_list = swf_tag_shape_bitmap_get_refcid_list(tag, &bitmap_id_list_num);
293                 if (bitmap_id_list) {
294                     int i;
295                     for (i = 0 ; i < bitmap_id_list_num; i++) {
296                         trans_table_set(refcid_trans_table, bitmap_id_list[i], TRANS_TABLE_RESERVE_ID);
297                     }
298                     free(bitmap_id_list);
299                 }
300             } else if (isButtonTag(tag->code)) {
301                 int *character_id_list, character_id_list_num;
302                 character_id_list = swf_tag_button_character_get_refcid_list(tag, &character_id_list_num);
303                 if (character_id_list) {
304                     int i;
305                     for (i = 0 ; i < character_id_list_num; i++) {
306                         trans_table_set(refcid_trans_table, character_id_list[i], TRANS_TABLE_RESERVE_ID);
307                     }
308                     free(character_id_list);
309                 }
310             } else if (isSpriteTag(tag->code)) {
311                 swf_tag_t *t;
312                 swf_tag_sprite_detail_t *tag_sprite;
313                 tag_sprite = swf_tag_create_input_detail(tag, swf);
314                 if (tag_sprite == NULL) {
315                     fprintf(stderr, "swf_object_purge_contents: tag_sprite == NULL\n");
316                 } else {
317                     for (t = tag_sprite->tag ; t ; t = t->next) {
318                         if (isButtonTag(tag->code)) {
319                             int *character_id_list, character_id_list_num;
320                             character_id_list = swf_tag_button_character_get_refcid_list(tag, &character_id_list_num);
321                             if (character_id_list) {
322                                 int i;
323                                 for (i = 0 ; i < character_id_list_num; i++) {
324                                     trans_table_set(refcid_trans_table, character_id_list[i], TRANS_TABLE_RESERVE_ID);
325                                 }
326                                 free(character_id_list);
327                             }
328                         } else {
329                             int rid = swf_tag_get_refcid(t);
330                             if (rid > 0) {
331                                 trans_table_set(refcid_trans_table, rid, TRANS_TABLE_RESERVE_ID);
332                             }
333                         }
334                     }
335                 }
336             }
337         } else { // Purge!
338             if (isShapeTag(tag->code) || isBitmapTag(tag->code)) {
339                 // TODO:  tag == head ? tag == tail ? OK?
340                 swf_tag_t *next_tag = tag->next;
341                 tag->prev->next = tag->next;
342                 tag->next->prev = tag->prev;
343                 swf_tag_destroy(tag);
344                 tag = next_tag;
345             }
346         }
347     }
348     trans_table_close(refcid_trans_table);
349 }
350
351 /* --- */
352
353 unsigned char *
354 swf_object_get_tagdata(swf_object_t *swf, int tag_seqno,
355                        unsigned long *length) {
356     swf_tag_t *tag;
357     unsigned char *data = NULL;
358     tag = swf_object_search_tag_byseqno(swf, tag_seqno);
359     if (tag) {
360         bitstream_t *bs = bitstream_open();
361         swf_tag_build(bs, tag, swf);
362         data = bitstream_steal(bs, length);
363         bitstream_close(bs);
364     }
365     return data;
366 }
367
368 int
369 swf_object_replace_tagdata(swf_object_t *swf, int tag_seqno,
370                            unsigned char *data, unsigned long length) {
371     swf_tag_t *old_tag, *new_tag;
372     old_tag = swf_object_search_tag_byseqno(swf, tag_seqno);
373     if (old_tag) {
374         bitstream_t *bs = bitstream_open();
375         bitstream_input(bs, data,length);
376         new_tag = swf_tag_create(bs);
377         bitstream_close(bs);
378         if (new_tag) {
379             _swf_object_replace_tag(swf, old_tag, new_tag);
380             swf_tag_destroy(old_tag);
381             return 0;
382         }
383     }
384     return 1;
385 }
386
387 unsigned char *
388 swf_object_get_tagdata_bycid(swf_object_t *swf, int cid,
389                              unsigned long *length) {
390     swf_tag_t *tag;
391     unsigned char *data = NULL;
392     tag = swf_object_search_tag_bycid(swf, cid);
393     if (tag) {
394         bitstream_t *bs = bitstream_open();
395         swf_tag_build(bs, tag, swf);
396         data = bitstream_steal(bs, length);
397         bitstream_close(bs);
398     }
399     return data;
400 }
401
402 int
403 swf_object_replace_tagdata_bycid(swf_object_t *swf, int cid,
404                               unsigned char *data, unsigned long length) {
405     swf_tag_t *old_tag, *new_tag;
406     old_tag = swf_object_search_tag_bycid(swf, cid);
407     if (old_tag) {
408         bitstream_t *bs = bitstream_open();
409         bitstream_input(bs, data,length);
410         new_tag = swf_tag_create(bs);
411         bitstream_close(bs);
412         swf_tag_replace_cid(new_tag, cid); // keep cid in SWF
413         if (new_tag) {
414             // re-join to new tag
415             _swf_object_replace_tag(swf, old_tag, new_tag);
416             swf_tag_destroy(old_tag);
417             return 0;
418         }
419     }
420     return 1;
421 }
422
423 unsigned char *
424 swf_object_get_tagcontents_bycid(swf_object_t *swf, int cid,
425                                   unsigned long *length) {
426     swf_tag_t *tag;
427     tag = swf_object_search_tag_bycid(swf, cid);
428     if (tag) {
429         // rebuild detail to (raw)data if modified
430         if ((tag->data == NULL) && tag->detail) {
431             bitstream_t *bs;
432             bs = bitstream_open();
433             swf_tag_build(bs, tag, swf);
434             tag->data = bitstream_steal(bs, &(tag->length));
435             bitstream_close(bs);
436         }
437         if (tag->data) {
438             *length = tag->length - 2;
439             return tag->data + 2; // success
440         }
441     }
442     *length = 0;
443     return NULL; // failed
444 }
445
446 int
447 swf_object_replace_tagcontents_bycid(swf_object_t *swf, int cid,
448                                      unsigned char *data,
449                                      unsigned long length) {
450     swf_tag_t *tag;
451     tag = swf_object_search_tag_bycid(swf, cid);
452     if (tag) {
453         if (tag->detail) {
454             swf_tag_destroy_detail(tag);
455             tag->detail = NULL;
456         }
457         if (tag->data) {
458             free(tag->data);
459             tag->data = NULL;
460         }
461         tag->length = length + 2;
462         tag->data = malloc(length + 2);
463         PutUShortLE(tag->data, cid);
464         memcpy(tag->data + 2, data, length);
465         return 0; // success
466     }
467     return 1; // failure
468 }
469
470 int
471 swf_object_remove_tag(swf_object_t *swf, int tag_seqno,
472                       int tag_seqno_in_sprite) {
473     swf_tag_t *tag;
474     int ret = 1;
475
476     tag = swf_object_search_tag_byseqno(swf, tag_seqno);
477     if (tag) {
478         if (tag_seqno_in_sprite >= 0) {
479             if (isSpriteTag(tag->code)) {
480                 swf_tag_sprite_detail_t   *tag_sprite;
481                 swf_tag_t *tag_in_sprite;
482                 tag_sprite = swf_tag_create_input_detail(tag, swf);
483
484                 tag_in_sprite = swf_object_search_tag_in_sprite_byseqno(tag_sprite, tag_seqno_in_sprite);
485                 if (tag_in_sprite) {
486                     ret = _swf_object_remove_tag_in_sprite(tag_sprite, tag_in_sprite);
487                     if (ret == 0) {
488                         free(tag->data);
489                         tag->data = NULL;
490                     }
491                 } else {
492                     ;
493                 }
494             } else {
495                 fprintf(stderr, "swf_object_remove_tag: not SpriteTag seqno=%d\n", tag_seqno);
496             }
497         } else {
498             ret = _swf_object_remove_tag(swf, tag);
499         }
500     }
501     return ret;
502 }
503
504 int
505 swf_object_print_tagdata(swf_object_t *swf, unsigned char *data, 
506                          unsigned long length) {
507     bitstream_t *bs;
508     swf_tag_t *tag;
509     bs = bitstream_open();
510     bitstream_input(bs, data, length);
511     tag = swf_tag_create(bs);
512     bitstream_close(bs);
513     if (tag == NULL) {
514         fprintf(stderr, "swf_object_print_tagdata: swf_tag_create failed\n");
515         return 1;
516     }
517     swf_tag_print(tag, swf, 0);
518     swf_tag_destroy(tag);
519     return 0;
520 }
521
522
523
524 static int
525 _swf_object_remove_tag(swf_object_t *swf, swf_tag_t *tag) {
526     if (tag->prev) {
527         if (tag->next) { // prev:O next:O
528             tag->prev->next = tag->next;
529             tag->next->prev = tag->prev;
530         } else {         // prev:O next:X
531             tag->prev->next = NULL;
532             swf->tag_tail = tag->prev;
533         }
534     } else {
535         if (tag->next) { // prev:X next:O
536             tag->next->prev = NULL;
537             swf->tag_head = tag->next;
538         } else {         // prev:X next:X
539             swf->tag_head = NULL;
540             swf->tag_tail = NULL;
541         }
542     }
543     swf_tag_destroy(tag);
544     return 0;
545 }
546
547 static int
548 _swf_object_remove_tag_in_sprite(swf_tag_sprite_detail_t *sprite_tag, swf_tag_t *tag) {
549     if (tag->prev) {
550         if (tag->next) { // prev:O next:O
551             tag->prev->next = tag->next;
552             tag->next->prev = tag->prev;
553         } else {         // prev:O next:X
554             tag->prev->next = NULL;
555             // swf->tag_tail = tag->prev;
556         }
557     } else {
558         if (tag->next) { // prev:X next:O
559             sprite_tag->tag = tag->next;
560             tag->next->prev = NULL;
561             // swf->tag_heat = tag->next;
562         } else {         // prev:X next:X
563             sprite_tag->tag = NULL;
564             // swf->tag_head = NULL;
565             // swf->tag_tail = NULL;
566         }
567     }
568     swf_tag_destroy(tag);
569     return 0;
570 }
571
572 /* --- */
573
574 unsigned char *
575 swf_object_get_shapedata(swf_object_t *swf, int cid, unsigned long *length) {
576     swf_tag_t *tag;
577     unsigned char *data = NULL;
578
579     tag = swf_object_search_tag_bycid(swf, cid);
580     if (tag) {
581         bitstream_t *bs;
582         if (! isShapeTag(tag->code)) {
583             fprintf(stderr, "swf_object_get_shapedata: not isShapeTag(%d)\n", tag->code);
584             *length = 0;
585             return NULL;
586         }
587         bs = bitstream_open();
588         swf_tag_build(bs, tag, swf);
589         data = bitstream_steal(bs, length);
590         bitstream_close(bs);
591     }
592     if (data == NULL) {
593         *length = 0;
594     }
595     return data;
596 }
597
598 int
599 swf_object_replace_shapedata(swf_object_t *swf, int cid,
600                              unsigned char *data,
601                              unsigned long length) {
602     swf_tag_t *old_tag, *new_tag;
603     old_tag = swf_object_search_tag_bycid(swf, cid);
604     if (old_tag) {
605         bitstream_t *bs;
606         if (! isShapeTag(old_tag->code)) {
607             fprintf(stderr, "swf_object_replace_shapedata: ! isShapeTag(%d)", old_tag->code);
608             return 1; // failure
609         }
610         bs = bitstream_open();
611         bitstream_input(bs, data, length);
612         new_tag = swf_tag_create(bs);
613         bitstream_close(bs);
614         if ((new_tag == NULL) || (! isShapeTag(new_tag->code))) {
615             fprintf(stderr, "swf_object_replace_shapedata: fallback to read old shape data\n");
616             // fallback reading Shape v0.37 and before
617             if (new_tag) {
618                 swf_tag_destroy(new_tag);
619             }
620             new_tag = swf_tag_move(old_tag);
621             swf_tag_destroy_detail(new_tag);
622             new_tag->length = length + 2;
623             if (new_tag->data) {
624                 free(new_tag->data);
625             }
626             new_tag->data = malloc(length + 2);
627             PutUShortLE(new_tag->data, cid);
628             memcpy(new_tag->data + 2, data, length);
629         }
630         if (new_tag) {
631             if (swf_tag_create_input_detail(new_tag, swf)) {
632                 // save cid in SWF
633                 swf_tag_replace_cid(new_tag, cid);
634                 _swf_object_replace_tag(swf, old_tag, new_tag);
635                 swf_tag_destroy(old_tag);
636                 // information modified so remove raw data.
637                 free(new_tag->data);
638                 new_tag->data = NULL;
639                 return 0;
640             }
641         }
642     }
643     return 1;
644 }
645
646 /* --- */
647
648 swf_tag_t *
649 swf_object_search_tag_byseqno(swf_object_t *swf, int tag_seqno) {
650     int i;
651     swf_tag_t *tag;
652     if (swf == NULL) {
653         fprintf(stderr, "swf_object_search_tag_by_seqno: swf == NULL\n");
654         return NULL;
655     }
656     i=0;
657     for (tag = swf->tag_head ; tag ; tag = tag->next) {
658         if (i >= tag_seqno) {
659             break;
660         }
661         i++;
662     }
663     return tag;
664 }
665
666 swf_tag_t *
667 swf_object_search_tag_in_sprite_byseqno(swf_tag_sprite_detail_t *sprite, int tag_seqno) {
668     int i;
669     swf_tag_t *tag;
670     if (sprite == NULL) {
671         fprintf(stderr, "swf_object_search_tag_by_seqno: sprite == NULL\n");
672         return NULL;
673     }
674     i=0;
675     for (tag = sprite->tag ; tag ; tag = tag->next) {
676         if (i >= tag_seqno) {
677             break;
678         }
679         i++;
680     }
681     return tag;
682 }
683
684 swf_tag_t *
685 swf_object_search_tag_bycid(swf_object_t *swf, int cid) {
686     swf_tag_t *tag;
687     if (swf == NULL) {
688         fprintf(stderr, "swf_object_search_tag_bycid: swf == NULL\n");
689         return NULL;
690     }
691     for (tag = swf->tag_head ; tag ; tag = tag->next) {
692         if (swf_tag_get_cid(tag) == cid) {
693             break; // match
694         }
695     }
696     return tag;
697 }
698
699 swf_tag_t *
700 swf_object_search_bitmap_tag(swf_object_t *swf, int bitmap_id) {
701     swf_tag_t *tag;
702     if (swf == NULL) {
703         fprintf(stderr, "swf_object_search_bitmap_tag: swf == NULL\n");
704         return NULL;
705     }
706     for (tag = swf->tag_head ; tag ; tag = tag->next) {
707         register int tag_code = tag->code;
708         if (isBitmapTag(tag_code)) {
709             if (swf_tag_get_cid(tag) == bitmap_id) {
710                 return tag; // match
711             }
712         }
713     }
714     return NULL;
715 }
716
717 int
718 swf_object_search_cid_by_bitmap_condition(swf_object_t *swf,
719                                           int width, int height,
720                                           int red, int green, int blue) {
721     swf_tag_t *tag;
722     int cid;
723     if (swf == NULL) {
724         fprintf(stderr, "swf_object_search_cid_by_bitmap_condition: swf == NULL\n");
725         return -1; // NG
726     }
727     for (tag = swf->tag_head ; tag ; tag = tag->next) {
728         register int tag_code = tag->code;
729         if (isBitmapTag(tag_code)) {
730             cid = swf_tag_search_cid_by_bitmap_condition(tag, width, height,
731                                                    red, green, blue);
732             if (cid > 0) {
733                 return cid;
734             }
735         }
736     }
737     return -1; // Not Found
738 }
739
740 /* --- */
741
742 int
743 swf_object_set_shape_adjust_mode(swf_object_t *swf, unsigned mode) {
744     if (swf == NULL) {
745         return 1;
746     }
747     swf->shape_adjust_mode = mode;
748     return 0;
749 }
750
751 int
752 swf_object_adjust_shapebitmap(swf_object_t *swf, int bitmap_id,
753                               int old_width, int old_height,
754                               int new_width, int new_height) {
755     swf_tag_t *tag = NULL;
756     double width_scale = 0, height_scale = 0;
757     int *bitmap_id_list, bitmap_id_list_num;
758     if (swf->shape_adjust_mode & SWFED_SHAPE_BITMAP_MATRIX_RESCALE) {
759         width_scale  = (double) old_width  / new_width;
760         height_scale = (double) old_height / new_height;
761         for (tag = swf->tag_head ; tag ; tag=tag->next) {
762             register int tag_code = tag->code;
763             if (isShapeTag(tag_code)) {
764                 bitmap_id_list = swf_tag_shape_bitmap_get_refcid_list(tag, &bitmap_id_list_num);
765                 if (bitmap_id_list) {
766                     int i;
767                     for (i = 0 ; i < bitmap_id_list_num ; i++) { 
768                         if (bitmap_id_list[i] == bitmap_id) {
769                             swf_tag_shape_detail_t *swf_tag_shape = tag->detail;
770                             swf_tag_apply_shape_matrix_factor(tag, swf_tag_shape->shape_id,
771                                                               bitmap_id,
772                                                               width_scale, height_scale,
773                                                               0, 0, 0, swf);
774                             break;
775                         }
776                     }
777                     free(bitmap_id_list);
778                 }
779             }
780         }
781     }
782     
783     if (swf->shape_adjust_mode & SWFED_SHAPE_BITMAP_RECT_RESIZE) {
784         width_scale  = (double) new_width  / old_width;
785         height_scale = (double) new_height / old_height;
786         for (tag = swf->tag_head ; tag ; tag=tag->next) {
787             register int tag_code = tag->code;
788             if (isShapeTag(tag_code)) {
789                 bitmap_id_list = swf_tag_shape_bitmap_get_refcid_list(tag, &bitmap_id_list_num);
790                 if (bitmap_id_list) {
791                     int i;
792                     for (i = 0 ; i < bitmap_id_list_num ; i++) { 
793                         if (bitmap_id_list[i] == bitmap_id) {
794                             swf_tag_shape_detail_t *swf_tag_shape = tag->detail;
795                             swf_tag_apply_shape_rect_factor(tag, swf_tag_shape->shape_id,
796                                                             bitmap_id,
797                                                             width_scale, height_scale,
798                                                             0, 0, swf);
799                             break;
800                         }
801                     }
802                     free(bitmap_id_list);
803                 }
804             }
805         }
806     }
807     if (swf->shape_adjust_mode & SWFED_SHAPE_BITMAP_TYPE_TILLED) {
808         for (tag = swf->tag_head ; tag ; tag=tag->next) {
809             register int tag_code = tag->code;
810             if (isShapeTag(tag_code)) {
811                 bitmap_id_list = swf_tag_shape_bitmap_get_refcid_list(tag, &bitmap_id_list_num);
812                 if (bitmap_id_list) {
813                     int i;
814                     for (i = 0 ; i < bitmap_id_list_num ; i++) { 
815                         if (bitmap_id_list[i] == bitmap_id) {
816                             swf_tag_shape_detail_t *swf_tag_shape = tag->detail;
817                             swf_tag_apply_shape_type_tilled(tag, swf_tag_shape->shape_id, bitmap_id, swf);
818                         }
819                     }
820                     free(bitmap_id_list);
821                 }
822             }
823         }
824     }
825     return 0;
826 }
827
828 int
829 swf_object_get_bitmap_size(swf_object_t *swf, int bitmap_id,
830                            int *width, int *height) {
831     swf_tag_t *tag;
832     int ret;
833     tag = swf_object_search_bitmap_tag(swf, bitmap_id);
834     if (tag == NULL) {
835         return 1;
836     }
837     ret = swf_tag_get_bitmap_size(tag, width, height);
838     return ret;
839 }
840
841 /* --- */
842
843 unsigned char *
844 swf_object_get_jpegdata(swf_object_t *swf, unsigned long *length, int image_id) {
845     swf_tag_t *tag, *tag_jpegtables = NULL;
846     unsigned char *data = NULL;
847     *length = 0;
848     if (swf == NULL) {
849         fprintf(stderr, "swf_object_get_jpegdata: swf == NULL\n");
850         return NULL;
851     }
852     for (tag=swf->tag_head ; tag ; tag=tag->next) {
853         if (tag->code == 8) { // JPEGTables
854             tag_jpegtables = tag;
855             continue;
856         }
857         // ! DefineBitsJPEG(1),2,3
858         if ((tag->code != 6) && (tag->code != 21) && (tag->code != 35)) {
859             continue;
860         }
861         data = swf_tag_get_jpeg_data(tag, length, image_id, tag_jpegtables);
862         if (data) {
863             break;
864         }
865     }
866     return data;
867 }
868
869 unsigned char *
870 swf_object_get_alphadata(swf_object_t *swf, unsigned long *length, int image_id) {
871     swf_tag_t *tag;
872     unsigned char *data = NULL;
873     *length = 0;
874     if (swf == NULL) {
875         fprintf(stderr, "swf_object_get_alphadata: swf == NULL\n");
876         return NULL;
877     }
878     for (tag=swf->tag_head ; tag ; tag=tag->next) {
879         if (tag->code != 35) { // ! DefineBitsJPEG3
880             continue;
881         }
882         data = swf_tag_get_alpha_data(tag, length, image_id);
883         if (data) {
884             break;
885         }
886     }
887     return data;
888 }
889
890 int
891 swf_object_replace_jpegdata(swf_object_t *swf, int image_id,
892                             unsigned char *jpeg_data,
893                             unsigned long jpeg_data_len,
894                             unsigned char *alpha_data,
895                             unsigned long alpha_data_len,
896                             int without_converting) {
897     int result = 1;
898     swf_tag_t *tag;
899     int old_width, old_height, new_width, new_height;
900     if (swf == NULL) {
901         fprintf(stderr, "swf_object_replace_jpegdata: swf == NULL\n");
902         return 1;
903     }
904     tag = swf_object_search_bitmap_tag(swf, image_id);
905     if (tag == NULL) {
906         fprintf(stderr, "swf_object_replace_jpegdata: tag == NULL\n");
907         return 1;
908     }
909     if (swf->shape_adjust_mode) {
910         swf_tag_get_bitmap_size(tag, &old_width, &old_height);
911         bitmap_size(jpeg_data, jpeg_data_len, &new_width, &new_height);
912     }
913     result = swf_tag_replace_jpeg_data(tag, image_id,
914                                        jpeg_data, jpeg_data_len,
915                                        alpha_data, alpha_data_len,
916                                        without_converting);
917     if (result) {
918         fprintf(stderr, "swf_object_replace_jpegdata: swf_tag_replace_jpeg_data failed\n");
919         return result;
920     }
921     if (swf->shape_adjust_mode) {
922         swf_object_adjust_shapebitmap(swf, image_id,
923                                       old_width, old_height,
924                                       new_width, new_height);
925     }
926     return result;
927 }
928
929 #ifdef HAVE_PNG
930
931 unsigned char *
932 swf_object_get_pngdata(swf_object_t *swf, unsigned long *length, int image_id) {
933     swf_tag_t *tag;
934     unsigned char *data = NULL;
935     if (swf == NULL) {
936         fprintf(stderr, "swf_object_get_pngdata: swf == NULL\n");
937         return NULL;
938     }
939     if (length == NULL) {
940         fprintf(stderr, "swf_object_get_pngdata: length == NULL\n");
941         return NULL;
942     }
943     *length = 0;
944     for (tag=swf->tag_head ; tag ; tag=tag->next) {
945         // DefineBitsLossless(1),2
946         if ((tag->code != 20) && (tag->code != 36)) {
947             continue;
948         }
949         data = swf_tag_get_png_data(tag, length, image_id);
950         if (data) {
951             break;
952         }
953     }
954     return data;
955 }
956
957 int
958 swf_object_replace_pngdata(swf_object_t *swf, int image_id,
959                             unsigned char *png_data,
960                             unsigned long png_data_len, int rgb15) {
961     int result = 1;
962     swf_tag_t *tag;
963     int old_width, old_height, new_width, new_height;
964     if (swf == NULL) {
965         fprintf(stderr, "swf_object_replace_pngdata: swf == NULL\n");
966         return 1;
967     }
968     if (png_data == NULL) {
969         fprintf(stderr, "swf_object_replace_pngdata: png_data == NULL\n");
970         return 1;
971     }
972     tag = swf_object_search_bitmap_tag(swf, image_id);
973     if (tag == NULL) {
974         fprintf(stderr, "swf_object_replace_pngdata: tag == NULL\n");
975         return 1;
976     }
977     if (swf->shape_adjust_mode) {
978         swf_tag_get_bitmap_size(tag, &old_width, &old_height);
979         png_size(png_data, png_data_len, &new_width, &new_height);
980     }
981     result = swf_tag_replace_png_data(tag, image_id,
982                                       png_data, png_data_len, rgb15);
983     if (result) {
984         fprintf(stderr, "swf_object_replace_pngdata: swf_tag_replace_png_data failed\n");
985         return result;
986     }
987     if (swf->shape_adjust_mode) {
988         swf_object_adjust_shapebitmap(swf, image_id,
989                                       old_width, old_height,
990                                       new_width, new_height);
991     }
992     return result;
993 }
994
995 #endif /* HAVE_PNG */
996
997 #ifdef HAVE_GIF
998
999 int
1000 swf_object_replace_gifdata(swf_object_t *swf, int image_id,
1001                             unsigned char *gif_data,
1002                             unsigned long gif_data_len) {
1003     int result = 1;
1004     swf_tag_t *tag;
1005     int old_width, old_height, new_width, new_height;
1006     if (swf == NULL) {
1007         fprintf(stderr, "swf_object_replace_gifdata: swf == NULL\n");
1008         return 1;
1009     }
1010     if (gif_data == NULL) {
1011         fprintf(stderr, "swf_object_replace_gifdata: gif_data == NULL\n");
1012         return 1;
1013     }
1014     tag = swf_object_search_bitmap_tag(swf, image_id);
1015     if (tag == NULL) {
1016         fprintf(stderr, "swf_object_replace_gifdata: tag == NULL\n");
1017         return 1;
1018     }
1019     if (swf->shape_adjust_mode) {
1020         swf_tag_get_bitmap_size(tag, &old_width, &old_height);
1021         gif_size(gif_data, gif_data_len, &new_width, &new_height);
1022     }
1023     result = swf_tag_replace_gif_data(tag, image_id,
1024                                       gif_data, gif_data_len);
1025     if (result) {
1026         fprintf(stderr, "swf_object_replace_pngdata: swf_tag_replace_png_data failed\n");
1027         return result;
1028     }
1029     if (swf->shape_adjust_mode) {
1030         swf_object_adjust_shapebitmap(swf, image_id,
1031                                       old_width, old_height,
1032                                       new_width, new_height);
1033     }
1034     return result;
1035 }
1036
1037 #endif /* HAVE_GIF */
1038
1039 int
1040 swf_object_convert_bitmapdata_tojpegtag(swf_object_t *swf) {
1041     swf_tag_t *tag;
1042     if (swf == NULL) {
1043         fprintf(stderr, "swf_object_convert_bitmapdata_tojpegtag: swf == NULL\n");
1044         return 1;
1045     }
1046     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1047         swf_tag_convert_bitmap_data_tojpegtag(tag);
1048     }
1049     return 0;
1050 }
1051
1052 unsigned char *
1053 swf_object_get_sounddata(swf_object_t *swf, unsigned long *length, int sound_id) {
1054     swf_tag_t *tag;
1055     unsigned char *data = NULL;
1056     *length = 0;
1057     if (swf == NULL) {
1058         fprintf(stderr, "swf_object_get_sounddata: swf == NULL\n");
1059         return NULL;
1060     }
1061     if (length == NULL) {
1062         fprintf(stderr, "swf_object_get_sounddata: length == NULL\n");
1063         return NULL;
1064     }
1065     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1066         // DefineSound
1067         if (tag->code != 14) {
1068             continue;
1069         }
1070         data = swf_tag_get_sound_data(tag, length, sound_id);
1071         if (data) {
1072             break;
1073         }
1074     }
1075     return data;
1076 }
1077
1078 int
1079 swf_object_replace_melodata(swf_object_t *swf, int sound_id,
1080                             unsigned char *melo_data,
1081                             unsigned long melo_data_len) {
1082     int result = 1;
1083     swf_tag_t *tag;
1084     if (swf == NULL) {
1085         fprintf(stderr, "swf_object_replace_melodata: swf == NULL\n");
1086         return 1;
1087     }
1088     if (melo_data == NULL) {
1089         fprintf(stderr, "swf_object_replace_melodata: melo_data == NULL\n");
1090         return 1;
1091     }
1092     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1093         result = swf_tag_replace_melo_data(tag, sound_id,
1094                                            melo_data, melo_data_len);
1095         if (! result) {
1096             break;
1097         }
1098     }
1099     return result;
1100 }
1101
1102 char *
1103 swf_object_get_editstring(swf_object_t *swf,
1104                           char *variable_name, int variable_name_len,
1105                           int *error) {
1106     swf_tag_t *tag;
1107     char *data = NULL;
1108     if (swf == NULL) {
1109         fprintf(stderr, "swf_object_get_editstring: swf == NULL\n");
1110         return NULL;
1111     }
1112     if (variable_name == NULL) {
1113         fprintf(stderr, "swf_object_get_editstring: variable_name == NULL\n");
1114         return NULL;
1115     }
1116     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1117         data = swf_tag_get_edit_string(tag, variable_name,
1118                                        variable_name_len, error, swf);
1119         if (data || (*error == 0)) {
1120             break;
1121         }
1122     }
1123     return data;
1124 }
1125
1126 int
1127 swf_object_replace_editstring(swf_object_t *swf,
1128                               char *variable_name,
1129                               int variable_name_len,
1130                               char *initial_text,
1131                               int initial_text_len) {
1132     int result = 1;
1133     swf_tag_t *tag;
1134     if (swf == NULL) {
1135         fprintf(stderr, "swf_object_replace_editstring: swf == NULL\n");
1136         return 1;
1137     }
1138     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1139         result = swf_tag_replace_edit_string(tag, variable_name,
1140                                              variable_name_len,
1141                                              initial_text,
1142                                              initial_text_len,
1143                                              swf);
1144         if (! result) {
1145             break;
1146         }
1147     }
1148     return result;
1149 }
1150
1151 unsigned char *
1152 swf_object_get_actiondata(swf_object_t *swf, unsigned long *length, int tag_seqno) {
1153     swf_tag_t *tag;
1154     swf_tag_action_detail_t *swf_tag_action;
1155     bitstream_t *bs;
1156     unsigned char *data;
1157     int i = 0;
1158     if (swf == NULL) {
1159         fprintf(stderr, "swf_object_get_actiondata: swf == NULL\n");
1160         return NULL;
1161     }
1162     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1163         if (i == tag_seqno) {
1164             break;
1165         }
1166         i++;
1167     }
1168     if (tag == NULL) {
1169         return NULL;
1170     }
1171     if ((tag->code != 12) &&  (tag->code != 59)) { //  DoAction, DoInitAction
1172         return NULL;
1173     }
1174     swf_tag_action = (swf_tag_action_detail_t *) swf_tag_create_input_detail(tag, swf);
1175     if (swf_tag_action == NULL) {
1176         fprintf(stderr, "swf_object_get_actiondata: swf_tag_create_input_detail failed");
1177         return NULL;
1178     }
1179     bs = bitstream_open();
1180     swf_action_list_build(bs,swf_tag_action->action_list);
1181     data = bitstream_steal(bs, length);
1182     bitstream_close(bs);
1183     return data;
1184 }
1185
1186 int
1187 swf_object_insert_action_setvariables(swf_object_t *swf,
1188                                       y_keyvalue_t *kv) {
1189     swf_tag_t *tag, *prev = NULL;
1190     swf_tag_t *action_tag = NULL, *prev_tag = NULL;
1191     int ret, done = 0;
1192     if ((swf == NULL) || (swf->tag_head == NULL)) {
1193         fprintf(stderr, "swf_object_insert_action_setvariables: swf or swf->tag_head is NULL\n");
1194         return 1; // NG
1195     }
1196     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1197         switch (tag->code) {
1198         case 1: // ShowFrame
1199             if (prev_tag == NULL) {
1200                 // no candidate point before ShowFrame so prev It.
1201                 prev_tag = prev;
1202             }
1203             done = 1;
1204             break;
1205         case 12: // DoAction
1206             // DoAction found so merge ActionByteCode to it.
1207             action_tag = tag;
1208             done = 1;
1209             break;
1210         case 69: // FileAttributs
1211         case  9: // SetBackgroundColor
1212         case 24: // Protect
1213             // put image after there tags.
1214             prev_tag = tag;
1215             break;
1216         default:
1217             if (prev_tag == NULL) {
1218                 prev_tag = prev;
1219             }
1220             break;
1221         }
1222         if (done) {
1223             break;
1224         }
1225         prev = tag;
1226     }
1227     if (action_tag) { // apppend setvariable image to top of DoAction
1228         ret = swf_tag_put_action_setvariables(action_tag,
1229                                               kv,
1230                                               swf);
1231         if (ret) {
1232             fprintf(stderr, "swf_object_insert_action_setvariables: swf_tag_put_action_setvariables failed\n");
1233             return 1; // NG
1234         }
1235     } else { // insert new DoAction
1236         tag = swf_tag_create_action_setvariables(kv);
1237         if (tag == NULL) {
1238             fprintf(stderr, "swf_object_insert_action_setvariables: swf_tag_create_action_setvariables failed\n");
1239             return 1; // NG
1240         }
1241         if (prev_tag == NULL) { // to make sure. abnormal situation.
1242             tag->next = swf->tag_head;
1243             tag->next->prev = tag;
1244             swf->tag_head = tag;
1245             tag->prev = NULL;
1246         } else {
1247             tag->next = prev_tag->next;
1248             tag->next->prev = tag;
1249             prev_tag->next = tag;
1250             tag->prev = prev_tag;
1251         }
1252     }
1253     return 0; // SUCCESS
1254 }
1255
1256 int
1257 swf_object_replace_action_strings(swf_object_t *swf, y_keyvalue_t *kv) {
1258     swf_tag_t *tag;
1259     int ret = 0;
1260     int m;
1261     if (swf == NULL) {
1262         fprintf(stderr, "swf_object_replace_action_strings: swf == NULL\n");
1263         return 1; // NG
1264     }
1265     if (kv == NULL) {
1266         fprintf(stderr, "swf_object_replace_action_strings: kv == NULL\n");
1267         return 1; // NG
1268     }
1269     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1270         if (isActionTag(tag->code)) {
1271             ret = swf_tag_replace_action_strings(tag, kv, &m, swf);
1272             if (ret) {
1273                 fprintf(stderr, "swf_object_replace_action_strings: swf_tag_replace_action_string failed\n");
1274                 break;
1275             }
1276             if (m && tag->data) { // action tag modified
1277                 free(tag->data);
1278                 tag->data = NULL;
1279             }
1280         } else if (isSpriteTag(tag->code)) {
1281             swf_tag_sprite_detail_t *tag_sprite;
1282             tag_sprite = swf_tag_create_input_detail(tag, swf);
1283             if (tag_sprite == NULL) {
1284                 fprintf(stderr, "swf_object_replace_action_strings: tag_sprite == NULL\n");
1285             } else {
1286                 int modified = 0;
1287                 swf_tag_t *t;
1288                 for (t = tag_sprite->tag ; t ; t = t->next) {
1289                     if (isActionTag(t->code)) {
1290                         ret = swf_tag_replace_action_strings(t, kv, &m, swf);
1291                         if (ret) {
1292                             fprintf(stderr, "swf_object_replace_action_strings: replace_action_string failed\n");
1293                             break;
1294                         }
1295                         if (t->data) {
1296                             free(t->data);
1297                             t->data = NULL;
1298                         }
1299                         modified = 1; // action tag modified
1300                     }    
1301                 }
1302                 if (modified) { // sprite tag rebuild
1303                     if (tag->data) {
1304                         free(tag->data);
1305                         tag->data = NULL;
1306                     }
1307                 }
1308             }
1309         }
1310     }
1311     return ret;
1312 }
1313
1314 /*
1315  * replacce reference side CID value
1316  */
1317 static void
1318 trans_table_replace_refcid_recursive(swf_tag_t *tag, trans_table_t *cid_trans_table) {
1319     for ( ; tag ; tag=tag->next) {
1320         int tag_no = tag->code;
1321         if (isSpriteTag(tag_no)) {
1322             swf_tag_sprite_detail_t *tag_sprite;
1323             tag_sprite = swf_tag_create_input_detail(tag, NULL);
1324             if (tag_sprite == NULL) {
1325                 fprintf(stderr, "trans_table_replace_refcid_recursive: tag_sprite swf_tag_create_input_detail failed");
1326             }
1327             trans_table_replace_refcid_recursive(tag_sprite->tag, cid_trans_table);
1328         } else if (isPlaceTag(tag_no)) {
1329             int refcid = swf_tag_get_refcid(tag);
1330             if (refcid > 0) {
1331                 int to_refcid = trans_table_get(cid_trans_table, refcid);
1332                 if (refcid != to_refcid) {
1333                     swf_tag_replace_refcid(tag, to_refcid);
1334                 }
1335             }
1336         }
1337     }
1338 }
1339
1340 // return Sprite tag mapped target path
1341 static swf_tag_t *
1342 swf_object_saerch_sprite_by_target_path2(swf_tag_t *tag_head,
1343                                         unsigned char *target_path,
1344                                         int target_path_len,
1345                                         swf_object_t *swf) {
1346     swf_tag_t *tag, *sprite_tag = NULL;
1347     unsigned char *instance_name, *next_instance_name;
1348     int instance_name_len;
1349     int cid = 0;
1350     
1351     next_instance_name = (unsigned char *) strchr((char *) target_path, '/');
1352     if (next_instance_name != NULL) {
1353         next_instance_name[0] = '\0'; // null terminate
1354         next_instance_name++;
1355     }
1356     
1357     instance_name = target_path;
1358     instance_name_len = strlen((char *) instance_name);
1359     
1360     // search PlaceObject by instance_name and get ref CID
1361     for (tag = tag_head ; tag ; tag=tag->next) {
1362         cid = 0;
1363         if (tag->code == 26) { // PlaceObject2
1364             cid = swf_tag_place_get_cid_by_instance_name(tag, instance_name, instance_name_len, swf);
1365         }
1366         if (cid > 0) {
1367             break; // found
1368         }
1369     }
1370     if (cid <= 0) {
1371         fprintf(stderr,
1372                 "swf_object_saerch_sprite_by_target_path2: not found place target_path=%s (cid=%d)\n",
1373                 target_path, cid);
1374         return NULL; // not found instance name;
1375     }
1376     
1377     // search DefineSprite by CID
1378     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1379         if (isSpriteTag(tag->code)) {
1380             if (swf_tag_get_cid(tag) ==  cid) {
1381                 sprite_tag = tag;
1382                 break;
1383             }
1384         }
1385     }
1386     if (next_instance_name) { // nested sprite
1387         if (sprite_tag) {
1388             swf_tag_sprite_detail_t *tag_sprite;
1389             tag_sprite = swf_tag_create_input_detail(sprite_tag, swf);
1390             if (tag_sprite == NULL) {
1391                 fprintf(stderr, "swf_object_saerch_sprite_by_target_path2: tag_sprite swf_tag_create_input_detail failed\n");
1392             } else {
1393                 sprite_tag = swf_object_saerch_sprite_by_target_path(tag_sprite->tag, next_instance_name, target_path_len - instance_name_len - 1, swf);
1394             }
1395         }
1396     }
1397     return sprite_tag;
1398 }
1399 swf_tag_t *
1400 swf_object_saerch_sprite_by_target_path(swf_tag_t *tag_head,
1401                                         unsigned char *target_path,
1402                                         int target_path_len,
1403                                         swf_object_t *swf) {
1404     swf_tag_t *tag;
1405     unsigned char* target_path2 = (unsigned char*)malloc(target_path_len+1);
1406     memcpy(target_path2, target_path, target_path_len+1);
1407
1408     tag = swf_object_saerch_sprite_by_target_path2(tag_head,
1409                                              target_path2,
1410                                              target_path_len,
1411                                              swf);
1412     free(target_path2);
1413     return tag;
1414 }
1415
1416 int
1417 swf_object_replace_movieclip(swf_object_t *swf,
1418                              unsigned char *instance_name, int instance_name_len,
1419                              unsigned char *swf_data, int swf_data_len) {
1420     int cid = 0, sprite_cid = 0, ret = 0;
1421     swf_tag_t *tag = NULL;
1422     swf_tag_t *sprite_tag = NULL, *prev_sprite_tag = NULL;
1423     swf_tag_t *sprite_tag_tail = NULL; // last tag in sprite.
1424     swf_tag_sprite_detail_t *swf_tag_sprite = NULL;
1425     swf_object_t *swf4sprite = NULL;
1426     swf_tag_info_t *tag_info = NULL;
1427     swf_tag_detail_handler_t *detail_handler = NULL;
1428     trans_table_t *cid_trans_table = NULL;
1429     
1430     if (swf == NULL) {
1431         fprintf(stderr, "swf_object_replace_movieclip: swf == NULL\n");
1432         return 1;
1433     }
1434     
1435     // search symbol(SpriteTag) mapped instance_name(target path)
1436     sprite_tag = swf_object_saerch_sprite_by_target_path(tag=swf->tag_head,
1437                                                          instance_name,
1438                                                          instance_name_len,
1439                                                          swf);
1440     
1441     if (sprite_tag == NULL) {
1442         fprintf(stderr, "swf_object_replace_movieclip: sprite_tag == NULL\n");
1443         return 1; // not found instance name;
1444     }
1445     prev_sprite_tag = sprite_tag->prev;
1446     sprite_cid = swf_tag_get_cid(sprite_tag);
1447     
1448     // swf data that MC replace to
1449     swf4sprite = swf_object_open();
1450     ret = swf_object_input(swf4sprite, swf_data, swf_data_len);
1451     if (ret) {
1452         fprintf(stderr, "swf_object_replace_movieclip: swf_object_input (swf_data_len=%d) failed\n", swf_data_len);
1453         return ret;
1454     }
1455     
1456     // old CID
1457     cid_trans_table = trans_table_open();
1458     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1459         int cid;
1460         cid = swf_tag_get_cid(tag);
1461         if (cid > 0) {
1462             trans_table_set(cid_trans_table, cid, TRANS_TABLE_RESERVE_ID);
1463         }
1464     }
1465 //    trans_table_print(cid_trans_table);
1466     
1467     // clean up innner SpriteTag
1468     tag_info = get_swf_tag_info(sprite_tag->code);
1469     detail_handler = tag_info->detail_handler();
1470     free(sprite_tag->data);
1471     sprite_tag->data = NULL;
1472     sprite_tag->length = 0;
1473     if (sprite_tag->detail) {
1474         detail_handler->destroy(sprite_tag);
1475     }
1476     sprite_tag->detail = detail_handler->create();
1477     swf_tag_sprite = sprite_tag->detail;
1478     swf_tag_sprite->sprite_id = sprite_cid;
1479     
1480     // extract tag each that type in SWF
1481     for (tag = swf4sprite->tag_head ; tag ; tag = tag->next) {
1482         int tag_no = tag->code;
1483         switch (tag_no) {
1484             // tag skip
1485           default: // misc
1486           case 3: // FreeCharacter
1487           case 9: // SetBackgroundColor
1488             // 16 missing
1489           case 56: // Export
1490           case 69: // FileAttributes
1491           case 74: // CSMTextSettings
1492           case 8: // JPEGTables // XXX
1493               ;
1494             break;
1495             // Character Tag
1496           case 2: // DefineShape
1497           case 6: // DefineBitsJPEG
1498           case 7: // DefineButton
1499           case 10: // DefineFont
1500           case 11: // DefineText
1501           case 13: // DefineFontInfo
1502           case 14: // DefineSound
1503           case 17: // DefineButtonSound
1504           case 18: // SoundStreamHead"
1505           case 19: // SoundStreamBlock
1506           case 20: // DefineBitsLossless
1507           case 21: // DefineBitsJPEG2
1508           case 22: // DefineShape2
1509           case 32: // DefineShape3
1510           case 33: // DefineText2
1511           case 34: // DefineButton2
1512           case 35: // DefineBitsJPEG3
1513           case 36: // DefineBitsLossless2
1514           case 37: // DefineEditText
1515           case 39: // DefineSprite
1516           case 46: // DefineMorphShape
1517           case 48: // DefineFont2
1518           case 73: // DefineFontAlignZones
1519           case 75: // DefineFont3
1520           case 83: // DefineShape4
1521           case 84: // DefineMorphShape2
1522           case 88: // DefineFontName
1523             // change CID
1524             cid = swf_tag_get_cid(tag);
1525             if (cid > 0) {
1526                 int to_cid;
1527                 to_cid = trans_table_get(cid_trans_table, cid);
1528                 if (to_cid == TRANS_TABLE_RESERVE_ID) {
1529                     to_cid = trans_table_get_freeid(cid_trans_table);
1530                     trans_table_set(cid_trans_table, cid, to_cid);
1531                     trans_table_set(cid_trans_table, to_cid, TRANS_TABLE_RESERVE_ID);
1532                 } else if (to_cid == 0) {
1533                     trans_table_set(cid_trans_table, cid, cid);
1534                     to_cid = cid;
1535                 }
1536                 if (cid != to_cid) {
1537                     if (swf_tag_replace_cid(tag, to_cid)) {
1538                         fprintf(stderr, "swf_object_replace_movieclip: swf_tag_replace_cid %d => %d failed\n", cid, to_cid);
1539                         // no stop
1540                     }
1541                 }
1542             }
1543             if (isShapeTag(tag_no)) {
1544                 int *bitmap_id_list, bitmap_id_list_num;
1545                 bitmap_id_list = swf_tag_shape_bitmap_get_refcid_list(tag, &bitmap_id_list_num);
1546                 if (bitmap_id_list) {
1547                     int i;
1548                     for (i = 0 ; i < bitmap_id_list_num; i++) {
1549                         int bitmap_id = bitmap_id_list[i];
1550                         int to_bitmap_id = trans_table_get(cid_trans_table, bitmap_id);
1551                         if ((to_bitmap_id > 0) && (bitmap_id != to_bitmap_id)) {
1552                             swf_tag_shape_bitmap_replace_refcid_list(tag, bitmap_id, to_bitmap_id);
1553                         }
1554                     }
1555                     free(bitmap_id_list);
1556                 }
1557             } else if (isSpriteTag(tag_no)){
1558                 swf_tag_sprite_detail_t *s;
1559                 s = swf_tag_create_input_detail(tag, swf);
1560                 if (s == NULL) {
1561                     fprintf(stderr, "swf_object_replace_movieclip: s swf_tag_create_input_detail failed\n");
1562                 }
1563                 trans_table_replace_refcid_recursive(s->tag, cid_trans_table);
1564                 free(tag->data);
1565                 tag->data = NULL;
1566             } else {
1567                 int refcid, to_refcid;                
1568                 refcid = swf_tag_get_refcid(tag);
1569                 if (refcid > 0) {
1570                     to_refcid = trans_table_get(cid_trans_table, refcid);
1571                     if (refcid != to_refcid) {
1572                         swf_tag_replace_refcid(tag, to_refcid);
1573                     }
1574                 }
1575             }
1576             // extract tag before SpriteTag
1577             prev_sprite_tag->next = swf_tag_move(tag);
1578             prev_sprite_tag->next->prev = prev_sprite_tag;
1579             prev_sprite_tag = prev_sprite_tag->next;
1580             prev_sprite_tag->next = sprite_tag;
1581             sprite_tag->prev = prev_sprite_tag;
1582             break;
1583             // Control Tag
1584           case 0: // End
1585           case 1: // ShowFrame
1586           case 4: // PlaceObject
1587           case 5: // RemoveObject
1588           case 12: // DoAction
1589           case 15: // StartSound
1590           case 26: // PlaceObject2
1591           case 28: // RemoveObject2
1592           case 43: // FrameLabel
1593           case 59: // DoInitAction
1594             // insert into Sprite
1595             // follow Character ID change
1596             switch (tag_no) {
1597                 int refcid, to_refcid;
1598               case 4:  // PlaceObject
1599               case 26: // PlaceObject2
1600                 refcid = swf_tag_get_refcid(tag);
1601                 if (refcid > 0) {
1602                     to_refcid = trans_table_get(cid_trans_table, refcid);
1603                     if (refcid != to_refcid) {
1604                         swf_tag_replace_refcid(tag, to_refcid);
1605                     }
1606                 }
1607                 break;
1608             }
1609             // inplant tag to Sprite
1610             if (sprite_tag_tail == NULL) {
1611                 swf_tag_sprite->tag = swf_tag_move(tag);
1612                 sprite_tag_tail = swf_tag_sprite->tag;
1613             } else {
1614                 sprite_tag_tail->next = swf_tag_move(tag);
1615                 sprite_tag_tail = sprite_tag_tail->next;
1616             }
1617             sprite_tag_tail->next = NULL;
1618             if (tag_no == 1) { // ShowFrame
1619                 swf_tag_sprite->frame_count  += 1;
1620             }
1621             break;
1622         }
1623     }
1624     trans_table_close(cid_trans_table);
1625     swf_object_close(swf4sprite);
1626     return 0;
1627 }
1628
1629 int
1630 swf_object_apply_shapematrix_factor(swf_object_t *swf, int shape_id,
1631                                     int bitmap_id,
1632                                     double scale_x, double scale_y,
1633                                     double rotate_rad,
1634                                     signed int trans_x, signed int trans_y) {
1635     int result = 1;
1636     swf_tag_t *tag;
1637     if (swf == NULL) {
1638         fprintf(stderr, "swf_object_apply_shapematrix_factor: swf == NULL\n");
1639         return 1;
1640     }
1641     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1642         result = swf_tag_apply_shape_matrix_factor(tag, shape_id,
1643                                                    bitmap_id,
1644                                                    scale_x, scale_y,
1645                                                    rotate_rad,
1646                                                    trans_x, trans_y,
1647                                                    swf);
1648         if (! result) {
1649             break;
1650         }
1651     }
1652     return result;
1653 }
1654
1655 int
1656 swf_object_apply_shaperect_factor(swf_object_t *swf, int shape_id,
1657                                   int bitmap_id, 
1658                                   double scale_x, double scale_y,
1659                                   signed int trans_x, signed int trans_y) {
1660     int result = 1;
1661     swf_tag_t *tag;
1662     if (swf == NULL) {
1663         fprintf(stderr, "swf_object_apply_shaperect_factor: swf == NULL\n");
1664         return 1;
1665     }
1666     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1667         result = swf_tag_apply_shape_rect_factor(tag, shape_id, bitmap_id,
1668                                                  scale_x, scale_y,
1669                                                  trans_x, trans_y,
1670                                                  swf);
1671         if (! result) {
1672             break;
1673         }
1674     }
1675     return result;
1676 }
1677
1678 int
1679 swf_object_apply_shapetype_tilled(swf_object_t *swf,int shape_id,
1680                                   int bitmap_id) {
1681     int result = 1;
1682     swf_tag_t *tag;
1683     if (swf == NULL) {
1684         fprintf(stderr, "swf_object_apply_shaperect_factor: swf == NULL\n");
1685         return 1;
1686     }
1687     for (tag=swf->tag_head ; tag ; tag=tag->next) {
1688         result = swf_tag_apply_shape_type_tilled(tag, shape_id, bitmap_id, swf);
1689         if (! result) {
1690             break;
1691         }
1692     }
1693     return result;
1694 }
1695
1696 int
1697 swf_object_is_shape_tagdata(unsigned char *data, int data_len) {
1698     bitstream_t *bs;
1699     swf_tag_t *tag;
1700     int ret = 0; // default FALSE;
1701     
1702     bs = bitstream_open();
1703     bitstream_input(bs, data, data_len);
1704     tag = swf_tag_create(bs);
1705     if (tag) {
1706         if (isShapeTag(tag->code)) {
1707             ret = 1; // TRUE
1708         }
1709     }
1710     bitstream_close(bs);
1711     return ret;
1712 }
1713
1714 int
1715 swf_object_is_bitmap_tagdata(unsigned char *data, int data_len) {
1716     bitstream_t *bs;
1717     swf_tag_t *tag;
1718     int ret = 0; // default FALSE;
1719     
1720     bs = bitstream_open();
1721     bitstream_input(bs, data, data_len);
1722     tag = swf_tag_create(bs);
1723     if (tag) {
1724         if (isBitmapTag(tag->code)) {
1725             ret = 1; // TRUE
1726         }
1727     }
1728     bitstream_close(bs);
1729     return ret;
1730 }
1731
1732 static int
1733 _swf_object_replace_tag(swf_object_t *swf, 
1734                         swf_tag_t *old_tag, swf_tag_t *new_tag) {
1735     old_tag->prev->next = new_tag;
1736     old_tag->next->prev = new_tag;
1737     new_tag->prev = old_tag->prev;
1738     new_tag->next = old_tag->next;
1739     if (new_tag->prev == NULL) {
1740         swf->tag_head = new_tag;
1741     }
1742     if (new_tag->next == NULL) {
1743         swf->tag_tail = new_tag;
1744     }
1745     old_tag->prev = NULL;
1746     old_tag->next = NULL;
1747     return 0;
1748 }