swfmill 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+