swfmill 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/.document +5 -0
  2. data/.gitignore +23 -0
  3. data/.swfmill +240 -0
  4. data/LICENSE +340 -0
  5. data/README.rdoc +37 -0
  6. data/Rakefile +59 -0
  7. data/VERSION +1 -0
  8. data/ext/.gitignore +5 -0
  9. data/ext/extconf.rb +86 -0
  10. data/ext/swfmill/.gitignore +27 -0
  11. data/ext/swfmill/AUTHORS +9 -0
  12. data/ext/swfmill/COPYING +340 -0
  13. data/ext/swfmill/Makefile.am +14 -0
  14. data/ext/swfmill/Makefile.in +635 -0
  15. data/ext/swfmill/NEWS +189 -0
  16. data/ext/swfmill/README +170 -0
  17. data/ext/swfmill/TODO +33 -0
  18. data/ext/swfmill/aclocal.m4 +7712 -0
  19. data/ext/swfmill/autogen.sh +7 -0
  20. data/ext/swfmill/compile +142 -0
  21. data/ext/swfmill/config.guess +1516 -0
  22. data/ext/swfmill/config.sub +1626 -0
  23. data/ext/swfmill/configure +21868 -0
  24. data/ext/swfmill/configure.ac +55 -0
  25. data/ext/swfmill/depcomp +589 -0
  26. data/ext/swfmill/install-sh +519 -0
  27. data/ext/swfmill/ltmain.sh +6964 -0
  28. data/ext/swfmill/missing +367 -0
  29. data/ext/swfmill/src/Geom.cpp +107 -0
  30. data/ext/swfmill/src/Geom.h +100 -0
  31. data/ext/swfmill/src/Makefile.am +86 -0
  32. data/ext/swfmill/src/Makefile.in +1025 -0
  33. data/ext/swfmill/src/SWF.h +11941 -0
  34. data/ext/swfmill/src/SWFAction.cpp +41 -0
  35. data/ext/swfmill/src/SWFAction.h +19 -0
  36. data/ext/swfmill/src/SWFBasic.h +7 -0
  37. data/ext/swfmill/src/SWFFile.cpp +406 -0
  38. data/ext/swfmill/src/SWFFile.h +34 -0
  39. data/ext/swfmill/src/SWFFilter.cpp +25 -0
  40. data/ext/swfmill/src/SWFFilter.h +15 -0
  41. data/ext/swfmill/src/SWFGlyphList.cpp +262 -0
  42. data/ext/swfmill/src/SWFGlyphList.h +34 -0
  43. data/ext/swfmill/src/SWFIdItem.h +85 -0
  44. data/ext/swfmill/src/SWFIdItems.h +16 -0
  45. data/ext/swfmill/src/SWFItem.cpp +235 -0
  46. data/ext/swfmill/src/SWFItem.h +60 -0
  47. data/ext/swfmill/src/SWFList.h +179 -0
  48. data/ext/swfmill/src/SWFReader.cpp +352 -0
  49. data/ext/swfmill/src/SWFReader.h +73 -0
  50. data/ext/swfmill/src/SWFShapeItem.cpp +220 -0
  51. data/ext/swfmill/src/SWFShapeItem.h +45 -0
  52. data/ext/swfmill/src/SWFShapeMaker.cpp +401 -0
  53. data/ext/swfmill/src/SWFShapeMaker.h +128 -0
  54. data/ext/swfmill/src/SWFTag.cpp +49 -0
  55. data/ext/swfmill/src/SWFTag.h +20 -0
  56. data/ext/swfmill/src/SWFTrait.cpp +35 -0
  57. data/ext/swfmill/src/SWFTrait.h +22 -0
  58. data/ext/swfmill/src/SWFWriter.cpp +312 -0
  59. data/ext/swfmill/src/SWFWriter.h +84 -0
  60. data/ext/swfmill/src/base64.c +110 -0
  61. data/ext/swfmill/src/base64.h +15 -0
  62. data/ext/swfmill/src/codegen/Makefile.am +15 -0
  63. data/ext/swfmill/src/codegen/Makefile.in +346 -0
  64. data/ext/swfmill/src/codegen/basic.xsl +45 -0
  65. data/ext/swfmill/src/codegen/basics.xsl +235 -0
  66. data/ext/swfmill/src/codegen/dumper.xsl +109 -0
  67. data/ext/swfmill/src/codegen/header.xsl +131 -0
  68. data/ext/swfmill/src/codegen/mk.xsl +26 -0
  69. data/ext/swfmill/src/codegen/parser.xsl +196 -0
  70. data/ext/swfmill/src/codegen/parsexml.xsl +312 -0
  71. data/ext/swfmill/src/codegen/size.xsl +189 -0
  72. data/ext/swfmill/src/codegen/source.xml +2197 -0
  73. data/ext/swfmill/src/codegen/writer.xsl +190 -0
  74. data/ext/swfmill/src/codegen/writexml.xsl +138 -0
  75. data/ext/swfmill/src/swfmill.cpp +482 -0
  76. data/ext/swfmill/src/swft/Makefile.am +55 -0
  77. data/ext/swfmill/src/swft/Makefile.in +717 -0
  78. data/ext/swfmill/src/swft/Parser.cpp +76 -0
  79. data/ext/swfmill/src/swft/Parser.h +37 -0
  80. data/ext/swfmill/src/swft/SVGAttributeParser.cpp +78 -0
  81. data/ext/swfmill/src/swft/SVGAttributeParser.h +35 -0
  82. data/ext/swfmill/src/swft/SVGColor.cpp +116 -0
  83. data/ext/swfmill/src/swft/SVGColor.h +37 -0
  84. data/ext/swfmill/src/swft/SVGColors.h +167 -0
  85. data/ext/swfmill/src/swft/SVGGradient.cpp +258 -0
  86. data/ext/swfmill/src/swft/SVGGradient.h +81 -0
  87. data/ext/swfmill/src/swft/SVGPathParser.cpp +155 -0
  88. data/ext/swfmill/src/swft/SVGPathParser.h +126 -0
  89. data/ext/swfmill/src/swft/SVGPointsParser.cpp +51 -0
  90. data/ext/swfmill/src/swft/SVGPointsParser.h +25 -0
  91. data/ext/swfmill/src/swft/SVGStyle.cpp +181 -0
  92. data/ext/swfmill/src/swft/SVGStyle.h +80 -0
  93. data/ext/swfmill/src/swft/SVGTransformParser.cpp +72 -0
  94. data/ext/swfmill/src/swft/SVGTransformParser.h +32 -0
  95. data/ext/swfmill/src/swft/readpng.c +305 -0
  96. data/ext/swfmill/src/swft/readpng.h +92 -0
  97. data/ext/swfmill/src/swft/swft.cpp +251 -0
  98. data/ext/swfmill/src/swft/swft.h +64 -0
  99. data/ext/swfmill/src/swft/swft_document.cpp +57 -0
  100. data/ext/swfmill/src/swft/swft_import.cpp +38 -0
  101. data/ext/swfmill/src/swft/swft_import_binary.cpp +82 -0
  102. data/ext/swfmill/src/swft/swft_import_jpeg.cpp +255 -0
  103. data/ext/swfmill/src/swft/swft_import_mp3.cpp +268 -0
  104. data/ext/swfmill/src/swft/swft_import_png.cpp +231 -0
  105. data/ext/swfmill/src/swft/swft_import_ttf.cpp +519 -0
  106. data/ext/swfmill/src/swft/swft_import_wav.cpp +255 -0
  107. data/ext/swfmill/src/swft/swft_path.cpp +178 -0
  108. data/ext/swfmill/src/xslt/Makefile.am +51 -0
  109. data/ext/swfmill/src/xslt/Makefile.in +536 -0
  110. data/ext/swfmill/src/xslt/README +19 -0
  111. data/ext/swfmill/src/xslt/assemble.xsl +38 -0
  112. data/ext/swfmill/src/xslt/simple-deprecated.xslt +62 -0
  113. data/ext/swfmill/src/xslt/simple-elements.xslt +627 -0
  114. data/ext/swfmill/src/xslt/simple-import.xslt +565 -0
  115. data/ext/swfmill/src/xslt/simple-svg.xslt +383 -0
  116. data/ext/swfmill/src/xslt/simple-tools.xslt +255 -0
  117. data/ext/swfmill/src/xslt/simple.cpp +1686 -0
  118. data/ext/swfmill/src/xslt/simple.xml +7 -0
  119. data/ext/swfmill/src/xslt/xslt.h +7 -0
  120. data/ext/swfmill/test/Makefile.am +1 -0
  121. data/ext/swfmill/test/Makefile.in +490 -0
  122. data/ext/swfmill/test/xml/Makefile.am +20 -0
  123. data/ext/swfmill/test/xml/Makefile.in +353 -0
  124. data/ext/swfmill/test/xml/test-xml +21 -0
  125. data/ext/swfmill_ext.cc +375 -0
  126. data/lib/swfmill.rb +30 -0
  127. data/spec/data/swfmill-banner1.swf +0 -0
  128. data/spec/spec.opts +1 -0
  129. data/spec/spec_helper.rb +14 -0
  130. data/spec/swfmill_spec.rb +125 -0
  131. metadata +206 -0
