1 /*
2 * MP3val - a program for MPEG audio file validation
3 * Copyright (C) 2005-2009 Alexey Kuznetsov (ring0) and Eugen Tikhonov (jetsys)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include "crossapi.h"
21 #include "mpegparse.h"
22 #include "report.h"
23 #include "out.h"
24 #include "crc.h"
25 #include <cstring>
26 #include <iostream>
27 #include <fstream>
28
29 using namespace std;
30
31 int mpeg1layer1_bitrates[]={-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448,-1};
32 int mpeg1layer2_bitrates[]={-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384,-1};
33 int mpeg1layer3_bitrates[]={-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1};
34 int mpeg2layer1_bitrates[]={-1,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1};
35 int mpeg2layers23_bitrates[]={-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1};
36
37 int ValidateMPEGFrame(unsigned char *baseptr,int index, MPEGINFO *mpginfo);
38 int CheckMP3CRC(unsigned char *baseptr,int index,MPEGINFO *mpginfo,bool fix);
39 int ValidateID3v2Tag(unsigned char *baseptr,int index, MPEGINFO *mpginfo);
40 int ValidateAPEv2Tag(unsigned char *baseptr,int index, MPEGINFO *mpginfo);
41
42 int ParseXingHeader(unsigned char *baseptr,int index,MPEGINFO *mpginfo);
43 int ParseVBRIHeader(unsigned char *baseptr,int index,MPEGINFO *mpginfo);
44
45 int ParseRIFFHeader(unsigned char *baseptr,int index,int iFileSize,int *iNewFileSize);
46
47 int MPEGResync(unsigned char *baseptr,int index,int iFileSize,int frames);
48
49 DWORD rotate_dword(DWORD x);
50
ValidateFile(unsigned char * baseptr,int iFileSize,MPEGINFO * mpginfo,ostream * out,char * filename,bool fix,int hFile)51 int ValidateFile(unsigned char *baseptr,int iFileSize,MPEGINFO *mpginfo,ostream *out,char *filename,bool fix,int hFile) {
52 int iFrame;
53 int iFrameSize=0;
54 int iLastMPEGFrame=0,iNewFrame;
55 bool WasFirstFrame=false;
56 int iXingOffset=0;
57 int iID3v1Offset=0;
58 int iFirstMPEGFrameOffset=0;
59 DWORD dwTemp;
60 int mpeg_total;
61 bool LastFrameWasMPEG=false;
62
63 iFrame=0;
64
65 mpginfo->clear();
66
67 if(iFileSize>=128&&!memcmp(&baseptr[iFileSize-128],"TAG",3)) {
68 mpginfo->id3v1=1;
69 iFileSize-=128;
70 iID3v1Offset=iFileSize;
71 }
72
73 if((iFileSize>=4)&&!memcmp(&baseptr[iFrame],"ID3",3)) {
74 if(iFrame+10>iFileSize) {
75 mpginfo->truncated=iFrame;
76 }
77 else {
78 iFrame+=ValidateID3v2Tag(baseptr,iFrame,mpginfo);
79 if(fix) {
80 if(WriteToFile(hFile,(char *)baseptr,0,iFrame,iFileSize)==-1) return -1;
81 LastFrameWasMPEG=false;
82 }
83 }
84 }
85
86 while(iFrame!=iFileSize) {
87 if(iFrame+4>iFileSize) {
88 //Bad (unknown) frame
89 mpginfo->truncated=iFrame;
90 break;
91 }
92 if(!memcmp(&baseptr[iFrame],"RIFF",4)) {
93 if(!WasFirstFrame) {
94 //This is actually a WAV file, not MPEG. Parsing RIFF header
95 mpginfo->riff=iFrame;
96 iNewFrame=ParseRIFFHeader(baseptr,iFrame,iFileSize,&iFileSize);
97 if(iNewFrame!=-1) {
98 iFrame=iNewFrame;
99 continue;
100 }
101 }
102 }
103
104 if((baseptr[iFrame]==0xFF)&&((baseptr[iFrame+1]&0xE0)==0xE0)) {
105 //MPEG frame
106 iFrameSize=ValidateMPEGFrame(baseptr,iFrame,mpginfo);
107 if(iFrameSize!=-1) {
108 if(iFrameSize+iFrame<=iFileSize&&mpginfo->iLastMPEGLayer==3&&mpginfo->bLastFrameCRC) CheckMP3CRC(baseptr,iFrame,mpginfo,fix);
109 if(fix&&!WasFirstFrame) iFirstMPEGFrameOffset=CrossAPI_SetFilePointer(hFile,0,true);
110 if(fix) {
111 if(WriteToFile(hFile,(char *)baseptr,iFrame,iFrameSize,iFileSize)==-1) return -1;
112 LastFrameWasMPEG=true;
113 }
114 if(!WasFirstFrame) {
115 WasFirstFrame=true;
116 mpginfo->iFirstMPEGFrameSize=iFrameSize;
117 if(mpginfo->iLastMPEGVersion==1) {
118 if(mpginfo->LastFrameStereo) {
119 iXingOffset=32;
120 }
121 else {
122 iXingOffset=17;
123 }
124 }
125 else {
126 if(mpginfo->LastFrameStereo) {
127 iXingOffset=17;
128 }
129 else {
130 iXingOffset=9;
131 }
132 }
133 ParseXingHeader(baseptr,iFrame+4+iXingOffset,mpginfo);
134 if(!mpginfo->VBRHeaderPresent) ParseVBRIHeader(baseptr,iFrame+4+32,mpginfo);
135 }
136 iLastMPEGFrame=iFrame;
137 iFrame+=iFrameSize;
138 continue;
139 }
140 }
141 //APEv2 tag
142 if(!memcmp(&baseptr[iFrame],"APET",4)) {
143 if(iFrame+16>iFileSize) {
144 mpginfo->truncated=iFrame;
145 break;
146 }
147 iFrameSize=ValidateAPEv2Tag(baseptr,iFrame,mpginfo);
148 if(fix) {
149 if(WriteToFile(hFile,(char *)baseptr,iFrame,iFrameSize,iFileSize)==-1) return -1;
150 LastFrameWasMPEG=false;
151 }
152 iFrame+=iFrameSize;
153 continue;
154 }
155
156 if(fix) {
157 if(LastFrameWasMPEG) {
158 mpginfo->iDeletedFrames++;
159 mpginfo->iTotalMPEGBytes-=WriteToFile(hFile,NULL,0,-1,-1);
160 }
161 /* else {
162 if(WriteToFile(hFile,NULL,0,-1,-1)==-1) return -1;
163 }*/
164 }
165 else if(LastFrameWasMPEG) {
166 mpginfo->iDeletedFrames++;
167 mpginfo->iTotalMPEGBytes-=GetLastFrameSize();
168 }
169
170 if(!iFrame) {
171 iNewFrame=MPEGResync(baseptr,iFrame,iFileSize,8);
172 if(iNewFrame==-1) {
173 mpginfo->unknown_format=0;
174 break;
175 }
176 mpginfo->garbage_at_the_begin=0;
177 if(!fix) PrintMessage(out,"WARNING",filename,"Garbage at the beginning of the file",mpginfo->garbage_at_the_begin);
178 mpginfo->iErrors++;
179 iFrame=iNewFrame;
180 }
181 else {
182 iNewFrame=MPEGResync(baseptr,iLastMPEGFrame?(iLastMPEGFrame+1):iFrame,iFileSize,6);
183 if(iNewFrame==-1) {
184 mpginfo->garbage_at_the_end=iFrame;
185 if(!fix) PrintMessage(out,"WARNING",filename,"Garbage at the end of the file",mpginfo->garbage_at_the_end);
186 mpginfo->iErrors++;
187 break;
188 }
189 mpginfo->mpeg_stream_error=iFrame;
190 if(!fix) PrintMessage(out,"WARNING",filename,"MPEG stream error, resynchronized successfully",mpginfo->mpeg_stream_error);
191 mpginfo->iErrors++;
192 iFrame=iNewFrame;
193 }
194
195 }
196
197 mpeg_total=
198 mpginfo->mpeg1layer1+
199 mpginfo->mpeg1layer2+
200 mpginfo->mpeg1layer3+
201 mpginfo->mpeg2layer1+
202 mpginfo->mpeg2layer2+
203 mpginfo->mpeg2layer3+
204 mpginfo->mpeg25layer1+
205 mpginfo->mpeg25layer2+
206 mpginfo->mpeg25layer3;
207
208 if(mpginfo->truncated>=0) {
209 if(fix) {
210 if(WriteToFile(hFile,NULL,0,-1,-1)==-1) return -1;
211 if(LastFrameWasMPEG) {
212 mpginfo->iTotalMPEGBytes-=iFrameSize;
213 mpginfo->iDeletedFrames++;
214 }
215 }
216 else if(LastFrameWasMPEG) {
217 mpginfo->iTotalMPEGBytes-=iFrameSize;
218 mpginfo->iDeletedFrames++;
219 }
220 }
221
222 if(fix&&mpginfo->id3v1) {
223 if(WriteToFile(hFile,(char *)baseptr,iID3v1Offset,128,-1)==-1) return -1;
224 }
225
226 if(fix) CrossAPI_SetEndOfFile(hFile);
227
228 if(fix&&mpginfo->VBRHeaderPresent) {
229 if(mpginfo->IsXingHeader) {
230 if(mpginfo->BytesPresent&&mpginfo->FramesPresent) {
231 CrossAPI_SetFilePointer(hFile,iFirstMPEGFrameOffset+iXingOffset+12,false);
232 dwTemp=rotate_dword(mpeg_total-mpginfo->iDeletedFrames);
233 if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1;
234 dwTemp=rotate_dword(mpginfo->iTotalMPEGBytes);
235 if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1;
236 }
237 else if(mpginfo->BytesPresent) {
238 CrossAPI_SetFilePointer(hFile,iFirstMPEGFrameOffset+iXingOffset+12,false);
239 dwTemp=rotate_dword(mpginfo->iTotalMPEGBytes);
240 if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1;
241 }
242 else if(mpginfo->FramesPresent) {
243 CrossAPI_SetFilePointer(hFile,iFirstMPEGFrameOffset+iXingOffset+12,false);
244 dwTemp=rotate_dword(mpeg_total-mpginfo->iDeletedFrames);
245 if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1;
246 }
247 }
248 else {
249 CrossAPI_SetFilePointer(hFile,iFirstMPEGFrameOffset+46,false);
250 dwTemp=rotate_dword(mpginfo->iTotalMPEGBytes);
251 if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1;
252 dwTemp=rotate_dword(mpeg_total-mpginfo->iDeletedFrames);
253 if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1;
254 }
255 }
256
257 if(fix) mpginfo->iErrors=1;
258
259 return 0;
260 }
261
ValidateMPEGFrame(unsigned char * baseptr,int index,MPEGINFO * mpginfo)262 int ValidateMPEGFrame(unsigned char *baseptr,int index, MPEGINFO *mpginfo) {
263 int mpeg_version, mpeg_layer;
264 int mpeg_bitrate, mpeg_sampling_rate, mpeg_padding;
265
266 int bitrate_index=0;
267 int iFrameSize;
268
269 //Check if the frame contains CRC
270 if(baseptr[index+1]&0x01) {
271 mpginfo->bLastFrameCRC=false;
272 }
273 else {
274 mpginfo->bLastFrameCRC=true;
275 mpginfo->bCRC=true;
276 }
277
278 // Determine MPEG version and layer
279 switch((baseptr[index+1]>>1)&0x0F) {
280 case 0x0F:
281 mpginfo->mpeg1layer1++;
282 mpeg_version=1;
283 mpeg_layer=1;
284 break;
285 case 0x0E:
286 mpginfo->mpeg1layer2++;
287 mpeg_version=1;
288 mpeg_layer=2;
289 break;
290 case 0x0D:
291 mpginfo->mpeg1layer3++;
292 mpeg_version=1;
293 mpeg_layer=3;
294 break;
295 case 0x0B:
296 mpginfo->mpeg2layer1++;
297 mpeg_version=2;
298 mpeg_layer=1;
299 break;
300 case 0x0A:
301 mpginfo->mpeg2layer2++;
302 mpeg_version=2;
303 mpeg_layer=2;
304 break;
305 case 0x09:
306 mpginfo->mpeg2layer3++;
307 mpeg_version=2;
308 mpeg_layer=3;
309 break;
310 case 0x03:
311 mpginfo->mpeg25layer1++;
312 mpeg_version=25;
313 mpeg_layer=1;
314 break;
315 case 0x02:
316 mpginfo->mpeg25layer2++;
317 mpeg_version=25;
318 mpeg_layer=2;
319 break;
320 case 0x01:
321 mpginfo->mpeg25layer3++;
322 mpeg_version=25;
323 mpeg_layer=3;
324 break;
325 default:
326 mpginfo->mpeg_stream_error=index;
327 return -1;
328 }
329 // Calculate bit rate
330 *((unsigned char *)&bitrate_index)=((baseptr[index+2])>>4)&0x0F;
331 if(mpeg_version==1) {
332 if(mpeg_layer==1) {
333 mpeg_bitrate=mpeg1layer1_bitrates[bitrate_index];
334 }
335 else if(mpeg_layer==2) {
336 mpeg_bitrate=mpeg1layer2_bitrates[bitrate_index];
337 }
338 else {
339 mpeg_bitrate=mpeg1layer3_bitrates[bitrate_index];
340 }
341 }
342 else {
343 if(mpeg_layer==1) {
344 mpeg_bitrate=mpeg2layer1_bitrates[bitrate_index];
345 }
346 else {
347 mpeg_bitrate=mpeg2layers23_bitrates[bitrate_index];
348 }
349 }
350
351 if(mpeg_bitrate==-1) {
352 mpginfo->mpeg_stream_error=index;
353 return -1;
354 }
355
356 if(mpginfo->iLastBitrate>0&&mpginfo->iLastBitrate!=mpeg_bitrate) mpginfo->bVariableBitrate=true;
357 mpginfo->iLastBitrate=mpeg_bitrate;
358
359 //Determine sampling rate
360 switch((baseptr[index+2]>>2)&0x03) {
361 case 0x00:
362 if(mpeg_version==1) mpeg_sampling_rate=44100;
363 else if(mpeg_version==2) mpeg_sampling_rate=22050;
364 else mpeg_sampling_rate=11025;
365 break;
366 case 0x01:
367 if(mpeg_version==1) mpeg_sampling_rate=48000;
368 else if(mpeg_version==2) mpeg_sampling_rate=24000;
369 else mpeg_sampling_rate=12000;
370 break;
371 case 0x02:
372 if(mpeg_version==1) mpeg_sampling_rate=32000;
373 else if(mpeg_version==2) mpeg_sampling_rate=16000;
374 else mpeg_sampling_rate=8000;
375 break;
376 default:
377 mpginfo->mpeg_stream_error=index;
378 return -1;
379 }
380
381 //Check if padding is being used
382 if((baseptr[index+2]>>1)&0x01) mpeg_padding=1;
383 else mpeg_padding=0;
384
385 //Check if frame is stereo
386 if((baseptr[index+3]&0xC0)==0xC0) mpginfo->LastFrameStereo=false;
387 else mpginfo->LastFrameStereo=true;
388
389 mpginfo->iLastMPEGVersion=mpeg_version;
390 mpginfo->iLastMPEGLayer=mpeg_layer;
391
392 if(mpeg_layer==1) iFrameSize=(12*mpeg_bitrate*1000/mpeg_sampling_rate+mpeg_padding)*4;
393 else if(mpeg_layer==2) iFrameSize=144*mpeg_bitrate*1000/mpeg_sampling_rate+mpeg_padding;
394 else if(mpeg_layer==3&&mpeg_version==1) iFrameSize=144*mpeg_bitrate*1000/mpeg_sampling_rate+mpeg_padding;
395 else iFrameSize=72*mpeg_bitrate*1000/mpeg_sampling_rate+mpeg_padding;
396
397 mpginfo->iTotalMPEGBytes+=iFrameSize;
398
399 return iFrameSize;
400 }
401
CheckMP3CRC(unsigned char * baseptr,int index,MPEGINFO * mpginfo,bool fix)402 int CheckMP3CRC(unsigned char *baseptr,int index,MPEGINFO *mpginfo,bool fix) {
403 int crc=0xFFFF;
404 int storedcrc=0;
405 int iSideInfoSize;
406 crc=CalculateCRC16(crc,0x8005,(char *)&baseptr[index+2],2);
407
408 if(mpginfo->LastFrameStereo) {
409 if(mpginfo->iLastMPEGVersion==1) {
410 iSideInfoSize=32;
411 }
412 else {
413 iSideInfoSize=17;
414 }
415 }
416 else {
417 if(mpginfo->iLastMPEGVersion==1) {
418 iSideInfoSize=17;
419 }
420 else {
421 iSideInfoSize=9;
422 }
423 }
424
425 crc=CalculateCRC16(crc,0x8005,(char *)&baseptr[index+6],iSideInfoSize);
426
427 ((char *)&storedcrc)[1]=baseptr[index+4];
428 ((char *)&storedcrc)[0]=baseptr[index+5];
429
430 if(storedcrc!=crc) {
431 mpginfo->bCRCError=true;
432 mpginfo->iCRCErrors++;
433 if(fix) {
434 baseptr[index+4]=((char *)&crc)[1];
435 baseptr[index+5]=((char *)&crc)[0];
436 }
437 }
438
439 return 0;
440 }
441
ValidateID3v2Tag(unsigned char * baseptr,int index,MPEGINFO * mpginfo)442 int ValidateID3v2Tag(unsigned char *baseptr,int index, MPEGINFO *mpginfo) {
443 int iDataSize;
444
445 mpginfo->id3v2++;
446
447 iDataSize=baseptr[index+9];
448 iDataSize+=128*baseptr[index+8];
449 iDataSize+=16384*baseptr[index+7];
450 iDataSize+=2097152*baseptr[index+6];
451
452 if(baseptr[index+5]&0x10) return iDataSize+20;
453 return iDataSize+10;
454 }
455
ValidateAPEv2Tag(unsigned char * baseptr,int index,MPEGINFO * mpginfo)456 int ValidateAPEv2Tag(unsigned char *baseptr,int index, MPEGINFO *mpginfo) {
457 mpginfo->apev2++;
458 return *((int *)&baseptr[index+12])+32;
459 }
460
MPEGResync(unsigned char * baseptr,int index,int iFileSize,int frames)461 int MPEGResync(unsigned char *baseptr,int index,int iFileSize,int frames) {
462 unsigned char *p=&baseptr[index];
463 int sync_frames=0;
464 int new_frame=0;
465 int iFrameSize;
466 MPEGINFO tmp_mpginfo;
467 int iMPEGVersion=0,iMPEGLayer=0;
468
469 do {
470 if(iFileSize-(p-baseptr)-3<=0) return -1;
471 p=(unsigned char *)memchr(p,'\xFF',iFileSize-(p-baseptr)-3);
472 if(!p) break;
473 if((p[1]&0xE0)!=0xE0) {
474 p++;
475 sync_frames=0;
476 iMPEGVersion=0;
477 iMPEGLayer=0;
478 continue;
479 }
480 iFrameSize=ValidateMPEGFrame(baseptr,p-baseptr,&tmp_mpginfo);
481 if(iFrameSize==-1) {
482 p++;
483 sync_frames=0;
484 iMPEGVersion=0;
485 iMPEGLayer=0;
486 continue;
487 }
488 new_frame=iFrameSize+(p-baseptr);
489 sync_frames++;
490 iMPEGVersion=tmp_mpginfo.iLastMPEGVersion;
491 iMPEGLayer=tmp_mpginfo.iLastMPEGLayer;
492 while(sync_frames<frames) {
493 if(new_frame+4>iFileSize) {
494 sync_frames=0;
495 iMPEGVersion=0;
496 iMPEGLayer=0;
497 p++;
498 break;
499 }
500 iFrameSize=ValidateMPEGFrame(baseptr,new_frame,&tmp_mpginfo);
501 if(iFrameSize==-1) {
502 sync_frames=0;
503 iMPEGVersion=0;
504 iMPEGLayer=0;
505 p++;
506 break;
507 }
508 new_frame+=iFrameSize;
509 sync_frames++;
510 if(iMPEGVersion&&iMPEGVersion!=tmp_mpginfo.iLastMPEGVersion) {
511 sync_frames=0;
512 iMPEGVersion=0;
513 iMPEGLayer=0;
514 p++;
515 break;
516 }
517 if(iMPEGLayer&&iMPEGLayer!=tmp_mpginfo.iLastMPEGLayer) {
518 sync_frames=0;
519 iMPEGVersion=0;
520 iMPEGLayer=0;
521 p++;
522 break;
523 }
524 }
525 } while(sync_frames<frames);
526
527 if(sync_frames>=frames) return (p-baseptr);
528 return -1;
529 }
530
ParseXingHeader(unsigned char * baseptr,int index,MPEGINFO * mpginfo)531 int ParseXingHeader(unsigned char *baseptr,int index,MPEGINFO *mpginfo) {
532 if(memcmp(&baseptr[index],"Xing",4)&&memcmp(&baseptr[index],"Info",4)) return 0;
533 mpginfo->VBRHeaderPresent=true;
534 mpginfo->IsXingHeader=true;
535 switch(baseptr[index+7]&0x03) {
536 case 0x00:
537 return 0;
538 case 0x01:
539 mpginfo->iFrames=16777216*baseptr[index+8]+65536*baseptr[index+9]+256*baseptr[index+10]+baseptr[index+11];
540 mpginfo->FramesPresent=true;
541 mpginfo->BytesPresent=false;
542 return 0;
543 case 0x02:
544 mpginfo->iBytes=16777216*baseptr[index+8]+65536*baseptr[index+9]+256*baseptr[index+10]+baseptr[index+11];
545 mpginfo->FramesPresent=false;
546 mpginfo->BytesPresent=true;
547 return 0;
548 case 0x03:
549 mpginfo->iFrames=16777216*baseptr[index+8]+65536*baseptr[index+9]+256*baseptr[index+10]+baseptr[index+11];
550 mpginfo->iBytes=16777216*baseptr[index+12]+65536*baseptr[index+13]+256*baseptr[index+14]+baseptr[index+15];
551 mpginfo->FramesPresent=true;
552 mpginfo->BytesPresent=true;
553 return 0;
554 }
555
556 return 0;
557 }
558
ParseVBRIHeader(unsigned char * baseptr,int index,MPEGINFO * mpginfo)559 int ParseVBRIHeader(unsigned char *baseptr,int index,MPEGINFO *mpginfo) {
560 if(memcmp(&baseptr[index],"VBRI",4)) return 0;
561 mpginfo->VBRHeaderPresent=true;
562 mpginfo->IsXingHeader=false;
563 mpginfo->iBytes=16777216*baseptr[index+10]+65536*baseptr[index+11]+256*baseptr[index+12]+baseptr[index+13];
564 mpginfo->iFrames=16777216*baseptr[index+14]+65536*baseptr[index+15]+256*baseptr[index+16]+baseptr[index+17];
565 mpginfo->FramesPresent=true;
566 mpginfo->BytesPresent=true;
567 return 0;
568 }
569
ParseRIFFHeader(unsigned char * baseptr,int index,int iFileSize,int * iNewFileSize)570 int ParseRIFFHeader(unsigned char *baseptr,int index,int iFileSize,int *iNewFileSize) {
571 int iDataLength;
572
573 if(index+11>iFileSize) return -1;
574 if(memcmp(&baseptr[index],"RIFF",4)) return -1;
575
576 if(memcmp(&baseptr[index+8],"WAVE",4)) return -1;
577
578 index+=12;
579
580 do {
581 if(index+7>iFileSize) return -1;
582 iDataLength=*(int *)&baseptr[index+4];
583 if(memcmp(&baseptr[index],"data",4)) {
584 index+=iDataLength+8;
585 continue;
586 }
587
588 *iNewFileSize=index+8+iDataLength;
589 if(*iNewFileSize>iFileSize) *iNewFileSize=iFileSize;
590 return index+8;
591 }while(true);
592 }
593
rotate_dword(DWORD x)594 DWORD rotate_dword(DWORD x) {
595 DWORD res;
596
597 ((unsigned char *)&res)[0]=((unsigned char *)&x)[3];
598 ((unsigned char *)&res)[1]=((unsigned char *)&x)[2];
599 ((unsigned char *)&res)[2]=((unsigned char *)&x)[1];
600 ((unsigned char *)&res)[3]=((unsigned char *)&x)[0];
601
602 return res;
603 }
604