OSDN Git Service

add bitmap_id parameter into apply factor method.
[swfed/swfed.git] / src / swf_tag.c
1 /*
2   +----------------------------------------------------------------------+
3   | Author: yoya@awm.jp                                                  |
4   +----------------------------------------------------------------------+
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "bitstream.h"
10 #include "swf_define.h"
11 #include "swf_tag.h"
12 #include "swf_tag_jpeg.h"
13 #include "swf_tag_lossless.h"
14 #include "swf_tag_edit.h"
15 #include "swf_tag_action.h"
16 #include "swf_tag_sound.h"
17 #include "swf_tag_sprite.h"
18 #include "swf_tag_shape.h"
19 #include "swf_tag_place.h"
20 #include "swf_tag_button.h"
21 #include "bitmap_util.h"
22
23 swf_tag_info_t swf_tag_info_table[] = {
24     { 0, "End", NULL },
25     { 1, "ShowFrame", NULL },
26     { 2, "DefineShape", swf_tag_shape_detail_handler },
27     { 3, "FreeCharacter", NULL},
28     { 4, "PlaceObject", swf_tag_place_detail_handler },
29     { 5, "RemoveObject", NULL},
30     { 6, "DefineBitsJPEG", swf_tag_jpeg_detail_handler },
31     { 7, "DefineButton", swf_tag_button_detail_handler},
32     { 8, "JPEGTables", swf_tag_jpegt_detail_handler },
33     { 9, "SetBackgroundColor", NULL },
34     { 10, "DefineFont", NULL},
35     { 11, "DefineText", NULL },
36     { 12, "DoAction", swf_tag_action_detail_handler },
37     { 13, "DefineFontInfo", NULL },
38     { 14, "DefineSound", swf_tag_sound_detail_handler },
39     { 15, "StartSound", NULL },
40     // 16 missing
41     { 17, "DefineButtonSound", NULL },
42     { 18, "SoundStreamHead", NULL },
43     { 19, "SoundStreamBlock", NULL },
44     { 20, "DefineBitsLossless", swf_tag_lossless_detail_handler },
45     { 21, "DefineBitsJPEG2", swf_tag_jpeg_detail_handler },
46     { 22, "DefineShape2", swf_tag_shape_detail_handler },
47     { 24, "Protect", NULL },
48     { 26, "PlaceObject2", swf_tag_place_detail_handler },
49     { 28, "RemoveObject2", NULL },
50     { 32, "DefineShape3", swf_tag_shape_detail_handler },
51     { 33, "DefineText2", NULL },
52     { 34, "DefineButton2", swf_tag_button_detail_handler },
53     { 35, "DefineBitsJPEG3", swf_tag_jpeg3_detail_handler },
54     { 36, "DefineBitsLossless2", swf_tag_lossless_detail_handler },
55     { 37, "DefineEditText", swf_tag_edit_detail_handler },
56     { 39, "DefineSprite", swf_tag_sprite_detail_handler },
57     { 43, "FrameLabel", NULL } ,
58     { 46, "DefineMorphShape", swf_tag_shape_detail_handler },
59     { 48, "DefineFont2", NULL } ,
60     { 56, "Export", NULL } ,
61     { 59, "DoInitAction", swf_tag_action_detail_handler },
62     { 69, "FileAttributes", NULL },
63     { 73, "DefineFontAlignZones", NULL },
64     { 74, "CSMTextSettings", NULL },
65     { 75, "DefineFont3", NULL } ,
66     { 83, "DefineShape4",  swf_tag_shape_cid_handler },
67     { 84, "DefineMorphShape2", swf_tag_shape_cid_handler },
68     { 88, "DefineFontName", NULL } ,
69     { 777,"Reflex", NULL } ,
70 };
71
72 swf_tag_info_t *get_swf_tag_info(int tag_id) {
73     int i, tag_info_num = NumOfTable(swf_tag_info_table);
74     for (i=0 ; i < tag_info_num ; i++) {
75         if (tag_id == swf_tag_info_table[i].id) {
76             return &(swf_tag_info_table[i]);
77         }
78     }
79     return NULL;
80 }
81
82 swf_tag_t *swf_tag_create(bitstream_t *bs) {
83     swf_tag_t *tag = NULL;
84     unsigned short tag_and_length;
85     if (bs == NULL) {
86         fprintf(stderr, "swf_tag_create: bs == NULL\n");
87         return NULL;
88     }
89     tag_and_length = bitstream_getbytesLE(bs, 2);
90     if (tag_and_length == (unsigned short) -1) {
91         fprintf(stderr, "swf_tag_create: tag_and_length(short) == -1\n");
92         return NULL;
93     }
94     tag = calloc(sizeof(*tag), 1);
95     tag->code = tag_and_length >> 6;
96     tag->length = tag_and_length & 0x3f;
97     tag->length_longformat = 0;
98     if (tag->length == 0x3f) {
99         tag->length = bitstream_getbytesLE(bs, 4);
100         if (tag_and_length == (unsigned short) -1) {
101             fprintf(stderr, "swf_tag_create: tag_and_length(long) == -1\n");
102             free(tag);
103             return NULL;
104         }
105         tag->length_longformat = 1;
106     }
107 //    printf("XXX: malloc length=%d\n", tag->length);
108     tag->data = malloc(tag->length);
109     bitstream_getstring(bs, tag->data, tag->length);
110     tag->detail = NULL;
111     return tag;
112 }
113
114 void swf_tag_destroy(swf_tag_t *tag) {
115     if (tag == NULL) {
116         return;
117     }
118     if (tag->data) {
119         free(tag->data);
120         tag->data = NULL;
121     }
122     if (tag->detail) {
123         swf_tag_destroy_detail(tag);
124         tag->detail = NULL;
125     }
126     free(tag);
127 }
128
129 static int swf_tag_and_length_build(bitstream_t *bs, swf_tag_t *tag) {
130     signed short tag_and_length;
131     if (bs == NULL) {
132         fprintf(stderr, "swf_tag_and_length_build: bs == NULL\n");
133         return 1;
134     }
135     if (tag == NULL) {
136         fprintf(stderr, "swf_tag_and_length_build: tag == NULL\n");
137         return 1;
138     }
139     if (tag->length >= 0x3f) {
140         tag->length_longformat = 1;
141     } else {
142         switch (tag->code) {
143           case 6:  // DefineBitsJPEG
144           case 21: // DefineBitsJPEG2
145           case 35: // DefineBitsJPEG3
146           case 20: // DefineBitsLossless
147           case 36: // DefineBitsLossless2
148           case 19: // SoundStreamBlock
149             tag->length_longformat = 1;
150             break;
151           default:
152             tag->length_longformat = 0;
153             break;
154         }
155     }
156     if (tag->length_longformat) {
157         tag_and_length = (tag->code << 6) | 0x3f;
158         bitstream_putbytesLE(bs, tag_and_length, 2);
159         bitstream_putbytesLE(bs, tag->length, 4);
160     } else {
161         tag_and_length = (tag->code << 6) | tag->length;
162         bitstream_putbytesLE(bs, tag_and_length, 2);
163     }
164     return 0;
165 }
166
167 int swf_tag_build(bitstream_t *bs, swf_tag_t *tag, struct swf_object_ *swf) {
168     swf_tag_info_t *tag_info = NULL;
169     unsigned char *data = NULL;
170     unsigned long data_len = 0;
171     swf_tag_detail_handler_t *detail_handler = NULL;
172     if (bs == NULL) {
173         fprintf(stderr, "swf_tag_build: bs == NULL\n");
174         return 1;
175     }
176     if (tag == NULL) {
177         fprintf(stderr, "swf_tag_build: tag == NULL\n");
178         return 1;
179     }
180 //    fprintf(stderr, "XXX: swf_tag_build: tag->code=%d\n",tag->code);
181     if (tag->data) {
182         swf_tag_and_length_build(bs, tag);
183         bitstream_putstring(bs, tag->data, tag->length);
184     } else if (tag->detail) {
185         tag_info = get_swf_tag_info(tag->code);
186         if ((tag_info == NULL) || (tag_info->detail_handler == NULL)) {
187             fprintf(stderr, "swf_tag_build: not implemented yet. detail build tag->code=%d\n",
188                 tag->code);
189             return 1;
190         }
191         detail_handler = tag_info->detail_handler();
192         if (detail_handler->output == NULL) {
193             fprintf(stderr, "swf_tag_build: detail_handler->output == NULL: tag->code=%d\n",
194                     tag->code);
195             return 1;
196         }
197         data = detail_handler->output(tag, &data_len, swf);
198         if (data == NULL) {
199             fprintf(stderr, "swf_tag_build: Can't output: data=%p data_len=%lu\n",
200                     data, data_len);
201         }
202         tag->length = data_len;
203         swf_tag_and_length_build(bs, tag);
204         bitstream_putstring(bs, data, data_len);
205         free(data);
206     } else {
207         fprintf(stderr, "ERROR: not found tag data and detail\n");
208         return 1;
209     }
210     return 0;
211 }
212
213 int
214 swf_tag_rebuild(swf_tag_t *tag, struct swf_object_ *swf) {
215     swf_tag_info_t *tag_info = NULL;
216     swf_tag_detail_handler_t * detail_handler = NULL;
217     void *detail;
218     tag_info = get_swf_tag_info(tag->code);
219     if ((tag_info == NULL) || (tag_info->detail_handler == NULL)) {
220         return 0; // no info
221     }
222     detail_handler = tag_info->detail_handler();
223     if (detail_handler == NULL) {
224         return 0; // no detail handler
225     }
226     if ((detail_handler->input == NULL) || (detail_handler->output == NULL)) {
227         return 0; // no input or output handler
228     }
229     detail = swf_tag_create_input_detail(tag, swf);
230     if (detail == NULL) {
231         fprintf(stderr, "swf_tag_rebuild: swf_tag_create_input_detail failed tag->code=%d\n", tag->code);
232         return 1;
233     }
234     free(tag->data);
235     tag->data = NULL;
236     return 0;
237 }
238
239
240 void
241 swf_tag_print(swf_tag_t *tag, struct swf_object_ *swf, int indent_depth) {
242     swf_tag_info_t *tag_info = NULL;
243     const char *tag_name = NULL;
244     if (tag == NULL) {
245         fprintf(stderr, "swf_tag_print: tag == NULL\n");
246         return ;
247     }
248     tag_info = get_swf_tag_info(tag->code);
249     tag_name = (tag_info)?tag_info->name:"Unknown";
250 //  print_indent(indent_depth);
251     printf("tag=%s(%d)", tag_name, tag->code);
252     if (tag->length > 0) {
253         printf("  length=%lu",  tag->length);
254     }
255     printf("\n");
256     if (tag_info && tag_info->detail_handler) {
257         swf_tag_detail_handler_t * detail_handler;
258         if (swf_tag_create_input_detail(tag, swf) == NULL) {
259             fprintf(stderr, "swf_tag_print: swf_tag_create_input_detail failed\n");
260             return ;
261         }
262         detail_handler = tag_info->detail_handler();
263         if (detail_handler->print) {
264             detail_handler->print(tag, swf, indent_depth + 1);
265         }
266     }
267 }
268
269 void *swf_tag_create_input_detail(swf_tag_t *tag, struct swf_object_ *swf) {
270     swf_tag_info_t *tag_info = NULL;
271     if (tag == NULL) {
272         fprintf(stderr, "swf_tag_create_input_detail: tag == NULL\n");
273         return NULL;
274     }
275     if (tag->detail) {
276         return tag->detail;
277     }
278     tag_info = get_swf_tag_info(tag->code);
279     if (tag_info && tag_info->detail_handler) {
280         int result;
281         swf_tag_detail_handler_t * detail_handler = tag_info->detail_handler();
282         if (detail_handler->create == NULL) {
283             fprintf(stderr, "swf_tag_create_input_detail: detail_handler->create == NULL (tag=%d)\n",
284                     tag->code);
285             return NULL;
286         }
287         tag->detail = detail_handler->create();
288         if (tag->detail == NULL) {
289             fprintf(stderr, "swf_tag_create_input_detail: can't create tag detail (tag=%d)\n", tag->code);
290             return NULL;
291         }
292         result = detail_handler->input(tag, swf);
293         if (result) {
294             fprintf(stderr, "swf_tag_create_input_detail: can't input tag detail (result=%d)\n", result);
295             return NULL;
296         }
297     } else {
298         fprintf(stderr, "swf_tag_create_input_detail: tag_info or detail_handler  == NULL\n");
299     }
300     if (tag->detail == NULL) {
301         fprintf(stderr, "swf_tag_create_input_detail: function tail but tag->detail == NULL (tag->code=%d)\n", tag->code);
302     }
303     return tag->detail;
304 }
305
306 void swf_tag_destroy_detail(swf_tag_t *tag) {
307     if (tag == NULL) {
308         return;
309     }
310     if (tag->detail) {
311         swf_tag_info_t *tag_info = get_swf_tag_info(tag->code);
312         if (tag_info && tag_info->detail_handler) {
313             swf_tag_detail_handler_t * detail_handler = tag_info->detail_handler();
314             if (detail_handler->destroy) {
315                 detail_handler->destroy(tag);
316             } else {
317                 fprintf(stderr, "detail_handler->destroy == NULL (tag=%d)\n",
318                         tag->code);
319             }
320         } else {
321             fprintf(stderr, "not impremented yet. destroy tag detail\n");
322         }
323         tag->detail = NULL;
324     }
325 }
326
327
328 int
329 swf_tag_get_cid(swf_tag_t *tag) {
330     swf_tag_info_t *tag_info = NULL;
331     int tag_no;
332     if (tag == NULL) {
333         fprintf(stderr, "swf_tag_get_cid: tag == NULL\n");
334         return 1;
335     }
336     tag_no = tag->code;
337     if (tag->data) {
338         switch (tag_no) {
339           case 7:  // DefineButton
340           case 10: // DefineFont
341           case 11: // DefineText
342           case 13: // DefineFontInfo
343           case 14: // DefineSound
344           case 17: // DefineButtonSound
345           case 33: // DefineText2
346           case 34: // DefineButton2
347           case 39: // DefineSprite
348           case 46: // DefineMorphShape
349           case 48: // DefineFont2
350           case 88: // DefineFontName
351               return GetUShortLE(tag->data);
352               break;
353         }
354     }
355     tag_info = get_swf_tag_info(tag_no);
356     if (tag_info && tag_info->detail_handler) {
357         swf_tag_detail_handler_t * detail_handler = tag_info->detail_handler();
358         if (detail_handler->get_cid) {
359             return detail_handler->get_cid(tag);
360         }
361     }
362     return -1; // no cid tag
363 }
364
365 int
366 swf_tag_replace_cid(swf_tag_t *tag, int cid) {
367     swf_tag_info_t *tag_info;
368     int tag_no;
369     if (tag == NULL) {
370         fprintf(stderr, "swf_tag_replace_cid: tag == NULL\n");
371         return 1; // failure
372     }
373     tag_no = tag->code;
374     tag_info = get_swf_tag_info(tag_no);
375     if (tag_info && tag_info->detail_handler) {
376         swf_tag_detail_handler_t * detail_handler = tag_info->detail_handler();
377         if (detail_handler->replace_cid) {
378             return detail_handler->replace_cid(tag, cid);
379         }
380     } else {
381         switch (tag_no) {
382           case 7:  // DefineButton
383           case 10: // DefineFont
384           case 11: // DefineText
385           case 13: // DefineFontInfo
386           case 14: // DefineSound
387           case 17: // DefineButtonSound
388           case 33: // DefineText2
389           case 34: // DefineButton2
390           case 39: // DefineSprite
391           case 46: // DefineMorphShape
392           case 48: // DefineFont2
393           case 88: // DefineFontName
394             if (tag->data) {
395                 PutUShortLE(tag->data, cid);
396                 return 0;
397             }
398             break;
399           default:
400               ;
401         }
402     }
403     return 1; // no cid tag
404 }
405
406 int
407 swf_tag_get_refcid(swf_tag_t *tag) {
408     if (tag == NULL) {
409         fprintf(stderr, "swf_tag_get_refcid: tag == NULL\n");
410         return -1;
411     }
412     if (isPlaceTag(tag->code)) { // PlaceObject, PlaceObject2
413         swf_tag_place_detail_t *swf_tag_place;
414         swf_tag_place = swf_tag_create_input_detail(tag, NULL);
415         if (swf_tag_place == NULL) {
416             fprintf(stderr, "swf_tag_get_refcid: swf_tag_place swf_tag_create_input_detail failed\n");
417             return -1;
418         }
419         return swf_tag_place->character_id;
420     }
421     return -1; // no cid tag
422 }
423
424 int
425 swf_tag_replace_refcid(swf_tag_t *tag, int cid) {
426     if (tag == NULL) {
427         fprintf(stderr, "swf_tag_replace_refcid: tag == NULL\n");
428         return 1; // failure
429     }
430     if (isPlaceTag(tag->code)) { // PlaceObject, PlaceObject2
431         swf_tag_place_detail_t *swf_tag_place;
432         swf_tag_place = swf_tag_create_input_detail(tag, NULL);
433         if (swf_tag_place == NULL) {
434             fprintf(stderr, "swf_tag_replace_refcid: swf_tag_place swf_tag_create_input_detail failed\n");
435             return 1; // failure
436         }
437         swf_tag_place->character_id = cid;
438     }
439     if (tag->data) {
440         free(tag->data);
441         tag->data = NULL;
442     }
443     return 0; // success
444 }
445
446 /*
447  * bitmap tag
448  */
449
450 int
451 swf_tag_get_bitmap_size(swf_tag_t *tag,
452                         int *width, int *height) {
453     int ret = 0;
454     if (tag == NULL) {
455         fprintf(stderr, "swf_tag_get_bitmap_size: tag == NULL\n");
456         return 1;
457     }
458     if ((width == NULL ) || (height == NULL)) {
459         fprintf(stderr, "swf_tag_get_bitmap_size: width == NULL or height == NULL\n");
460         return 1;
461     }
462     if (isBitsJPEGTag(tag->code)) {
463         swf_tag_jpeg_detail_t *swf_tag_jpeg;
464         if (swf_tag_create_input_detail(tag, NULL) == NULL) {
465             fprintf(stderr, "swf_tag_get_bitmap_size: swf_tag_create_input_detail failed\n");
466             return 1;
467         }
468         swf_tag_jpeg = (swf_tag_jpeg_detail_t *) tag->detail;
469         ret = jpeg_size(swf_tag_jpeg->jpeg_data, swf_tag_jpeg->jpeg_data_len,
470                         width, height);
471     } else if (isBitsLosslessTag(tag->code)) {
472         if (tag->detail) {
473             swf_tag_lossless_detail_t *swf_tag_lossless = (swf_tag_lossless_detail_t *) tag->detail;
474             *width  = swf_tag_lossless->width;
475             *height = swf_tag_lossless->height;
476         } else {
477             *width  = GetUShortLE((tag->data + 3));
478             *height = GetUShortLE((tag->data + 5));
479         }
480     } else { // no Bitmap Tag
481         return 1;
482     }
483     return ret;
484 }
485
486 int
487 swf_tag_get_bitmap_color1stpixel(swf_tag_t *tag,
488                                  int *red, int *green, int *blue) {
489     swf_tag_lossless_detail_t *swf_tag_lossless = NULL;
490     if (tag == NULL) {
491         fprintf(stderr, "swf_tag_get_bitmap_color1stpixel: tag == NULL\n");
492         return 1;
493     }
494     if ((red == NULL ) || (green == NULL) || (blue == NULL)) {
495         fprintf(stderr, "swf_tag_get_bitmap_color1stpixel: width == NULL or height == NULL\n");
496         return 1;
497     }
498     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
499         fprintf(stderr, "swf_tag_get_bitmap_color1stpixel: swf_tag_create_input_detail failed\n");
500         return 1;
501     }
502     if (isBitsLosslessTag(tag->code) == 0) {
503         return 1; // No Lossless Tag;
504     }
505     swf_tag_lossless = (swf_tag_lossless_detail_t *) tag->detail;
506
507     // get first 1 pixel RGB value. by format and tag_code.
508     switch (swf_tag_lossless->format) {
509         int color_index;
510     case 3:
511         color_index = swf_tag_lossless->indices[0];
512         if (tag->code == 20) { // Lossless => RGB
513             *red   = swf_tag_lossless->colormap[color_index].red;
514             *green = swf_tag_lossless->colormap[color_index].green;
515             *blue  = swf_tag_lossless->colormap[color_index].blue;
516         } else { // Lossless2 => RGBA
517             int alpha = swf_tag_lossless->colormap2[color_index].alpha;
518             if (alpha == 0) {
519                 *red   = swf_tag_lossless->colormap2[color_index].red;
520                 *green = swf_tag_lossless->colormap2[color_index].green;
521                 *blue  = swf_tag_lossless->colormap2[color_index].blue;
522             }
523             else {
524                 *red   = swf_tag_lossless->colormap2[color_index].red * 255 / alpha;
525                 *green = swf_tag_lossless->colormap2[color_index].green * 255 / alpha;
526                 *blue  = swf_tag_lossless->colormap2[color_index].blue * 255 / alpha;
527             }
528         }
529         break;
530     case 5:
531         if (tag->code == 20) { // Lossless => RGB
532             *red   = swf_tag_lossless->bitmap[0].red;
533             *green = swf_tag_lossless->bitmap[0].green;
534             *blue  = swf_tag_lossless->bitmap[0].blue;
535         } else { // Lossless2 => ARGB
536             int alpha = swf_tag_lossless->bitmap2[0].alpha;
537             if (alpha == 0) {
538                 *red   = swf_tag_lossless->bitmap2[0].red;
539                 *green = swf_tag_lossless->bitmap2[0].green;
540                 *blue  = swf_tag_lossless->bitmap2[0].blue;
541             }
542             else {
543                 *red   = swf_tag_lossless->bitmap2[0].red * 255 / alpha;
544                 *green = swf_tag_lossless->bitmap2[0].green * 255 / alpha;
545                 *blue  = swf_tag_lossless->bitmap2[0].blue * 255 / alpha;
546             }
547         }
548         break;
549     default: // include 4 (15bit color)
550         fprintf(stderr, "swf_tag_get_bitmap_color1stpixel: unacceptable format=(%d)\n", swf_tag_lossless->format);
551         return 1;
552     }
553     return 0; // SUCCESS
554 }
555
556 unsigned char *
557 swf_tag_get_jpeg_data(swf_tag_t *tag, unsigned long *length, int image_id, swf_tag_t *tag_jpegtables) {
558     swf_tag_info_t *tag_info = NULL;
559     *length = 0;
560     if (tag == NULL) {
561         fprintf(stderr, "swf_tag_get_jpeg_data: tag == NULL\n");
562         return NULL;
563     }
564     if (length == NULL) {
565         fprintf(stderr, "swf_tag_get_jpeg_data: length == NULL\n");
566         return NULL;
567     }
568     tag_info = get_swf_tag_info(tag->code);
569     if ((tag->code != 6) && (tag->code != 21) && (tag->code != 35)) {
570         return NULL;
571     }
572     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
573         fprintf(stderr, "swf_tag_get_jpeg_data: swf_tag_create_input_detail failed\n");
574         return NULL;
575     }
576     if (tag_jpegtables) {
577         return swf_tag_jpeg_get_jpeg_data(tag->detail, length, image_id,
578                                           tag_jpegtables->data,
579                                           tag_jpegtables->length);
580     } else {
581         return swf_tag_jpeg_get_jpeg_data(tag->detail, length, image_id,
582                                           NULL, 0);
583     }
584 }
585
586 unsigned char *
587 swf_tag_get_alpha_data(swf_tag_t *tag, unsigned long *length, int image_id) {
588     *length = 0;
589     if (tag == NULL) {
590         fprintf(stderr, "swf_tag_get_alpha_data: tag == NULL\n");
591         return NULL;
592     }
593     if (length == NULL) {
594         fprintf(stderr, "swf_tag_get_alpha_data: length == NULL\n");
595         return NULL;
596     }
597     if (tag->code != 35) { // ! DefineBitsJPEG3
598         return NULL;
599     }
600     if (swf_tag_get_cid(tag) != image_id) {
601         return NULL;
602     }
603     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
604         fprintf(stderr, "swf_tag_get_alpha_data: swf_tag_create_input_detail failed\n");
605         return NULL;
606     }
607     return swf_tag_jpeg_get_alpha_data(tag->detail, length, image_id);
608 }
609
610 int
611 swf_tag_replace_jpeg_data(swf_tag_t *tag, int image_id,
612                           unsigned char *jpeg_data,
613                           unsigned long jpeg_data_len,
614                           unsigned char *alpha_data,
615                           unsigned long alpha_data_len,
616                           int without_converting) {
617     swf_tag_info_t *tag_info = NULL;
618     swf_tag_detail_handler_t * detail_handler = NULL;
619     int result;
620     if (tag == NULL) {
621         fprintf(stderr, "swf_tag_replace_jpeg_data: tag == NULL\n");
622         return 1;
623     }
624     if (jpeg_data == NULL) {
625         fprintf(stderr, "swf_tag_replace_jpeg_data: jpeg_data == NULL\n");
626         return 1;
627     }
628     if (! isBitmapTag(tag->code)) {
629         return 1;
630     }
631     tag_info = get_swf_tag_info(tag->code); // Bitmap Tag
632     detail_handler = tag_info->detail_handler();
633     if (detail_handler->get_cid(tag) !=  image_id) {
634         return 1;
635     }
636
637     if (tag->detail && (! isBitsJPEGTag(tag->code))) {
638         detail_handler->destroy(tag);
639         tag->detail = NULL;
640     }
641     if (alpha_data && (alpha_data_len > 0)) {
642         tag->code = 35; // DefineBitsJPEG3
643     } else {
644         tag->code = 21; // DefineBitsJPEG2
645     }
646     
647     tag_info = get_swf_tag_info(tag->code); // JPEG Tag
648     detail_handler = tag_info->detail_handler();
649     if (tag->detail == NULL) {
650         tag->detail = detail_handler->create();
651     }
652
653     if (without_converting) {
654         result= swf_tag_jpeg_replace_bitmap_data(tag->detail, image_id,
655                                                  jpeg_data, jpeg_data_len,
656                                                  tag);
657     } else {
658         result= swf_tag_jpeg_replace_jpeg_data(tag->detail, image_id,
659                                                jpeg_data, jpeg_data_len,
660                                                alpha_data, alpha_data_len, tag);
661     }
662     if (result == 0) {
663         free(tag->data);
664         tag->data = NULL;
665         tag->length = 0;
666     } else {
667         detail_handler->destroy(tag);
668         tag->detail = NULL;
669     } 
670     return result;
671 }
672
673
674 #ifdef HAVE_PNG
675
676 unsigned char *
677 swf_tag_get_png_data(swf_tag_t *tag, unsigned long *length, int image_id) {
678     swf_tag_info_t *tag_info = NULL;
679     *length = 0;
680     if (tag == NULL) {
681         fprintf(stderr, "swf_tag_get_png_data: tag == NULL\n");
682         return NULL;
683     }
684     if (length == NULL) {
685         fprintf(stderr, "swf_tag_get_png_data: length == NULL\n");
686         return NULL;
687     }
688     tag_info = get_swf_tag_info(tag->code);
689     if ((tag->code != 20) && (tag->code != 36)) {
690         return NULL;
691     }
692     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
693         fprintf(stderr, "swf_tag_get_png_data: swf_tag_create_input_detail failed\n");
694         return NULL;
695     }
696     return swf_tag_lossless_get_png_data(tag->detail, length, image_id, tag);
697 }
698
699 int
700 swf_tag_replace_png_data(swf_tag_t *tag, int image_id,
701                          unsigned char *png_data,
702                          unsigned long png_data_len, int rgb15) {
703     swf_tag_info_t *tag_info = NULL;
704     swf_tag_detail_handler_t *detail_handler = NULL;
705     int result;
706     if (tag == NULL) {
707         fprintf(stderr, "swf_tag_replace_png_data: tag == NULL\n");
708         return 1;
709     }
710     if (png_data == NULL) {
711         fprintf(stderr, "swf_tag_replace_png_data: png_data == NULL\n");
712         return 1;
713     }
714     if (! isBitmapTag(tag->code)) {
715         return 1;
716     }
717     tag_info = get_swf_tag_info(tag->code); // Bitmap Tag
718     detail_handler = tag_info->detail_handler();
719     if (detail_handler->get_cid(tag) != image_id) {
720         return 1;
721     }
722     
723     if (tag->detail && (! isBitsLosslessTag(tag->code))) {
724         detail_handler->destroy(tag);
725         tag->detail = NULL;
726     }
727     if (tag->code == 20) {
728         tag->code = 20; // DefineBitsLossless
729     } else {
730         tag->code = 36; // DefineBitsLossless2
731     }
732     
733     tag_info = get_swf_tag_info(tag->code); // Lossless Tag
734     detail_handler = tag_info->detail_handler();
735     if (tag->detail == NULL) {
736         tag->detail = detail_handler->create();
737     }
738     
739     result= swf_tag_lossless_replace_png_data(tag->detail, image_id,
740                                               png_data, png_data_len,
741                                               rgb15, tag);
742     if (result == 0) {
743         free(tag->data);
744         tag->data = NULL;
745         tag->length = 0;
746     } else {
747         detail_handler->destroy(tag);
748         tag->detail = NULL;
749     }
750     return result;
751 }
752
753 #endif /* HAVE_PNG */
754
755 #ifdef HAVE_GIF
756
757 int
758 swf_tag_replace_gif_data(swf_tag_t *tag, int image_id,
759                          unsigned char *gif_data,
760                          unsigned long gif_data_len) {
761     swf_tag_info_t *tag_info = NULL;
762     swf_tag_detail_handler_t *detail_handler = NULL;
763     int result;
764     if (tag == NULL) {
765         fprintf(stderr, "swf_tag_replace_gif_data: tag == NULL\n");
766         return 1;
767     }
768     if (gif_data == NULL) {
769         fprintf(stderr, "swf_tag_replace_gif_data: gif_data == NULL\n");
770         return 1;
771     }
772     if (! isBitmapTag(tag->code)) {
773         return 1;
774     }
775     tag_info = get_swf_tag_info(tag->code); // Bitmap Tag
776     detail_handler = tag_info->detail_handler();
777     if (detail_handler->get_cid(tag) != image_id) {
778         return 1;
779     }
780     
781     if (tag->detail && (! isBitsLosslessTag(tag->code))) {
782         detail_handler->destroy(tag);
783         tag->detail = NULL;
784     }
785     if (tag->code == 20) {
786         tag->code = 20; // DefineBitsLossless
787     } else {
788         tag->code = 36; // DefineBitsLossless2
789     }
790     
791     tag_info = get_swf_tag_info(tag->code); // Lossless Tag
792     detail_handler = tag_info->detail_handler();
793     if (tag->detail == NULL) {
794         tag->detail = detail_handler->create();
795     }
796     
797     result= swf_tag_lossless_replace_gif_data(tag->detail, image_id,
798                                               gif_data, gif_data_len, tag);
799     if (result == 0) {
800         free(tag->data);
801         tag->data = NULL;
802         tag->length = 0;
803     } else {
804         detail_handler->destroy(tag);
805         tag->detail = NULL;
806     }
807     return result;
808 }
809
810 #endif /* HAVE_GIF */
811
812 int
813 swf_tag_convert_bitmap_data_tojpegtag(swf_tag_t *tag) {
814     int tag_code;
815     int image_id;
816     unsigned char *bitmap_data;
817     unsigned long bitmap_data_len;
818     swf_tag_lossless_detail_t *swf_tag_lossless;
819     int ret;
820     if (tag == NULL) {
821         fprintf(stderr, "swf_object_convert_bitmap_data_tojpegtag: tag == NULL\n");
822         return 1;
823     }
824     tag_code = tag->code;
825     if ((tag_code != 20) && (tag_code != 36)) {
826         return 1;
827     }
828     if (tag->detail == NULL) {
829         swf_tag_lossless = (swf_tag_lossless_detail_t *) swf_tag_create_input_detail(tag, NULL);
830     } else {
831         swf_tag_lossless = (swf_tag_lossless_detail_t *) tag->detail;
832     }
833     image_id= swf_tag_lossless->image_id;
834     bitmap_data = swf_tag_lossless_get_png_data(swf_tag_lossless, &bitmap_data_len, image_id, tag);
835     if (bitmap_data == NULL) {
836         fprintf(stderr, "swf_object_convert_bitmap_data_tojpegtag: failed to swf_tag_get_png_data image_id=%d\n", image_id);
837         return 1;
838     }
839     ret = swf_tag_replace_jpeg_data(tag, image_id,
840                                     bitmap_data, bitmap_data_len, NULL, 0, 1);
841     free(bitmap_data);
842     if (ret) {
843         fprintf(stderr, "swf_object_convert_bitmap_data_tojpegtag: failed to swf_tag_replace_jpeg_data image_id=%d\n", image_id);
844         return ret;
845     }
846     return 0;
847 }
848
849 /*
850  * DefineSound
851  */
852
853 unsigned char *
854 swf_tag_get_sound_data(swf_tag_t *tag, unsigned long *length, int sound_id) {
855     swf_tag_info_t *tag_info = NULL;
856     *length = 0;
857     if (tag == NULL) {
858         fprintf(stderr, "swf_tag_get_sound_data: tag == NULL\n");
859         return NULL;
860     }
861     if (length == NULL) {
862         fprintf(stderr, "swf_tag_get_sound_data: length == NULL\n");
863         return NULL;
864     }
865     tag_info = get_swf_tag_info(tag->code);
866     if (tag->code != 14) { // DefineSound
867         return NULL;
868     }
869     if (! tag->detail) {
870         
871     }
872     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
873         fprintf(stderr, "swf_tag_get_sound_data: swf_tag_create_input_detail failed\n");
874         return NULL;
875     }
876     return swf_tag_sound_get_sound_data(tag->detail, length, sound_id);
877 }
878
879 int
880 swf_tag_replace_melo_data(swf_tag_t *tag, int sound_id,
881                           unsigned char *melo_data,
882                           unsigned long melo_data_len) {
883     int result;
884     if (tag == NULL) {
885         fprintf(stderr, "swf_tag_replace_melo_data: tag == NULL\n");
886         return 1;
887     }
888     if (melo_data == NULL) {
889         fprintf(stderr, "swf_tag_replace_melo_data: melo_data == NULL\n");
890         return 1;
891     }
892     if (tag->code != 14) { // DefineSound
893         return 1;
894     }
895     if (swf_tag_get_cid(tag) != sound_id) {
896         return 1;
897     }
898     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
899         fprintf(stderr, "swf_tag_replace_melog_data: swf_tag_create_input_detail failed\n");
900         return 1;
901     }
902     result= swf_tag_sound_replace_melo_data(tag->detail, sound_id,
903                                             melo_data, melo_data_len);
904     if (result == 0) {
905         free(tag->data);
906         tag->data = NULL;
907         tag->length = 0;
908     }
909     return result;
910 }
911
912 char *
913 swf_tag_get_edit_string(swf_tag_t *tag,
914                         char *variable_name, int variable_name_len,
915                         int *error, struct swf_object_ *swf) {
916     *error = 1;
917     if (tag == NULL) {
918         fprintf(stderr, "swf_tag_get_edit_string: tag == NULL\n");
919         return NULL;
920     }
921     if (variable_name == NULL) {
922         fprintf(stderr, "swf_tag_get_edit_string: variable_name == NULL\n");
923         return NULL;
924     }
925     if (tag->code != 37) { // DefineEditText
926         return NULL;
927     }
928     if (swf_tag_create_input_detail(tag, swf) == NULL) {
929         fprintf(stderr, "swf_tag_get_edit_string: swf_tag_create_input_detail failed\n");
930         return NULL;
931     }
932     return swf_tag_edit_get_string(tag->detail,
933                                    variable_name, variable_name_len, error);
934 }
935
936 int
937 swf_tag_replace_edit_string(swf_tag_t *tag,
938                             char *variable_name, int variable_name_len,
939                             char *initial_text, int initial_text_len,
940                             struct swf_object_ *swf) {
941     int result;
942     if (tag == NULL) {
943         fprintf(stderr, "swf_tag_replace_edit_string: tag == NULL\n");
944         return 1;
945     }
946     if (variable_name == NULL) {
947         fprintf(stderr, "swf_tag_replace_edit_string: variable_name == NULL\n");
948         return 1;
949     }
950     if (tag->code != 37) { // DefineEditText
951         return 1;
952     }
953     if (swf_tag_create_input_detail(tag, swf) == NULL) {
954         fprintf(stderr, "swf_tag_replace_edit_string: swf_tag_create_input_detail failed\n");
955         return 1;
956     }
957     result = swf_tag_edit_replace_string(tag->detail,
958                                        variable_name, variable_name_len,
959                                        initial_text, initial_text_len);
960     if (result == 0) {
961         free(tag->data);
962         tag->data = NULL;
963         tag->length = 0;
964     }
965     return result;
966 }
967
968 int
969 swf_tag_apply_shape_matrix_factor(swf_tag_t *tag, int shape_id, int bitmap_id,
970                                   double scale_x, double scale_y,
971                                   double rotate_rad,
972                                   signed int trans_x, signed int trans_y,
973                                   struct swf_object_ *swf) {
974     int result;
975     if (tag == NULL) {
976         fprintf(stderr, "swf_tag_apply_shape_matrix_factor: tag == NULL\n");
977         return 1;
978     }
979     if ((tag->code != 2) && (tag->code != 22) && (tag->code !=32 )
980         && (tag->code != 46)) {
981         // ! DefineShape1,2,3, DefineMorphShape
982         return 1;
983     }
984     if (swf_tag_get_cid(tag) != shape_id) {
985         return 1;
986     }
987     if (swf_tag_create_input_detail(tag, swf) == NULL) {
988         fprintf(stderr, "swf_tag_apply_shape_matrix_factor: swf_tag_create_input_detail failed\n");
989         return 1;
990     }
991     result = swf_tag_shape_apply_matrix_factor(tag->detail, shape_id,
992                                                bitmap_id,
993                                                scale_x, scale_y,
994                                                rotate_rad,
995                                                trans_x, trans_y);
996     if (result == 0) {
997         free(tag->data);
998         tag->data = NULL;
999         tag->length = 0;
1000     }
1001     return result;
1002 }
1003
1004 int
1005 swf_tag_apply_shape_rect_factor(swf_tag_t *tag, int shape_id, int bitmap_id,
1006                                   double scale_x, double scale_y,
1007                                   signed int trans_x, signed int trans_y,
1008                                   struct swf_object_ *swf) {
1009     int result;
1010     if (tag == NULL) {
1011         fprintf(stderr, "swf_tag_apply_shape_rect_factor: tag == NULL\n");
1012         return 1;
1013     }
1014     if ((tag->code != 2) && (tag->code != 22) && (tag->code !=32 )
1015         && (tag->code != 46)) {
1016         // ! DefineShape1,2,3, DefineMorphShape
1017         return 1;
1018     }
1019     if (swf_tag_get_cid(tag) != shape_id) {
1020         return 1;
1021     }
1022     if (swf_tag_create_input_detail(tag, swf) == NULL) {
1023         fprintf(stderr, "swf_tag_apply_shape_rect_factor: swf_tag_create_input_detail failed\n");
1024         return 1;
1025     }
1026     result = swf_tag_shape_apply_rect_factor(tag->detail, shape_id, bitmap_id,
1027                                              scale_x, scale_y,
1028                                              trans_x, trans_y);
1029     if (result == 0) {
1030         free(tag->data);
1031         tag->data = NULL;
1032         tag->length = 0;
1033     }
1034     return result;
1035 }
1036
1037 int
1038 swf_tag_apply_shape_type_tilled(swf_tag_t *tag, int shape_id, int bitmap_id,
1039                                 struct swf_object_ *swf) {
1040     int result;
1041     if (tag == NULL) {
1042         fprintf(stderr, "swf_tag_apply_shape_type_tylled: tag == NULL\n");
1043         return 1;
1044     }
1045     if ((tag->code != 2) && (tag->code != 22) && (tag->code !=32 )
1046         && (tag->code != 46)) {
1047         // ! DefineShape1,2,3, DefineMorphShape
1048         return 1;
1049     }
1050     if (swf_tag_get_cid(tag) != shape_id) {
1051         return 1;
1052     }
1053     if (swf_tag_create_input_detail(tag, swf) == NULL) {
1054         fprintf(stderr, "swf_tag_apply_shape_rect_factor: swf_tag_create_input_detail failed\n");
1055         return 1;
1056     }
1057     result = swf_tag_shape_apply_type_tilled(tag->detail, shape_id, bitmap_id);
1058     if (result == 0) {
1059         free(tag->data);
1060         tag->data = NULL;
1061         tag->length = 0;
1062     }
1063     return result;
1064 }
1065
1066 swf_tag_t *
1067 swf_tag_create_action_setvariables(y_keyvalue_t *kv) {
1068     int ret;
1069     swf_tag_t *tag = NULL;
1070     swf_tag_action_detail_t *swf_tag_action;
1071     swf_tag_info_t *tag_info;
1072     swf_tag_detail_handler_t *detail_handler;
1073     if (kv == NULL) {
1074         fprintf(stderr, "swf_tag_create_action_setvariables: kv == NULL\n");
1075         return NULL;
1076     }
1077     tag = calloc(sizeof(*tag), 1);
1078     tag->code = 12; // DoAction
1079     tag_info = get_swf_tag_info(tag->code);
1080     detail_handler = tag_info->detail_handler();
1081     tag->detail = detail_handler->create();
1082     swf_tag_action = (swf_tag_action_detail_t*) tag->detail;
1083     swf_tag_action->action_list = swf_action_list_create();
1084     if (swf_tag_action->action_list == NULL) {
1085         fprintf(stderr, "swf_tag_create_action_setvariables: swf_action_list_create failed\n");
1086         swf_tag_destroy(tag);
1087         return NULL;
1088     }
1089     swf_action_list_append_top(swf_tag_action->action_list, 0, NULL, 0); // End Action
1090     ret = swf_tag_action_top_append_varibles(tag, kv);
1091     if (ret) {
1092         swf_tag_destroy(tag);
1093         return NULL;
1094     }
1095     return tag;
1096 }
1097
1098 int
1099 swf_tag_put_action_setvariables(swf_tag_t *tag, y_keyvalue_t *kv,
1100                                 struct swf_object_ *swf) {
1101     int ret;
1102     if (tag == NULL) {
1103         fprintf(stderr, "swf_tag_put_action_setvariables: tag == NULL\n");
1104         return 1;
1105     }
1106     if (kv == NULL) {
1107         fprintf(stderr, "swf_tag_put_action_setvariables: kv == NULL\n");
1108         return 1;
1109     }
1110     if (swf_tag_create_input_detail(tag, swf) == NULL) {
1111         fprintf(stderr, "swf_tag_put_action_setvariables: swf_tag_create_input_detail failed\n");
1112         return 1;
1113     }
1114     ret = swf_tag_action_top_append_varibles(tag, kv);
1115     if (ret) {
1116         swf_tag_destroy(tag);
1117         return 1; // NG
1118     }
1119     if (tag->data) {
1120         free(tag->data);
1121         tag->data = NULL;
1122     }
1123     return 0;
1124 }
1125
1126 int
1127 swf_tag_replace_action_strings(swf_tag_t *tag, y_keyvalue_t *kv,
1128                                int *modified, struct swf_object_ *swf) {
1129     int ret;
1130     if (tag == NULL) {
1131         fprintf(stderr, "swf_tag_replace_action_string: tag == NULL\n");
1132         return 1; // NG
1133     }
1134     if (kv == NULL) {
1135         fprintf(stderr, "swf_tag_replace_action_string: kv == NULL\n");
1136         return 1; // NG
1137     }
1138     if (swf == NULL) {
1139         fprintf(stderr, "swf_tag_replace_action_string: swf == NULL\n");
1140         return 1; // NG
1141     }
1142     if (swf_tag_create_input_detail(tag, swf) == NULL) {
1143         fprintf(stderr, "swf_tag_replace_action_string: swf_tag_create_input_detail failed\n");
1144         return 1; // NG
1145     }
1146     ret = swf_tag_action_replace_strings(tag, kv, modified);
1147     if (ret) {
1148       fprintf(stderr, "swf_tag_replace_action_string: swf_tag_action_replace_strings failed\n");
1149     }
1150     return ret;
1151 }
1152
1153
1154 // move tag contents.
1155 swf_tag_t *
1156 swf_tag_move(swf_tag_t *from_tag) {
1157     swf_tag_t *to_tag = NULL;
1158     if (from_tag == NULL) {
1159         fprintf(stderr, "swf_tag_move: from_tag == NULL\n");
1160         return NULL;
1161     }
1162     to_tag = calloc(sizeof(*to_tag), 1);
1163     to_tag->code = from_tag->code;
1164     to_tag->length = from_tag->length;
1165     to_tag->length_longformat = from_tag->length_longformat;
1166     to_tag->data = from_tag->data;
1167     from_tag->data = NULL;
1168     from_tag->length = 0;
1169     to_tag->detail = from_tag->detail;
1170     from_tag->detail = NULL;
1171     return to_tag;
1172 }
1173
1174 /*
1175  * return tag CID that all condition match
1176  */
1177
1178 int
1179 swf_tag_search_cid_by_bitmap_condition(swf_tag_t *tag,
1180                                        int width, int height,
1181                                        int red, int green, int blue) {
1182     int cid = -1;
1183     if ((width > 0) || (height > 0)) {
1184         int w, h;
1185         if (swf_tag_get_bitmap_size(tag, &w, &h)) {
1186             return -1; // out
1187         }
1188         if ((width > 0) && (width != w)) {
1189             return -1; // out
1190         }
1191         if ((height > 0) && (height != h)) {
1192             return -1; // out
1193         }
1194         cid = swf_tag_get_cid(tag);
1195     }
1196     if (isBitsLosslessTag(tag->code) &&
1197         ( (red >= 0) || (green >= 0) || (blue >= 0) ))  {
1198         int r, g, b;
1199         swf_tag_get_bitmap_color1stpixel(tag, &r, &g, &b);
1200         if (red >= 0) {
1201             int red_diff = red - r;
1202             if ((red_diff < -10) || (10 < red_diff)) {
1203                 return -1; // out
1204             }
1205         }
1206         if (green >= 0) {
1207             int green_diff = green - g;
1208             if ((green_diff < -10) || (10 < green_diff)) {
1209                 return -1; // out
1210             }
1211         }
1212         if (blue >= 0) {
1213             int blue_diff = blue - b;
1214             if ((blue_diff < -10) || (10 < blue_diff)) {
1215                 return -1; // out
1216             }
1217         }
1218         cid = swf_tag_get_cid(tag);
1219     }
1220     return cid;
1221 }