fixed utf8 handling
[swftools.git] / src / swfstrings.c
1 /* swfstrings.c
2    Scans a swf file for strings
3
4    Part of the swftools package.
5    
6    Copyright (c) 2000,2001 Rainer Böhme <rfxswf@reflex-studio.de>
7  
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include "../lib/rfxswf.h"
25 #include "../lib/args.h"
26 #include "../lib/utf8.h"
27
28 static char * filename = 0;
29 static char showfonts = 0;
30 static int x=0,y=0,w=0,h=0;
31
32 static struct options_t options[] = {
33 {"f", "fonts"},
34 {"x", "xpos"},
35 {"y", "ypos"},
36 {"W", "width"},
37 {"H", "height"},
38 {"V", "version"},
39 {0,0}
40 };
41
42 int args_callback_option(char*name,char*val)
43 {
44     if(!strcmp(name, "V")) {
45         printf("swfstrings - part of %s %s\n", PACKAGE, VERSION);
46         exit(0);
47     } else if(!strcmp(name, "x")) {
48         x = atoi(val);
49         return 1;
50     } else if(!strcmp(name, "y")) {
51         y = atoi(val);
52         return 1;
53     } else if(!strcmp(name, "W")) {
54         w = atoi(val);
55         return 1;
56     } else if(!strcmp(name, "H")) {
57         h = atoi(val);
58         return 1;
59     } else if(!strcmp(name, "f")) {
60         showfonts = 1;
61         return 0;
62     } else if(!strcmp(name, "V")) {
63         printf("swfstrings - part of %s %s\n", PACKAGE, VERSION);
64         exit(0);
65     } else {
66         fprintf(stderr, "Unknown option: -%s\n", name);
67         exit(1);
68     }
69     return 0;
70 }
71 int args_callback_longoption(char*name,char*val)
72 {
73     return args_long2shortoption(options, name, val);
74 }
75 void args_callback_usage(char *name)
76 {
77     printf("\n");
78     printf("Usage: %s [options] file.swf\n", name);
79     printf("\n");
80     printf("-f , --fonts                   Print out font information for each text block\n");
81     printf("-x , --xpos <x>                Set bounding box x coordinate\n");
82     printf("-y , --ypos <y>                Set bounding box y coordinate\n");
83     printf("-W , --width <width>           Set bounding box width\n");
84     printf("-H , --height <height>         Set bounding box height\n");
85     printf("-V , --version                 Print version information and exit\n");
86     printf("\n");
87 }
88 int args_callback_command(char*name,char*val)
89 {
90     if(filename) {
91         fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
92                  filename, name);
93     }
94     filename = name;
95     return 0;
96 }
97
98 static SWF swf;
99 static int fontnum = 0;
100 static SWFFONT**fonts = 0;
101
102 void fontcallback1(void*self, U16 id,U8 * name)
103 { fontnum++;
104 }
105
106 void fontcallback2(void*self, U16 id,U8 * name)
107
108   swf_FontExtract(&swf,id,&fonts[fontnum]);
109   fontnum++;
110 }
111
112
113 void textcallback(void*self, int*glyphs, int*advance, int nr, int fontid, int fontsize, int startx, int starty, RGBA*color) 
114 {
115     SWFFONT*font = 0;
116     int t;
117     for(t=0;t<fontnum;t++)
118     {
119         if(fonts[t]->id == fontid) {
120             font = fonts[t];
121             break;
122         }
123     }
124
125     if(showfonts) {
126         if(font)
127             printf("#<font %d \"%s\"%s%s>\n", fontid, font->name, swf_FontIsBold(font)?" bold":"",swf_FontIsItalic(font)?" italic":"");
128         printf("#<color #%02x%02x%02x%02x>\n", color->r, color->g, color->b, color->a);
129         printf("#<size %d>\n", fontsize);
130     }
131
132     for(t=0;t<nr;t++)
133     {
134         int xx = startx + advance[t];
135         int yy = starty;
136         MATRIX*m = (MATRIX*)self;
137         
138         SPOINT p = {xx,yy};
139         p = swf_TurnPoint(p, m);
140         xx = p.x / 20;
141         yy = p.y / 20;
142
143         if(x|y|w|h) {
144             if(xx < x || yy < y || xx > x+w || yy > y+h) {
145                 /* outside of bounding box */
146                 ///printf("(%d+%d,%d) -> (%d,%d)\n", startx, advance[t]/20, starty, xx, yy);
147                 if(t==nr-1) return;
148                 else continue;
149             }
150         }
151
152         unsigned char a; 
153         int advance = 0;
154         if(font) {
155             if(glyphs[t]<0 || glyphs[t] >= font->numchars  /*glyph is not in range*/
156                     || !font->glyph2ascii /* font has ascii<->glyph mapping */
157               ) a = glyphs[t];
158             else {
159                 if(font->glyph2ascii[glyphs[t]])
160                     a = font->glyph2ascii[glyphs[t]];
161                 else
162                     a = glyphs[t];
163             }
164         } else {
165             a = glyphs[t];
166         }
167
168         if(a>=32) {
169             char* utf8 = getUTF8(a);
170             printf("%s", utf8);
171         } else {
172             printf("\\x%x", (int)a);
173         }
174     }
175     printf("\n");
176 }
177
178 void fontcallback(void*self,U16 id,U8 * name)
179 { SWFFONT* font;
180   TAG* t;
181   
182   swf_FontExtract(&swf,id,&font);
183
184   t = swf.firstTag;
185
186   swf_FontFree(font);
187 }
188
189 TAG**id2tag = 0;
190
191 int main (int argc,char ** argv)
192
193     int f;
194     processargs(argc, argv);
195     if(!filename)
196         exit(0);
197
198     f = open(filename,O_RDONLY|O_BINARY);
199     if (f<0 || swf_ReadSWF(f,&swf)<0) {
200         fprintf(stderr,"%s is not a valid SWF file or contains errors.\n",filename);
201         if(f>=0) close(f);
202         exit(-1);
203     }
204     close(f);
205     
206     if(x|y|w|h) {
207         if(!w) w = (swf.movieSize.xmax - swf.movieSize.xmin) / 20;
208         if(!h) h = (swf.movieSize.ymax - swf.movieSize.ymin) / 20;
209     }
210
211     id2tag = malloc(sizeof(TAG)*65536);
212
213     fontnum = 0;
214     swf_FontEnumerate(&swf,&fontcallback1, 0);
215     fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
216     fontnum = 0;
217     swf_FontEnumerate(&swf,&fontcallback2, 0);
218  
219     TAG*tag = swf.firstTag;
220     while (tag)
221     { 
222         if(swf_isTextTag(tag)) {
223             id2tag[swf_GetDefineID(tag)] = tag;
224         } else if(swf_isPlaceTag(tag)) {
225             SWFPLACEOBJECT po;
226             swf_SetTagPos(tag, 0);
227             swf_GetPlaceObject(tag, &po);
228             if(!po.move && id2tag[po.id]) {
229                 TAG*text = id2tag[po.id];
230                 swf_SetTagPos(text, 0);
231                 swf_GetU16(text);
232                 swf_GetRect(text, NULL);
233                 swf_ResetReadBits(text);
234                 MATRIX m,tm;
235                 swf_GetMatrix(text, &tm);
236                 swf_MatrixJoin(&m, &po.matrix, &tm);
237                 swf_ParseDefineText(text, textcallback, &m);
238             }
239         }
240         tag = tag->next;
241     }
242   
243     swf_FreeTags(&swf);
244     return 0;
245 }
246