@@ -0,0 +1,255 @@
1
+ #include <libxslt/extensions.h>
2
+ #include <libxslt/xsltutils.h>
3
+ #include <libxslt/variables.h>
4
+ #include <libxml/xpathInternals.h>
5
+ #include "swft.h"
6
+ #include <sys/types.h>
7
+ #include <sys/stat.h>
8
+ #include <cstring>
9
+ #include "readpng.h"
10
+ #include <zlib.h>
11
+
12
+ #define TMP_STRLEN 0xff
13
+ const char jpeg_header[] = { 0xff, 0xd9, 0xff, 0xd8, 0 };
14
+
15
+ // defined in swft_import_png
16
+ bool compress( unsigned char *inputBuffer, int inLength, unsigned char *outputBuffer, int *outLength );
17
+
18
+
19
+ int getJpegWord( FILE *fp ) {
20
+ int r = fgetc(fp);
21
+ r <<= 8;
22
+ r += fgetc(fp);
23
+ return r;
24
+ }
25
+
26
+ void swft_import_jpeg( xmlXPathParserContextPtr ctx, int nargs ) {
27
+ xsltTransformContextPtr tctx;
28
+ unsigned char *filename;
29
+ xsltDocumentPtr xsltdoc;
30
+ xmlDocPtr doc = NULL;
31
+ xmlNodePtr node;
32
+ xmlXPathObjectPtr obj;
33
+ char tmp[TMP_STRLEN];
34
+
35
+ xmlXPathStringFunction(ctx, 1);
36
+ if (ctx->value->type != XPATH_STRING) {
37
+ xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL,
38
+ "swft:import-jpeg() : invalid arg expecting a string\n");
39
+ ctx->error = XPATH_INVALID_TYPE;
40
+ return;
41
+ }
42
+ obj = valuePop(ctx);
43
+ if (obj->stringval == NULL) {
44
+ valuePush(ctx, xmlXPathNewNodeSet(NULL));
45
+ return;
46
+ }
47
+
48
+ tctx = xsltXPathGetTransformContext(ctx);
49
+ filename = swft_get_filename( obj->stringval );
50
+
51
+ bool quiet = true;
52
+ xmlXPathObjectPtr quietObj = xsltVariableLookup( tctx, (const xmlChar*)"quiet", NULL );
53
+ if( quietObj && quietObj->stringval ) { quiet = !strcmp("true",(const char*)quietObj->stringval ); };
54
+
55
+
56
+ FILE *fp = fopen( (const char *)filename, "rb" );
57
+ if( !fp ) {
58
+ xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL,
59
+ "swft:import-jpeg() : failed to read file '%s'\n", (const char *)filename);
60
+ valuePush(ctx, xmlXPathNewNodeSet(NULL));
61
+ return;
62
+ }
63
+
64
+ doc = xmlNewDoc( (const xmlChar *)"1.0");
65
+ doc->xmlRootNode = xmlNewDocNode( doc, NULL, (const xmlChar *)"jpeg", NULL );
66
+ node = doc->xmlRootNode;
67
+
68
+ swft_addFileName( node, (const char *)filename );
69
+
70
+ // figure width/height
71
+ int width=-1, height=-1;
72
+ while( !feof( fp ) ) { // could do a && width==-1 here, but that captures preview imgs...
73
+ if( fgetc(fp) == 0xff ) {
74
+ if( fgetc(fp) == 0xc0 ) {
75
+ // StartOfFrame
76
+ // skip length and precision (UGLY, eh?)
77
+ fgetc(fp); fgetc(fp); fgetc(fp);
78
+
79
+ // read height, width
80
+ height = getJpegWord( fp );
81
+ width = getJpegWord( fp );
82
+ }
83
+ }
84
+ }
85
+ snprintf(tmp,TMP_STRLEN,"%i", width);
86
+ xmlSetProp( node, (const xmlChar *)"width", (const xmlChar *)&tmp );
87
+ snprintf(tmp,TMP_STRLEN,"%i", height);
88
+ xmlSetProp( node, (const xmlChar *)"height", (const xmlChar *)&tmp );
89
+
90
+ // add data
91
+ unsigned char *data = NULL;
92
+ int size, ofs;
93
+ struct stat filestat;
94
+ if( stat( (const char *)filename, &filestat ) ) goto fail;
95
+ size = filestat.st_size;
96
+
97
+ ofs = strlen(jpeg_header);
98
+
99
+ rewind(fp);
100
+ data = new unsigned char[size+ofs];
101
+ memcpy( data, jpeg_header, ofs );
102
+ if( fread( &data[ofs], 1, size, fp ) != size ) {
103
+ fprintf(stderr,"WARNING: could not read enough (%i) bytes for jpeg %s\n", size, filename );
104
+ goto fail;
105
+ }
106
+
107
+ if( !quiet ) {
108
+ fprintf(stderr,"Importing JPG: '%s'\n",filename);
109
+ }
110
+
111
+ swft_addData( node, (char*)data, size+ofs );
112
+ valuePush( ctx, xmlXPathNewNodeSet( (xmlNodePtr)doc ) );
113
+
114
+ fail:
115
+ if( fp ) fclose(fp);
116
+ if( data ) delete data;
117
+ }
118
+
119
+
120
+ void swft_import_jpega( xmlXPathParserContextPtr ctx, int nargs ) {
121
+ xsltTransformContextPtr tctx;
122
+ xmlChar *filename, *maskfilename;
123
+ xsltDocumentPtr xsltdoc;
124
+ xmlDocPtr doc = NULL;
125
+ xmlNodePtr node;
126
+ xmlXPathObjectPtr obj;
127
+ char tmp[TMP_STRLEN];
128
+
129
+ if( (nargs != 2) ) {
130
+ xmlXPathSetArityError(ctx);
131
+ return;
132
+ }
133
+
134
+ maskfilename = swft_get_filename( xmlXPathPopString(ctx) );
135
+ filename = swft_get_filename( xmlXPathPopString(ctx) );
136
+ if( xmlXPathCheckError(ctx) || (filename==NULL) || (maskfilename==NULL) ) {
137
+ return;
138
+ }
139
+
140
+ tctx = xsltXPathGetTransformContext(ctx);
141
+
142
+ FILE *fp = fopen( (const char *)filename, "rb" );
143
+ if( !fp ) {
144
+ xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL,
145
+ "swft:import-jpega() : failed to read file '%s'\n", (const char *)filename);
146
+ valuePush(ctx, xmlXPathNewNodeSet(NULL));
147
+ return;
148
+ }
149
+
150
+ doc = xmlNewDoc( (const xmlChar *)"1.0");
151
+ doc->xmlRootNode = xmlNewDocNode( doc, NULL, (const xmlChar *)"jpega", NULL );
152
+ node = doc->xmlRootNode;
153
+
154
+ swft_addFileName( node, (const char *)filename );
155
+
156
+ // figure width/height
157
+ int width=-1, height=-1;
158
+ while( !feof( fp ) ) { // could do a && width==-1 here, but that captures preview imgs...
159
+ if( fgetc(fp) == 0xff ) {
160
+ if( fgetc(fp) == 0xc0 ) {
161
+ // StartOfFrame
162
+ // skip length and precision (UGLY, eh?)
163
+ fgetc(fp); fgetc(fp); fgetc(fp);
164
+
165
+ // read height, width
166
+ height = getJpegWord( fp );
167
+ width = getJpegWord( fp );
168
+ }
169
+ }
170
+ }
171
+ snprintf(tmp,TMP_STRLEN,"%i", width);
172
+ xmlSetProp( node, (const xmlChar *)"width", (const xmlChar *)&tmp );
173
+ snprintf(tmp,TMP_STRLEN,"%i", height);
174
+ xmlSetProp( node, (const xmlChar *)"height", (const xmlChar *)&tmp );
175
+
176
+ // add data
177
+ unsigned char *jpegdata = NULL;
178
+ unsigned char *data = NULL;
179
+ int data_size, mask_size;
180
+ int size, ofs;
181
+ struct stat filestat;
182
+ unsigned char *maskdata;
183
+ unsigned long maskw, maskh, rowbytes;
184
+ int channels;
185
+ png_colorp palette;
186
+ int n_pal;
187
+ unsigned char *mask;
188
+ if( stat( (const char *)filename, &filestat ) ) goto fail;
189
+ size = filestat.st_size;
190
+
191
+ ofs = strlen(jpeg_header);
192
+
193
+ rewind(fp);
194
+ jpegdata = new unsigned char[size+ofs];
195
+ memcpy( jpegdata, jpeg_header, ofs );
196
+ if( fread( &jpegdata[ofs], 1, size, fp ) != size ) {
197
+ fprintf(stderr,"WARNING: could not read enough (%i) bytes for jpeg %s\n", size, filename );
198
+ goto fail;
199
+ }
200
+
201
+ snprintf(tmp,TMP_STRLEN,"%i", size+ofs);
202
+ xmlSetProp( node, (const xmlChar *)"offset_to_alpha", (const xmlChar *)&tmp );
203
+
204
+ fclose(fp);
205
+
206
+ // jpegdata is filled, now read the mask png.
207
+ fp = fopen( (const char *)maskfilename, "rb" );
208
+ if( !fp ) {
209
+ xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL,
210
+ "swft:import-jpega() : failed to read mask file '%s'\n", (const char *)maskfilename);
211
+ valuePush(ctx, xmlXPathNewNodeSet(NULL));
212
+ goto fail;
213
+ }
214
+
215
+ data_size = size + ofs + (width*height);
216
+ data = new unsigned char[ data_size ];
217
+ memcpy( data, jpegdata, size+ofs );
218
+ maskdata = &data[ size+ofs ];
219
+
220
+ if( readpng_init( fp, &maskw, &maskh ) ) goto fail;
221
+
222
+ if( maskw != width || maskh != height ) {
223
+ xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL,
224
+ "swft:import-jpega() : mask has different size than jpeg image: %i/%i and %i/%i\n", width, height, maskw, maskh );
225
+ valuePush(ctx, xmlXPathNewNodeSet(NULL));
226
+ goto fail;
227
+ }
228
+
229
+ mask = readpng_get_image( 2.2, &channels, &rowbytes, &palette, &n_pal );
230
+ if( channels != 1 || rowbytes != width ) {
231
+ xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL,
232
+ "swft:import-jpega() : mask is not 8bit grayscale\n");
233
+ valuePush(ctx, xmlXPathNewNodeSet(NULL));
234
+ goto fail;
235
+ }
236
+
237
+ mask_size = data_size;
238
+ if( compress( mask, width*height, maskdata, &mask_size ) ) {
239
+ data_size = size + ofs + mask_size;
240
+ } else {
241
+ xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL,
242
+ "swft:import-jpega() : could not compress mask\n" );
243
+ valuePush(ctx, xmlXPathNewNodeSet(NULL));
244
+ goto fail;
245
+ }
246
+
247
+ swft_addData( node, (char*)data, data_size );
248
+ valuePush( ctx, xmlXPathNewNodeSet( (xmlNodePtr)doc ) );
249
+
250
+ fail:
251
+ if( fp ) fclose(fp);
252
+ if( data ) delete data;
253
+ if( jpegdata ) delete jpegdata;
254
+ }
255
+
@@ -0,0 +1,268 @@
1
+ #include <libxslt/extensions.h>
2
+ #include <libxslt/xsltutils.h>
3
+ #include <libxslt/variables.h>
4
+ #include <libxml/xpathInternals.h>
5
+ #include "swft.h"
6
+ #include <sys/types.h>
7
+ #include <sys/stat.h>
8
+ #include <cstring>
9
+
10
+ #define TMP_STRLEN 0xff
11
+
12
+ #define ERROR_NO_MP3 -1
13
+ #define ERROR_WRONG_SAMPLING_RATE -2
14
+
15
+ enum {
16
+ MPEG_V25 = 0,
17
+ MPEG_RESERVED,
18
+ MPEG_V2,
19
+ MPEG_V1,
20
+ };
21
+
22
+ const int mpegVersionBitrate[] = {
23
+ 1, // V2.5, bitrates same as V2
24
+ -1,
25
+ 1, // V2
26
+ 0 // V1
27
+ };
28
+
29
+ // Only Layer3 is supported
30
+ const int mp3Bitrates[][15] = {
31
+ {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}, // V1
32
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, // V2 & V2.5
33
+ };
34
+
35
+
36
+ /* As required in DefineSound, as a function of mpegVersion */
37
+ const int flashSamplingRates[] = {
38
+ 1, // V25 -> 11025,
39
+ -1, // dummy
40
+ 2, // V2 -> 22050,
41
+ 3, // V1 -> 44100;
42
+ };
43
+
44
+
45
+ const int samplingRates[][4] = {
46
+ {11025, 12000, 8000, -1}, // V2.5
47
+ { -1, -1, -1, -1}, // dummy
48
+ {22050, 24000, 12000, -1}, // V2
49
+ {44100, 48000, 32000, -1}, // V1
50
+ };
51
+
52
+ struct MP3Info {
53
+ int samplingRate;
54
+ int samplesPerFrame;
55
+ int flashSamplingRateFlag;
56
+ int frames;
57
+ int stereo;
58
+ bool validMP3;
59
+ bool wrongSamplingRate;
60
+ };
61
+
62
+ int findFrame( const unsigned char* data, int size, int start ) {
63
+ int pos = start;
64
+
65
+ while( pos < size ) {
66
+ if( data[pos] == 0xFF && (data[pos + 1] & 0xE0) == 0xE0 ) {
67
+ return pos;
68
+ }
69
+ pos++;
70
+ }
71
+
72
+ return -1;
73
+ }
74
+
75
+ int getFrameSize( const unsigned char* data, int size, int pos, MP3Info &info) {
76
+ if( pos + 2 >= size ) {
77
+ return ERROR_NO_MP3;
78
+ }
79
+
80
+ unsigned char c = data[pos + 1];
81
+ int mpegVersion = (c & 0x18) >> 3; // 0:V2.5 1:reserved 2:V2 3:V1
82
+ int layer = (c & 0x06) >> 1; // 1 means Layer III
83
+
84
+ // An MP3 file is Layer III, MPEG version any
85
+ if( layer != 1) {
86
+ fprintf(stderr, "Error: Layer should be III.\n");
87
+ return ERROR_NO_MP3;
88
+ }
89
+
90
+ if (mpegVersion == MPEG_RESERVED) {
91
+ fprintf(stderr, "Error: Unknown MPEG version (reserved).\n");
92
+ return ERROR_NO_MP3;
93
+ }
94
+
95
+ c = data[pos + 2];
96
+ int bitrate = (c & 0xF0) >> 4;
97
+ int samplingRate = (c & 0x0C) >> 2;
98
+ int padding = (c & 0x02) >> 1;
99
+
100
+ if (bitrate > 14) {
101
+ fprintf(stderr, "MP3 bitrate field invalid. Corrupt MP3 file?");
102
+ return ERROR_NO_MP3;
103
+ }
104
+
105
+ info.samplingRate = samplingRates[mpegVersion][samplingRate];
106
+ info.flashSamplingRateFlag = flashSamplingRates[mpegVersion];
107
+
108
+ if( samplingRate != 0 ) {
109
+ fprintf(stderr, "Sampling rate: %d\n", info.samplingRate);
110
+ fprintf(stderr, "Error: Flash only supports sampling rates of 44100, 22050 and 11025 Hz\n");
111
+ return ERROR_WRONG_SAMPLING_RATE;
112
+ }
113
+
114
+ info.samplesPerFrame = mpegVersion == MPEG_V1 ? 1152 : 576; // Since we deal with Layer III only
115
+
116
+ //Calculate the frame size in bytes
117
+ int br_table = mpegVersionBitrate[mpegVersion];
118
+ int frameSize = (info.samplesPerFrame / 8) * (mp3Bitrates[br_table][bitrate] * 1000) / info.samplingRate + padding;
119
+
120
+ return frameSize;
121
+ }
122
+
123
+ void getMP3Info( MP3Info& info, const unsigned char* data, int size ) {
124
+ info.frames = 0;
125
+ info.stereo = 0;
126
+ info.validMP3 = true;
127
+ info.wrongSamplingRate = false;
128
+ int pos = 0;
129
+ bool first = true;
130
+
131
+ while( (pos = findFrame( data, size, pos)) >= 0 ) {
132
+ int frameSize = getFrameSize( data, size, pos, info );
133
+ if( frameSize > 0 ) {
134
+ if( first ) {
135
+ if(pos + 3 < size) {
136
+ if((data[pos + 3] & 0xC0) != 0xC0)
137
+ info.stereo = 1;
138
+ }
139
+ first = false;
140
+ }
141
+
142
+ pos += frameSize;
143
+ info.frames++;
144
+ } else {
145
+ if ( frameSize == ERROR_WRONG_SAMPLING_RATE ) {
146
+ info.wrongSamplingRate = true;
147
+ } else {
148
+ info.validMP3 = false;
149
+ }
150
+ return;
151
+ }
152
+ }
153
+
154
+ //no frames found -> no valid mp3
155
+ if( info.frames == 0 ) {
156
+ info.validMP3 = false;
157
+ }
158
+ }
159
+
160
+
161
+ void swft_import_mp3( xmlXPathParserContextPtr ctx, int nargs ) {
162
+ xsltTransformContextPtr tctx;
163
+ xmlChar *filename;
164
+ xsltDocumentPtr xsltdoc;
165
+ xmlDocPtr doc = NULL;
166
+ xmlNodePtr node;
167
+ xmlXPathObjectPtr obj;
168
+ char tmp[TMP_STRLEN];
169
+ //data variables
170
+ unsigned char *data = NULL;
171
+ int size;
172
+ struct stat filestat;
173
+
174
+ xmlXPathStringFunction(ctx, 1);
175
+ if (ctx->value->type != XPATH_STRING) {
176
+ xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL,
177
+ "swft:import-mp3() : invalid arg expecting a string\n");
178
+ ctx->error = XPATH_INVALID_TYPE;
179
+ return;
180
+ }
181
+ obj = valuePop(ctx);
182
+ if (obj->stringval == NULL) {
183
+ valuePush(ctx, xmlXPathNewNodeSet(NULL));
184
+ return;
185
+ }
186
+
187
+ tctx = xsltXPathGetTransformContext(ctx);
188
+
189
+ filename = obj->stringval;
190
+
191
+ bool quiet = true;
192
+ xmlXPathObjectPtr quietObj = xsltVariableLookup( tctx, (const xmlChar*)"quiet", NULL );
193
+ if( quietObj && quietObj->stringval ) { quiet = !strcmp("true",(const char*)quietObj->stringval ); };
194
+
195
+
196
+ FILE *fp = fopen( (const char *)filename, "rb" );
197
+ if( !fp ) {
198
+ xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL,
199
+ "swft:import-mp3() : failed to read file '%s'\n", (const char *)filename);
200
+ valuePush(ctx, xmlXPathNewNodeSet(NULL));
201
+ return;
202
+ }
203
+
204
+ doc = xmlNewDoc( (const xmlChar *)"1.0");
205
+ doc->xmlRootNode = xmlNewDocNode( doc, NULL, (const xmlChar *)"mp3", NULL );
206
+ node = doc->xmlRootNode;
207
+
208
+ swft_addFileName( node, (const char *)filename );
209
+
210
+ // get file size
211
+ if( stat( (const char *)filename, &filestat ) ) goto fail;
212
+ size = filestat.st_size;
213
+
214
+ // flash requires an initial latency value in front of the mp3 data
215
+ // TODO: check the meaning of this value and set it correctly
216
+ data = new unsigned char[size + 2];
217
+ data[0] = 0;
218
+ data[1] = 0;
219
+
220
+ // read data
221
+ if( fread( &data[2], 1, size, fp ) != size ) {
222
+ fprintf(stderr,"WARNING: could not read enough (%i) bytes for MP3 %s\n", size, filename );
223
+ goto fail;
224
+ }
225
+
226
+ if( size == 0 ) {
227
+ fprintf(stderr,"WARNING: MP3 %s is empty\n", filename );
228
+ goto fail;
229
+ }
230
+
231
+ MP3Info info;
232
+ getMP3Info( info, &data[2], size );
233
+
234
+ if( !info.validMP3 ) {
235
+ fprintf(stderr,"WARNING: this file is not a valid MP3 %s\n", filename );
236
+ goto fail;
237
+ }
238
+
239
+ if( info.wrongSamplingRate ) {
240
+ fprintf(stderr,"WARNING: MP3 file %s has a wrong sampling rate\n", filename );
241
+ goto fail;
242
+ }
243
+
244
+ xmlSetProp( node, (const xmlChar *)"format", (const xmlChar *)"2" ); //MP3
245
+
246
+ snprintf(tmp,TMP_STRLEN,"%i", info.flashSamplingRateFlag);
247
+ xmlSetProp( node, (const xmlChar *)"rate", (const xmlChar *)&tmp );
248
+
249
+ xmlSetProp( node, (const xmlChar *)"is16bit", (const xmlChar *)"1" ); //MP3 is always 16bit
250
+
251
+ snprintf(tmp,TMP_STRLEN,"%i", info.stereo);
252
+ xmlSetProp( node, (const xmlChar *)"stereo", (const xmlChar *)&tmp );
253
+
254
+ snprintf(tmp,TMP_STRLEN,"%i", info.frames * info.samplesPerFrame);
255
+ xmlSetProp( node, (const xmlChar *)"samples", (const xmlChar *)&tmp );
256
+
257
+ if( !quiet ) {
258
+ fprintf(stderr, "Importing MP3: '%s'\n", filename);
259
+ }
260
+
261
+ swft_addData( node, (char*)data, size + 2 );
262
+ valuePush( ctx, xmlXPathNewNodeSet( (xmlNodePtr)doc ) );
263
+
264
+ fail:
265
+ if( fp ) fclose(fp);
266
+ if( data ) delete data;
267
+ }
268
+