OSDN Git Service

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