OSDN Git Service

https://osdn.net/projects/swfed/scm/git/swfed/commits/a38e463ddaf7c6b915bdd94ee064a51...
[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     } else if (tag->code == 37) { // DefineEditText
421         swf_tag_edit_detail_t *swf_tag_edit;
422         swf_tag_edit = swf_tag_create_input_detail(tag, NULL);
423         if (swf_tag_edit == NULL) {
424             fprintf(stderr, "swf_tag_get_refcid: swf_tag_edit swf_tag_create_input_detail failed\n");
425             return -1;
426         }
427         return swf_tag_edit->edit_font_id_ref;
428     }
429     return -1; // no cid tag
430 }
431
432 int
433 swf_tag_replace_refcid(swf_tag_t *tag, int cid) {
434     if (tag == NULL) {
435         fprintf(stderr, "swf_tag_replace_refcid: tag == NULL\n");
436         return 1; // failure
437     }
438     if (isPlaceTag(tag->code)) { // PlaceObject, PlaceObject2
439         swf_tag_place_detail_t *swf_tag_place;
440         swf_tag_place = swf_tag_create_input_detail(tag, NULL);
441         if (swf_tag_place == NULL) {
442             fprintf(stderr, "swf_tag_replace_refcid: swf_tag_place swf_tag_create_input_detail failed\n");
443             return 1; // failure
444         }
445         swf_tag_place->character_id = cid;
446     } else if (tag->code == 37) { // DefineEditText
447         swf_tag_edit_detail_t *swf_tag_edit;
448         swf_tag_edit = swf_tag_create_input_detail(tag, NULL);
449         if (swf_tag_edit == NULL) {
450             fprintf(stderr, "swf_tag_get_refcid: swf_tag_edit swf_tag_create_input_detail failed\n");
451             return -1;
452         }
453         swf_tag_edit->edit_font_id_ref = cid;
454     }
455     if (tag->data) {
456         free(tag->data);
457         tag->data = NULL;
458     }
459     return 0; // success
460 }
461
462 /*
463  * bitmap tag
464  */
465
466 int
467 swf_tag_get_bitmap_size(swf_tag_t *tag,
468                         int *width, int *height) {
469     int ret = 0;
470     if (tag == NULL) {
471         fprintf(stderr, "swf_tag_get_bitmap_size: tag == NULL\n");
472         return 1;
473     }
474     if ((width == NULL ) || (height == NULL)) {
475         fprintf(stderr, "swf_tag_get_bitmap_size: width == NULL or height == NULL\n");
476         return 1;
477     }
478     if (isBitsJPEGTag(tag->code)) {
479         swf_tag_jpeg_detail_t *swf_tag_jpeg;
480         if (swf_tag_create_input_detail(tag, NULL) == NULL) {
481             fprintf(stderr, "swf_tag_get_bitmap_size: swf_tag_create_input_detail failed\n");
482             return 1;
483         }
484         swf_tag_jpeg = (swf_tag_jpeg_detail_t *) tag->detail;
485         ret = jpeg_size(swf_tag_jpeg->jpeg_data, swf_tag_jpeg->jpeg_data_len,
486                         width, height);
487     } else if (isBitsLosslessTag(tag->code)) {
488         if (tag->detail) {
489             swf_tag_lossless_detail_t *swf_tag_lossless = (swf_tag_lossless_detail_t *) tag->detail;
490             *width  = swf_tag_lossless->width;
491             *height = swf_tag_lossless->height;
492         } else {
493             *width  = GetUShortLE((tag->data + 3));
494             *height = GetUShortLE((tag->data + 5));
495         }
496     } else { // no Bitmap Tag
497         return 1;
498     }
499     return ret;
500 }
501
502 int
503 swf_tag_get_bitmap_color1stpixel(swf_tag_t *tag,
504                                  int *red, int *green, int *blue) {
505     swf_tag_lossless_detail_t *swf_tag_lossless = NULL;
506     if (tag == NULL) {
507         fprintf(stderr, "swf_tag_get_bitmap_color1stpixel: tag == NULL\n");
508         return 1;
509     }
510     if ((red == NULL ) || (green == NULL) || (blue == NULL)) {
511         fprintf(stderr, "swf_tag_get_bitmap_color1stpixel: width == NULL or height == NULL\n");
512         return 1;
513     }
514     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
515         fprintf(stderr, "swf_tag_get_bitmap_color1stpixel: swf_tag_create_input_detail failed\n");
516         return 1;
517     }
518     if (isBitsLosslessTag(tag->code) == 0) {
519         return 1; // No Lossless Tag;
520     }
521     swf_tag_lossless = (swf_tag_lossless_detail_t *) tag->detail;
522
523     // get first 1 pixel RGB value. by format and tag_code.
524     switch (swf_tag_lossless->format) {
525         int color_index;
526     case 3:
527         color_index = swf_tag_lossless->indices[0];
528         if (tag->code == 20) { // Lossless => RGB
529             *red   = swf_tag_lossless->colormap[color_index].red;
530             *green = swf_tag_lossless->colormap[color_index].green;
531             *blue  = swf_tag_lossless->colormap[color_index].blue;
532         } else { // Lossless2 => RGBA
533             int alpha = swf_tag_lossless->colormap2[color_index].alpha;
534             if (alpha == 0) {
535                 *red   = swf_tag_lossless->colormap2[color_index].red;
536                 *green = swf_tag_lossless->colormap2[color_index].green;
537                 *blue  = swf_tag_lossless->colormap2[color_index].blue;
538             }
539             else {
540                 *red   = swf_tag_lossless->colormap2[color_index].red * 255 / alpha;
541                 *green = swf_tag_lossless->colormap2[color_index].green * 255 / alpha;
542                 *blue  = swf_tag_lossless->colormap2[color_index].blue * 255 / alpha;
543             }
544         }
545         break;
546     case 5:
547         if (tag->code == 20) { // Lossless => RGB
548             *red   = swf_tag_lossless->bitmap[0].red;
549             *green = swf_tag_lossless->bitmap[0].green;
550             *blue  = swf_tag_lossless->bitmap[0].blue;
551         } else { // Lossless2 => ARGB
552             int alpha = swf_tag_lossless->bitmap2[0].alpha;
553             if (alpha == 0) {
554                 *red   = swf_tag_lossless->bitmap2[0].red;
555                 *green = swf_tag_lossless->bitmap2[0].green;
556                 *blue  = swf_tag_lossless->bitmap2[0].blue;
557             }
558             else {
559                 *red   = swf_tag_lossless->bitmap2[0].red * 255 / alpha;
560                 *green = swf_tag_lossless->bitmap2[0].green * 255 / alpha;
561                 *blue  = swf_tag_lossless->bitmap2[0].blue * 255 / alpha;
562             }
563         }
564         break;
565     default: // include 4 (15bit color)
566         fprintf(stderr, "swf_tag_get_bitmap_color1stpixel: unacceptable format=(%d)\n", swf_tag_lossless->format);
567         return 1;
568     }
569     return 0; // SUCCESS
570 }
571
572 unsigned char *
573 swf_tag_get_jpeg_data(swf_tag_t *tag, unsigned long *length, int image_id, swf_tag_t *tag_jpegtables) {
574     swf_tag_info_t *tag_info = NULL;
575     *length = 0;
576     if (tag == NULL) {
577         fprintf(stderr, "swf_tag_get_jpeg_data: tag == NULL\n");
578         return NULL;
579     }
580     if (length == NULL) {
581         fprintf(stderr, "swf_tag_get_jpeg_data: length == NULL\n");
582         return NULL;
583     }
584     tag_info = get_swf_tag_info(tag->code);
585     if ((tag->code != 6) && (tag->code != 21) && (tag->code != 35)) {
586         return NULL;
587     }
588     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
589         fprintf(stderr, "swf_tag_get_jpeg_data: swf_tag_create_input_detail failed\n");
590         return NULL;
591     }
592     if (tag_jpegtables) {
593         return swf_tag_jpeg_get_jpeg_data(tag->detail, length, image_id,
594                                           tag_jpegtables->data,
595                                           tag_jpegtables->length);
596     } else {
597         return swf_tag_jpeg_get_jpeg_data(tag->detail, length, image_id,
598                                           NULL, 0);
599     }
600 }
601
602 unsigned char *
603 swf_tag_get_alpha_data(swf_tag_t *tag, unsigned long *length, int image_id) {
604     *length = 0;
605     if (tag == NULL) {
606         fprintf(stderr, "swf_tag_get_alpha_data: tag == NULL\n");
607         return NULL;
608     }
609     if (length == NULL) {
610         fprintf(stderr, "swf_tag_get_alpha_data: length == NULL\n");
611         return NULL;
612     }
613     if (tag->code != 35) { // ! DefineBitsJPEG3
614         return NULL;
615     }
616     if (swf_tag_get_cid(tag) != image_id) {
617         return NULL;
618     }
619     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
620         fprintf(stderr, "swf_tag_get_alpha_data: swf_tag_create_input_detail failed\n");
621         return NULL;
622     }
623     return swf_tag_jpeg_get_alpha_data(tag->detail, length, image_id);
624 }
625
626 int
627 swf_tag_replace_jpeg_data(swf_tag_t *tag, int image_id,
628                           unsigned char *jpeg_data,
629                           unsigned long jpeg_data_len,
630                           unsigned char *alpha_data,
631                           unsigned long alpha_data_len,
632                           int without_converting) {
633     swf_tag_info_t *tag_info = NULL;
634     swf_tag_detail_handler_t * detail_handler = NULL;
635     int result;
636     if (tag == NULL) {
637         fprintf(stderr, "swf_tag_replace_jpeg_data: tag == NULL\n");
638         return 1;
639     }
640     if (jpeg_data == NULL) {
641         fprintf(stderr, "swf_tag_replace_jpeg_data: jpeg_data == NULL\n");
642         return 1;
643     }
644     if (! isBitmapTag(tag->code)) {
645         return 1;
646     }
647     tag_info = get_swf_tag_info(tag->code); // Bitmap Tag
648     detail_handler = tag_info->detail_handler();
649     if (detail_handler->get_cid(tag) !=  image_id) {
650         return 1;
651     }
652
653     if (tag->detail && (! isBitsJPEGTag(tag->code))) {
654         detail_handler->destroy(tag);
655         tag->detail = NULL;
656     }
657     if (alpha_data && (alpha_data_len > 0)) {
658         tag->code = 35; // DefineBitsJPEG3
659     } else {
660         tag->code = 21; // DefineBitsJPEG2
661     }
662     
663     tag_info = get_swf_tag_info(tag->code); // JPEG Tag
664     detail_handler = tag_info->detail_handler();
665     if (tag->detail == NULL) {
666         tag->detail = detail_handler->create();
667     }
668
669     if (without_converting) {
670         result= swf_tag_jpeg_replace_bitmap_data(tag->detail, image_id,
671                                                  jpeg_data, jpeg_data_len,
672                                                  tag);
673     } else {
674         result= swf_tag_jpeg_replace_jpeg_data(tag->detail, image_id,
675                                                jpeg_data, jpeg_data_len,
676                                                alpha_data, alpha_data_len, tag);
677     }
678     if (result == 0) {
679         free(tag->data);
680         tag->data = NULL;
681         tag->length = 0;
682     } else {
683         detail_handler->destroy(tag);
684         tag->detail = NULL;
685     } 
686     return result;
687 }
688
689
690 #ifdef HAVE_PNG
691
692 unsigned char *
693 swf_tag_get_png_data(swf_tag_t *tag, unsigned long *length, int image_id) {
694     swf_tag_info_t *tag_info = NULL;
695     *length = 0;
696     if (tag == NULL) {
697         fprintf(stderr, "swf_tag_get_png_data: tag == NULL\n");
698         return NULL;
699     }
700     if (length == NULL) {
701         fprintf(stderr, "swf_tag_get_png_data: length == NULL\n");
702         return NULL;
703     }
704     tag_info = get_swf_tag_info(tag->code);
705     if ((tag->code != 20) && (tag->code != 36)) {
706         return NULL;
707     }
708     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
709         fprintf(stderr, "swf_tag_get_png_data: swf_tag_create_input_detail failed\n");
710         return NULL;
711     }
712     return swf_tag_lossless_get_png_data(tag->detail, length, image_id, tag);
713 }
714
715 int
716 swf_tag_replace_png_data(swf_tag_t *tag, int image_id,
717                          unsigned char *png_data,
718                          unsigned long png_data_len, int rgb15) {
719     swf_tag_info_t *tag_info = NULL;
720     swf_tag_detail_handler_t *detail_handler = NULL;
721     int result;
722     if (tag == NULL) {
723         fprintf(stderr, "swf_tag_replace_png_data: tag == NULL\n");
724         return 1;
725     }
726     if (png_data == NULL) {
727         fprintf(stderr, "swf_tag_replace_png_data: png_data == NULL\n");
728         return 1;
729     }
730     if (! isBitmapTag(tag->code)) {
731         return 1;
732     }
733     tag_info = get_swf_tag_info(tag->code); // Bitmap Tag
734     detail_handler = tag_info->detail_handler();
735     if (detail_handler->get_cid(tag) != image_id) {
736         return 1;
737     }
738     
739     if (tag->detail && (! isBitsLosslessTag(tag->code))) {
740         detail_handler->destroy(tag);
741         tag->detail = NULL;
742     }
743     if (tag->code == 20) {
744         tag->code = 20; // DefineBitsLossless
745     } else {
746         tag->code = 36; // DefineBitsLossless2
747     }
748     
749     tag_info = get_swf_tag_info(tag->code); // Lossless Tag
750     detail_handler = tag_info->detail_handler();
751     if (tag->detail == NULL) {
752         tag->detail = detail_handler->create();
753     }
754     
755     result= swf_tag_lossless_replace_png_data(tag->detail, image_id,
756                                               png_data, png_data_len,
757                                               rgb15, tag);
758     if (result == 0) {
759         free(tag->data);
760         tag->data = NULL;
761         tag->length = 0;
762     } else {
763         detail_handler->destroy(tag);
764         tag->detail = NULL;
765     }
766     return result;
767 }
768
769 #endif /* HAVE_PNG */
770
771 #ifdef HAVE_GIF
772
773 int
774 swf_tag_replace_gif_data(swf_tag_t *tag, int image_id,
775                          unsigned char *gif_data,
776                          unsigned long gif_data_len) {
777     swf_tag_info_t *tag_info = NULL;
778     swf_tag_detail_handler_t *detail_handler = NULL;
779     int result;
780     if (tag == NULL) {
781         fprintf(stderr, "swf_tag_replace_gif_data: tag == NULL\n");
782         return 1;
783     }
784     if (gif_data == NULL) {
785         fprintf(stderr, "swf_tag_replace_gif_data: gif_data == NULL\n");
786         return 1;
787     }
788     if (! isBitmapTag(tag->code)) {
789         return 1;
790     }
791     tag_info = get_swf_tag_info(tag->code); // Bitmap Tag
792     detail_handler = tag_info->detail_handler();
793     if (detail_handler->get_cid(tag) != image_id) {
794         return 1;
795     }
796     
797     if (tag->detail && (! isBitsLosslessTag(tag->code))) {
798         detail_handler->destroy(tag);
799         tag->detail = NULL;
800     }
801     if (tag->code == 20) {
802         tag->code = 20; // DefineBitsLossless
803     } else {
804         tag->code = 36; // DefineBitsLossless2
805     }
806     
807     tag_info = get_swf_tag_info(tag->code); // Lossless Tag
808     detail_handler = tag_info->detail_handler();
809     if (tag->detail == NULL) {
810         tag->detail = detail_handler->create();
811     }
812     
813     result= swf_tag_lossless_replace_gif_data(tag->detail, image_id,
814                                               gif_data, gif_data_len, tag);
815     if (result == 0) {
816         free(tag->data);
817         tag->data = NULL;
818         tag->length = 0;
819     } else {
820         detail_handler->destroy(tag);
821         tag->detail = NULL;
822     }
823     return result;
824 }
825
826 #endif /* HAVE_GIF */
827
828 int
829 swf_tag_convert_bitmap_data_tojpegtag(swf_tag_t *tag) {
830     int tag_code;
831     int image_id;
832     unsigned char *bitmap_data;
833     unsigned long bitmap_data_len;
834     swf_tag_lossless_detail_t *swf_tag_lossless;
835     int ret;
836     if (tag == NULL) {
837         fprintf(stderr, "swf_object_convert_bitmap_data_tojpegtag: tag == NULL\n");
838         return 1;
839     }
840     tag_code = tag->code;
841     if ((tag_code != 20) && (tag_code != 36)) {
842         return 1;
843     }
844     if (tag->detail == NULL) {
845         swf_tag_lossless = (swf_tag_lossless_detail_t *) swf_tag_create_input_detail(tag, NULL);
846     } else {
847         swf_tag_lossless = (swf_tag_lossless_detail_t *) tag->detail;
848     }
849     image_id= swf_tag_lossless->image_id;
850     bitmap_data = swf_tag_lossless_get_png_data(swf_tag_lossless, &bitmap_data_len, image_id, tag);
851     if (bitmap_data == NULL) {
852         fprintf(stderr, "swf_object_convert_bitmap_data_tojpegtag: failed to swf_tag_get_png_data image_id=%d\n", image_id);
853         return 1;
854     }
855     ret = swf_tag_replace_jpeg_data(tag, image_id,
856                                     bitmap_data, bitmap_data_len, NULL, 0, 1);
857     free(bitmap_data);
858     if (ret) {
859         fprintf(stderr, "swf_object_convert_bitmap_data_tojpegtag: failed to swf_tag_replace_jpeg_data image_id=%d\n", image_id);
860         return ret;
861     }
862     return 0;
863 }
864
865 /*
866  * DefineSound
867  */
868
869 unsigned char *
870 swf_tag_get_sound_data(swf_tag_t *tag, unsigned long *length, int sound_id) {
871     swf_tag_info_t *tag_info = NULL;
872     *length = 0;
873     if (tag == NULL) {
874         fprintf(stderr, "swf_tag_get_sound_data: tag == NULL\n");
875         return NULL;
876     }
877     if (length == NULL) {
878         fprintf(stderr, "swf_tag_get_sound_data: length == NULL\n");
879         return NULL;
880     }
881     tag_info = get_swf_tag_info(tag->code);
882     if (tag->code != 14) { // DefineSound
883         return NULL;
884     }
885     if (! tag->detail) {
886         
887     }
888     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
889         fprintf(stderr, "swf_tag_get_sound_data: swf_tag_create_input_detail failed\n");
890         return NULL;
891     }
892     return swf_tag_sound_get_sound_data(tag->detail, length, sound_id);
893 }
894
895 int
896 swf_tag_replace_melo_data(swf_tag_t *tag, int sound_id,
897                           unsigned char *melo_data,
898                           unsigned long melo_data_len) {
899     int result;
900     if (tag == NULL) {
901         fprintf(stderr, "swf_tag_replace_melo_data: tag == NULL\n");
902         return 1;
903     }
904     if (melo_data == NULL) {
905         fprintf(stderr, "swf_tag_replace_melo_data: melo_data == NULL\n");
906         return 1;
907     }
908     if (tag->code != 14) { // DefineSound
909         return 1;
910     }
911     if (swf_tag_get_cid(tag) != sound_id) {
912         return 1;
913     }
914     if (swf_tag_create_input_detail(tag, NULL) == NULL) {
915         fprintf(stderr, "swf_tag_replace_melog_data: swf_tag_create_input_detail failed\n");
916         return 1;
917     }
918     result= swf_tag_sound_replace_melo_data(tag->detail, sound_id,
919                                             melo_data, melo_data_len);
920     if (result == 0) {
921         free(tag->data);
922         tag->data = NULL;
923         tag->length = 0;
924     }
925     return result;
926 }
927
928 char *
929 swf_tag_get_edit_string(swf_tag_t *tag,
930                         char *variable_name, int variable_name_len,
931                         int *error, struct swf_object_ *swf) {
932     *error = 1;
933     if (tag == NULL) {
934         fprintf(stderr, "swf_tag_get_edit_string: tag == NULL\n");
935         return NULL;
936     }
937     if (variable_name == NULL) {
938         fprintf(stderr, "swf_tag_get_edit_string: variable_name == NULL\n");
939         return NULL;
940     }
941     if (tag->code != 37) { // DefineEditText
942         return NULL;
943     }
944     if (swf_tag_create_input_detail(tag, swf) == NULL) {
945         fprintf(stderr, "swf_tag_get_edit_string: swf_tag_create_input_detail failed\n");
946         return NULL;
947     }
948     return swf_tag_edit_get_string(tag->detail,
949                                    variable_name, variable_name_len, error);
950 }
951
952 int
953 swf_tag_replace_edit_string(swf_tag_t *tag,
954                             char *variable_name, int variable_name_len,
955                             char *initial_text, int initial_text_len,
956                             struct swf_object_ *swf) {
957     int result;
958     if (tag == NULL) {
959         fprintf(stderr, "swf_tag_replace_edit_string: tag == NULL\n");
960         return 1;
961     }
962     if (variable_name == NULL) {
963         fprintf(stderr, "swf_tag_replace_edit_string: variable_name == NULL\n");
964         return 1;
965     }
966     if (tag->code != 37) { // DefineEditText
967         return 1;
968     }
969     if (swf_tag_create_input_detail(tag, swf) == NULL) {
970         fprintf(stderr, "swf_tag_replace_edit_string: swf_tag_create_input_detail failed\n");
971         return 1;
972     }
973     result = swf_tag_edit_replace_string(tag->detail,
974                                        variable_name, variable_name_len,
975                                        initial_text, initial_text_len);
976     if (result == 0) {
977         free(tag->data);
978         tag->data = NULL;
979         tag->length = 0;
980     }
981     return result;
982 }
983
984 int
985 swf_tag_apply_shape_matrix_factor(swf_tag_t *tag, int shape_id, int bitmap_id,
986                                   double scale_x, double scale_y,
987                                   double rotate_rad,
988                                   signed int trans_x, signed int trans_y,
989                                   struct swf_object_ *swf) {
990     int result;
991     if (tag == NULL) {
992         fprintf(stderr, "swf_tag_apply_shape_matrix_factor: tag == NULL\n");
993         return 1;
994     }
995     if ((tag->code != 2) && (tag->code != 22) && (tag->code !=32 )
996         && (tag->code != 46)) {
997         // ! DefineShape1,2,3, DefineMorphShape
998         return 1;
999     }
1000     if (swf_tag_get_cid(tag) != shape_id) {
1001         return 1;
1002     }
1003     if (swf_tag_create_input_detail(tag, swf) == NULL) {
1004         fprintf(stderr, "swf_tag_apply_shape_matrix_factor: swf_tag_create_input_detail failed\n");
1005         return 1;
1006     }
1007     result = swf_tag_shape_apply_matrix_factor(tag->detail, shape_id,
1008                                                bitmap_id,
1009                                                scale_x, scale_y,
1010                                                rotate_rad,
1011                                                trans_x, trans_y);
1012     if (result == 0) {
1013         free(tag->data);
1014         tag->data = NULL;
1015         tag->length = 0;
1016     }
1017     return result;
1018 }
1019
1020 int
1021 swf_tag_apply_shape_rect_factor(swf_tag_t *tag, int shape_id, int bitmap_id,
1022                                   double scale_x, double scale_y,
1023                                   signed int trans_x, signed int trans_y,
1024                                   struct swf_object_ *swf) {
1025     int result;
1026     if (tag == NULL) {
1027         fprintf(stderr, "swf_tag_apply_shape_rect_factor: tag == NULL\n");
1028         return 1;
1029     }
1030     if ((tag->code != 2) && (tag->code != 22) && (tag->code !=32 )
1031         && (tag->code != 46)) {
1032         // ! DefineShape1,2,3, DefineMorphShape
1033         return 1;
1034     }
1035     if (swf_tag_get_cid(tag) != shape_id) {
1036         return 1;
1037     }
1038     if (swf_tag_create_input_detail(tag, swf) == NULL) {
1039         fprintf(stderr, "swf_tag_apply_shape_rect_factor: swf_tag_create_input_detail failed\n");
1040         return 1;
1041     }
1042     result = swf_tag_shape_apply_rect_factor(tag->detail, shape_id, bitmap_id,
1043                                              scale_x, scale_y,
1044                                              trans_x, trans_y);
1045     if (result == 0) {
1046         free(tag->data);
1047         tag->data = NULL;
1048         tag->length = 0;
1049     }
1050     return result;
1051 }
1052
1053 int
1054 swf_tag_apply_shape_type_tilled(swf_tag_t *tag, int shape_id, int bitmap_id,
1055                                 struct swf_object_ *swf) {
1056     int result;
1057     if (tag == NULL) {
1058         fprintf(stderr, "swf_tag_apply_shape_type_tylled: tag == NULL\n");
1059         return 1;
1060     }
1061     if ((tag->code != 2) && (tag->code != 22) && (tag->code !=32 )
1062         && (tag->code != 46)) {
1063         // ! DefineShape1,2,3, DefineMorphShape
1064         return 1;
1065     }
1066     if (swf_tag_get_cid(tag) != shape_id) {
1067         return 1;
1068     }
1069     if (swf_tag_create_input_detail(tag, swf) == NULL) {
1070         fprintf(stderr, "swf_tag_apply_shape_rect_factor: swf_tag_create_input_detail failed\n");
1071         return 1;
1072     }
1073     result = swf_tag_shape_apply_type_tilled(tag->detail, shape_id, bitmap_id);
1074     if (result == 0) {
1075         free(tag->data);
1076         tag->data = NULL;
1077         tag->length = 0;
1078     }
1079     return result;
1080 }
1081
1082 swf_tag_t *
1083 swf_tag_create_action_setvariables(y_keyvalue_t *kv) {
1084     int ret;
1085     swf_tag_t *tag = NULL;
1086     swf_tag_action_detail_t *swf_tag_action;
1087     swf_tag_info_t *tag_info;
1088     swf_tag_detail_handler_t *detail_handler;
1089     if (kv == NULL) {
1090         fprintf(stderr, "swf_tag_create_action_setvariables: kv == NULL\n");
1091         return NULL;
1092     }
1093     tag = calloc(sizeof(*tag), 1);
1094     tag->code = 12; // DoAction
1095     tag_info = get_swf_tag_info(tag->code);
1096     detail_handler = tag_info->detail_handler();
1097     tag->detail = detail_handler->create();
1098     swf_tag_action = (swf_tag_action_detail_t*) tag->detail;
1099     swf_tag_action->action_list = swf_action_list_create();
1100     if (swf_tag_action->action_list == NULL) {
1101         fprintf(stderr, "swf_tag_create_action_setvariables: swf_action_list_create failed\n");
1102         swf_tag_destroy(tag);
1103         return NULL;
1104     }
1105     swf_action_list_append_top(swf_tag_action->action_list, 0, NULL, 0); // End Action
1106     ret = swf_tag_action_top_append_varibles(tag, kv);
1107     if (ret) {
1108         swf_tag_destroy(tag);
1109         return NULL;
1110     }
1111     return tag;
1112 }
1113
1114 int
1115 swf_tag_put_action_setvariables(swf_tag_t *tag, y_keyvalue_t *kv,
1116                                 struct swf_object_ *swf) {
1117     int ret;
1118     if (tag == NULL) {
1119         fprintf(stderr, "swf_tag_put_action_setvariables: tag == NULL\n");
1120         return 1;
1121     }
1122     if (kv == NULL) {
1123         fprintf(stderr, "swf_tag_put_action_setvariables: kv == NULL\n");
1124         return 1;
1125     }
1126     if (swf_tag_create_input_detail(tag, swf) == NULL) {
1127         fprintf(stderr, "swf_tag_put_action_setvariables: swf_tag_create_input_detail failed\n");
1128         return 1;
1129     }
1130     ret = swf_tag_action_top_append_varibles(tag, kv);
1131     if (ret) {
1132         swf_tag_destroy(tag);
1133         return 1; // NG
1134     }
1135     if (tag->data) {
1136         free(tag->data);
1137         tag->data = NULL;
1138     }
1139     return 0;
1140 }
1141
1142 int
1143 swf_tag_replace_action_strings(swf_tag_t *tag, y_keyvalue_t *kv,
1144                                int *modified, struct swf_object_ *swf) {
1145     int ret;
1146     if (tag == NULL) {
1147         fprintf(stderr, "swf_tag_replace_action_string: tag == NULL\n");
1148         return 1; // NG
1149     }
1150     if (kv == NULL) {
1151         fprintf(stderr, "swf_tag_replace_action_string: kv == NULL\n");
1152         return 1; // NG
1153     }
1154     if (swf == NULL) {
1155         fprintf(stderr, "swf_tag_replace_action_string: swf == NULL\n");
1156         return 1; // NG
1157     }
1158     if (swf_tag_create_input_detail(tag, swf) == NULL) {
1159         fprintf(stderr, "swf_tag_replace_action_string: swf_tag_create_input_detail failed\n");
1160         return 1; // NG
1161     }
1162     ret = swf_tag_action_replace_strings(tag, kv, modified);
1163     if (ret) {
1164       fprintf(stderr, "swf_tag_replace_action_string: swf_tag_action_replace_strings failed\n");
1165     }
1166     return ret;
1167 }
1168
1169
1170 // move tag contents.
1171 swf_tag_t *
1172 swf_tag_move(swf_tag_t *from_tag) {
1173     swf_tag_t *to_tag = NULL;
1174     if (from_tag == NULL) {
1175         fprintf(stderr, "swf_tag_move: from_tag == NULL\n");
1176         return NULL;
1177     }
1178     to_tag = calloc(sizeof(*to_tag), 1);
1179     to_tag->code = from_tag->code;
1180     to_tag->length = from_tag->length;
1181     to_tag->length_longformat = from_tag->length_longformat;
1182     to_tag->data = from_tag->data;
1183     from_tag->data = NULL;
1184     from_tag->length = 0;
1185     to_tag->detail = from_tag->detail;
1186     from_tag->detail = NULL;
1187     return to_tag;
1188 }
1189
1190 /*
1191  * return tag CID that all condition match
1192  */
1193
1194 int
1195 swf_tag_search_cid_by_bitmap_condition(swf_tag_t *tag,
1196                                        int width, int height,
1197                                        int red, int green, int blue) {
1198     int cid = -1;
1199     if ((width > 0) || (height > 0)) {
1200         int w, h;
1201         if (swf_tag_get_bitmap_size(tag, &w, &h)) {
1202             return -1; // out
1203         }
1204         if ((width > 0) && (width != w)) {
1205             return -1; // out
1206         }
1207         if ((height > 0) && (height != h)) {
1208             return -1; // out
1209         }
1210         cid = swf_tag_get_cid(tag);
1211     }
1212     if (isBitsLosslessTag(tag->code) &&
1213         ( (red >= 0) || (green >= 0) || (blue >= 0) ))  {
1214         int r, g, b;
1215         swf_tag_get_bitmap_color1stpixel(tag, &r, &g, &b);
1216         if (red >= 0) {
1217             int red_diff = red - r;
1218             if ((red_diff < -10) || (10 < red_diff)) {
1219                 return -1; // out
1220             }
1221         }
1222         if (green >= 0) {
1223             int green_diff = green - g;
1224             if ((green_diff < -10) || (10 < green_diff)) {
1225                 return -1; // out
1226             }
1227         }
1228         if (blue >= 0) {
1229             int blue_diff = blue - b;
1230             if ((blue_diff < -10) || (10 < blue_diff)) {
1231                 return -1; // out
1232             }
1233         }
1234         cid = swf_tag_get_cid(tag);
1235     }
1236     return cid;
1237 }