mp3val-0.1.8-src/ 777 0 0 0 11220755337 6467 5mp3val-0.1.8-src/changelog.txt 777 0 0 2342 11220755103 11232 0[0.1.8] The garbage handling behavior slightly changed. Some issues with ID3v2 tags being removed should be gone now. [0.1.7] This is mainly a bugfix release. Some issues from Sourceforge bug tracker and from Debian bug tracker have been addressed. [+] More precise report about CRC. [+] A new option added to keep file timestamps. [*] Added more accurate handling of write errors (Debian #413946). [*] Attributes are now correctly preserved. [0.1.6] [+] CRCs are now checked! [+] A new option to delete .bak files after file repair [*] Minor code cleaning [0.1.5] At last (after a long delay) MP3val 0.1.5 is released. It features some minor changes: [+] A new warning message for files with a "couple" of MPEG frames [+] A new warning message for VBR files without VBR header [*] An old CVS patch fixing a error that prevented mp3val from being compiled on AMD64. [0.1.4] This is a bugfix release. Nothing (almost) was changed in Windows version, but Linux version contained a major bug that is (I hope) fixed in this release. [0.1.3] Minor bugfix in command-line parsing, a few options added. [0.1.2] Ported to Unix API, fixed minor bug with file repairing. [0.1.1] First public release! mp3val-0.1.8-src/COPYING 777 0 0 43653 10376656654 7655 0 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. mp3val-0.1.8-src/crc.cpp 777 0 0 2321 11220755202 10012 0/* * MP3val - a program for MPEG audio file validation * Copyright (C) 2005-2009 Alexey Kuznetsov (ring0) and Eugen Tikhonov (jetsys) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "crc.h" unsigned int CalculateCRC16(unsigned int init, unsigned int polynom, char *buf, int cb) { int crc; int i,j; crc=init&0xFFFF; for(i=0;i<=cb-1;i++) { crc<<=8; ((char *)&crc)[2]^=buf[i]; for(j=0;j<=7;j++) { if((crc< int CrossAPI_GetCurrentDirectory(int iBufSize,char *pcBuffer) { return GetCurrentDirectory(iBufSize,pcBuffer); } int CrossAPI_SetCurrentDirectory(char *pcBuffer) { return SetCurrentDirectory(pcBuffer); } int CrossAPI_FindFirstFile(char *szFileName,CROSSAPI_FIND_DATA *cfd) { WIN32_FIND_DATA wfd; HANDLE res; res=FindFirstFile(szFileName,&wfd); strcpy(cfd->cFileName,wfd.cFileName); if(wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) cfd->bIsDirectory=true; else cfd->bIsDirectory=false; return (int)res; } int CrossAPI_FindNextFile(int iHandle,CROSSAPI_FIND_DATA *cfd) { WIN32_FIND_DATA wfd; BOOL res; res=FindNextFile((HANDLE)iHandle,&wfd); if(!res) return 0; strcpy(cfd->cFileName,wfd.cFileName); if(wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) cfd->bIsDirectory=true; else cfd->bIsDirectory=false; return 1; } int CrossAPI_FindClose(int iHandle) { FindClose((HANDLE)iHandle); return 0; } int CrossAPI_GetFullPathName(char *szFileName,char *pcBuffer,int iBufSize) { char *p; return GetFullPathName(szFileName,iBufSize,pcBuffer,&p); } int CrossAPI_GetTempFileAndName(int iBufSize,char *pcBuffer) { char pcDirBuffer[CROSSAPI_MAX_PATH]; if(iBufSizedwAttributes=GetFileAttributes(filename); hFile=CreateFile(filename,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); if(hFile==INVALID_HANDLE_VALUE) return -1; GetFileTime(hFile,&(cfa->ftCreation),&(cfa->ftLastAccess),&(cfa->ftLastWrite)); CloseHandle(hFile); return 0; } int CrossAPI_SetFileAttr(char *filename,CROSSAPI_FILE_ATTRIBUTES *cfa,bool timestamp) { HANDLE hFile; SetFileAttributes(filename,cfa->dwAttributes); hFile=CreateFile(filename,FILE_WRITE_ATTRIBUTES,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); if(hFile==INVALID_HANDLE_VALUE) return -1; if(timestamp) SetFileTime(hFile,&(cfa->ftCreation),&(cfa->ftLastAccess),&(cfa->ftLastWrite)); CloseHandle(hFile); return 0; } #else #include #include #include #include #include #include #include #include #include #include #include #include #include #define TMPBUFSIZE 8192 char pcTmpBuf[TMPBUFSIZE]; int iRoundedMappingLength; int CrossAPI_GetCurrentDirectory(int iBufSize,char *pcBuffer) { char *res; res=getcwd(pcBuffer,iBufSize); if(!res) return 0; return (res-pcBuffer); } int CrossAPI_SetCurrentDirectory(char *pcBuffer) { int res; res=chdir(pcBuffer); if(!res) return 1; return 0; } int CrossAPI_FindFirstFile(char *szFileName,CROSSAPI_FIND_DATA *cfd) { struct stat inode; stat(szFileName,&inode); strncpy(cfd->cFileName,szFileName,CROSSAPI_MAX_PATH); if(inode.st_mode&S_IFDIR) cfd->bIsDirectory=true; else cfd->bIsDirectory=false; return 1; } int CrossAPI_FindNextFile(int iHandle,CROSSAPI_FIND_DATA *cfd) { return 0; } int CrossAPI_FindClose(int iHandle) { return 0; } int CrossAPI_GetFullPathName(char *szFileName,char *pcBuffer,int iBufSize) { if(iBufSizest_mode=ss.st_mode; cfa->t_atime=ss.st_atime; cfa->t_mtime=ss.st_mtime; cfa->t_ctime=ss.st_ctime; return 0; } int CrossAPI_SetFileAttr(char *filename,CROSSAPI_FILE_ATTRIBUTES *cfa,bool timestamp) { struct utimbuf su; chmod(filename,cfa->st_mode); if(timestamp) { su.actime=cfa->t_atime; su.modtime=cfa->t_mtime; utime(filename,&su); } return 0; } #endif mp3val-0.1.8-src/crossapi.h 777 0 0 5616 11220755217 10553 0/* * MP3val - a program for MPEG audio file validation * Copyright (C) 2005-2009 Alexey Kuznetsov (ring0) and Eugen Tikhonov (jetsys) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __CROSSAPI_H__ #define __CROSSAPI_H__ #if (defined WIN32)||(defined __WIN32__)||(defined _MSC_VER)||(defined __NT__) #include #define CROSSAPI_MAX_PATH MAX_PATH struct CROSSAPI_FILE_ATTRIBUTES { DWORD dwAttributes; FILETIME ftCreation; FILETIME ftLastAccess; FILETIME ftLastWrite; }; #else #include #include #include #include #include #define CROSSAPI_MAX_PATH PATH_MAX typedef unsigned int DWORD; struct CROSSAPI_FILE_ATTRIBUTES { mode_t st_mode; time_t t_atime; time_t t_mtime; time_t t_ctime; }; #endif struct CROSSAPI_FIND_DATA { char cFileName[CROSSAPI_MAX_PATH]; bool bIsDirectory; }; int CrossAPI_GetCurrentDirectory(int iBufSize,char *pcBuffer); int CrossAPI_SetCurrentDirectory(char *pcBuffer); /* * Be careful: Unix version of CrossAPI_FindFirstFile doesn't support * wildcards. It isn't very critical, because GCC replaces wildcards * in the command line by an enumeration of all corresponding files */ int CrossAPI_FindFirstFile(char *szFileName,CROSSAPI_FIND_DATA *cfd); int CrossAPI_FindNextFile(int iHandle,CROSSAPI_FIND_DATA *cfd); int CrossAPI_FindClose(int iHandle); int CrossAPI_GetFullPathName(char *szFileName,char *pcBuffer,int iBufSize); int CrossAPI_GetTempFileAndName(int iBufSize,char *pcBuffer); int CrossAPI_MoveFile(char *szNewName,char *szOldName); int CrossAPI_DeleteFile(char *szFileName); int CrossAPI_OpenFile(char *szFileName,bool create,bool write); int CrossAPI_SetFilePointer(int iHandle,int iPointer,bool bFromCurrent); int CrossAPI_WriteFile(int iHandle,char *pcBuffer,int iBytes,int *iBytesWritten); int CrossAPI_CloseFile(int iHandle); int CrossAPI_GetFileSize(int iHandle); int CrossAPI_SetEndOfFile(int iHandle); void *CrossAPI_MapFile(char *filename); int CrossAPI_UnmapFile(void *); int CrossAPI_GetFileAttr(char *filename,CROSSAPI_FILE_ATTRIBUTES *cfa); int CrossAPI_SetFileAttr(char *filename,CROSSAPI_FILE_ATTRIBUTES *cfa,bool timestamp); #endif mp3val-0.1.8-src/main.cpp 777 0 0 17212 11220755321 10216 0/* * MP3val - a program for MPEG audio file validation * Copyright (C) 2005-2009 Alexey Kuznetsov (ring0) and Eugen Tikhonov (jetsys) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include using namespace std; #include "crossapi.h" #include "mpegparse.h" #include "report.h" char pcBuffer[CROSSAPI_MAX_PATH+1]; char pcBuffer2[CROSSAPI_MAX_PATH+1]; bool FixErrors=false; bool bSuppressInfo=false; bool bPipeMode=false; bool bDeleteBaks=false; bool bKeepTimestamps=false; extern int iMappingLength; int SplitFileName(char *szFileNameIn,char **szPathOut,char **szFileNameOut); int ProcessFile(char *szFileName,char *szLogFileName); int main(int argc, char *argv[]) { int hFind; int i; CROSSAPI_FIND_DATA cfd; bool help=false; char *szFile,*szPath; char *szLogFile=NULL; char szFullLogFile[CROSSAPI_MAX_PATH+2]; char szStartDir[CROSSAPI_MAX_PATH+2]; char szPipedFileName[CROSSAPI_MAX_PATH+2]; char ch; if(argc<2) help=true; if(argc==2) { if(!strcmp(argv[1],"/?")) help=true; else if(!strcmp(argv[1],"-h")) help=true; else if(!strcmp(argv[1],"--help")) help=true; } if(help) { cerr<<"MP3val - a program for MPEG audio stream validation.\n"; cerr<<"Version 0.1.8.\n\n"; cerr<<"Usage: "< [options]\n\n"; cerr<<"Options:\n\n"; cerr<<"\t-f try to fix errors\n"; cerr<<"\t-l write log to the specified file (default: stdout)\n"; cerr<<"\t-si suppress INFO messages\n"; cerr<<"\t-nb delete .bak files (suitable with -f)\n"; cerr<<"\t-t keep file timestamps (suitable with -f)\n"; cerr<<"\t-p pipe mode (receive input file names from stdin)\n"; cerr<<"\t-v print version number and exit\n"; cerr<<"\n"; cerr<<"Wildcards are allowed.\n\n"; cerr<<"(c) ring0, jetsys, 2005-2009.\n"; cerr<<"This program is released under GPL, see the attached file for details.\n"; return 0; } for(i=1;i=2)&&(!memcmp(argv[i],"-l",2))) { szLogFile=&argv[i][2]; } else if(!strcmp(argv[i],"-f")) { FixErrors=true; } else if(!strcmp(argv[i],"-si")) { bSuppressInfo=true; } else if(!strcmp(argv[i],"-nb")) { bDeleteBaks=true; } else if(!strcmp(argv[i],"-t")) { bKeepTimestamps=true; } else if(!strcmp(argv[i],"-p")) { bPipeMode=true; } else if(!strcmp(argv[i],"-v")) { cout<<"MP3val 0.1.8\n"; return 0; } else { cerr<<"Wrong parameter \""<CROSSAPI_MAX_PATH) i=0; if(cin.eof()) break; cin.get(ch); if(!ch) break; if(ch==0x0D||ch==0x0A) { szPipedFileName[i]='\0'; if(*szPipedFileName) ProcessFile(szPipedFileName,szLogFile?szFullLogFile:NULL); i=0; } else { szPipedFileName[i]=ch; i++; } } } else { for(i=1;i=szFileNameIn)&&(*p!='\\')&&(*p!='/');p--); p++; if(p==szFileNameIn) *szPathOut=NULL; else { *szPathOut=szFileNameIn; if(**szPathOut=='\"') *szPathOut++; *(p-1)='\0'; } if(p==szFileNameIn) *szFileNameOut=szFileNameIn; else *szFileNameOut=p; if(**szFileNameOut=='\"') { *szFileNameOut++; if(*szFileNameOut[strlen(*szFileNameOut)-1]=='\"') *szFileNameOut[strlen(*szFileNameOut)-1]='\0'; } return 0; } mp3val-0.1.8-src/Makefile.bcc 777 0 0 750 10577501352 10722 0mp3val.exe: main.obj mpegparse.obj out.obj report.obj crossapi.obj crc.obj bcc32 -emp3val.exe main.obj mpegparse.obj out.obj report.obj crossapi.obj crc.obj user32.lib main.obj: main.cpp bcc32 -c main.cpp mpegparse.obj: mpegparse.cpp bcc32 -c mpegparse.cpp out.obj: out.cpp bcc32 -c out.cpp report.obj: report.cpp bcc32 -c report.cpp crossapi.obj: crossapi.cpp bcc32 -c crossapi.cpp crc.obj: crc.cpp crc.h bcc32 -c crc.cpp clean: del *.exe del *.obj del *.tds mp3val-0.1.8-src/Makefile.dmc 777 0 0 732 10577771041 10742 0mp3val.exe: main.obj mpegparse.obj out.obj report.obj crossapi.obj crc.obj dmc main.obj mpegparse.obj out.obj report.obj crossapi.obj crc.obj user32.lib -omp3val.exe main.obj: main.cpp dmc -c main.cpp mpegparse.obj: mpegparse.cpp dmc -c mpegparse.cpp out.obj: out.cpp dmc -c out.cpp report.obj: report.cpp dmc -c report.cpp crossapi.obj: crossapi.cpp dmc -c crossapi.cpp crc.obj: crc.cpp crc.h dmc -c crc.cpp clean: del *.exe del *.obj del *.map mp3val-0.1.8-src/Makefile.gcc 777 0 0 731 10575302310 10715 0mp3val.exe: main.o mpegparse.o out.o report.o crossapi.o crc.o g++ -Wall main.o mpegparse.o out.o report.o crossapi.o crc.o -o mp3val.exe strip mp3val.exe main.o: main.cpp g++ -Wall -c main.cpp mpegparse.o: mpegparse.cpp g++ -Wall -c mpegparse.cpp out.o: out.cpp g++ -Wall -c out.cpp report.o: report.cpp g++ -Wall -c report.cpp crossapi.o: crossapi.cpp g++ -Wall -c crossapi.cpp crc.o: crc.cpp crc.h g++ -Wall -c crc.cpp clean: rm *.o rm *.exe mp3val-0.1.8-src/Makefile.intelc 777 0 0 1043 10600172565 11462 0mp3val.exe: main.obj mpegparse.obj out.obj report.obj crossapi.obj crc.obj icl /O1 /GX /MD main.obj mpegparse.obj out.obj report.obj crossapi.obj crc.obj user32.lib /Femp3val.exe main.obj: main.cpp icl /O1 /GX /MD /c main.cpp mpegparse.obj: mpegparse.cpp icl /O1 /GX /MD /c mpegparse.cpp out.obj: out.cpp icl /O1 /GX /MD /c out.cpp report.obj: report.cpp icl /O1 /GX /MD /c report.cpp crossapi.obj: crossapi.cpp icl /O1 /GX /MD /c crossapi.cpp crc.obj: crc.cpp crc.h icl /O1 /GX /MD /c crc.cpp clean: del *.exe del *.obj mp3val-0.1.8-src/Makefile.linux 777 0 0 225 10575302310 11316 0CXXFLAGS=-Wall -O2 mp3val: main.o mpegparse.o out.o report.o crossapi.o crc.o $(CXX) $(CXXFLAGS) $^ -o $@ clean: rm -f mp3val rm -f *.o mp3val-0.1.8-src/Makefile.msvc 777 0 0 1071 11220753255 11155 0mp3val.exe: main.obj mpegparse.obj out.obj report.obj crossapi.obj crc.obj cl /O1 /EHsc /MD main.obj mpegparse.obj out.obj report.obj crossapi.obj crc.obj user32.lib /Femp3val.exe main.obj: main.cpp cl /O1 /EHsc /MD /c main.cpp mpegparse.obj: mpegparse.cpp cl /O1 /EHsc /MD /c mpegparse.cpp out.obj: out.cpp cl /O1 /EHsc /MD /c out.cpp report.obj: report.cpp cl /O1 /EHsc /MD /c report.cpp crossapi.obj: crossapi.cpp cl /O1 /EHsc /MD /c crossapi.cpp crc.obj: crc.cpp crc.h cl /O1 /EHsc /MD /c crc.cpp clean: del *.exe del *.obj del *.manifestmp3val-0.1.8-src/Makefile.watcomc 777 0 0 1035 10577470562 11655 0mp3val.exe: main.obj mpegparse.obj out.obj report.obj crossapi.obj crc.obj wcl386 -d0 -xd main.obj mpegparse.obj out.obj report.obj crossapi.obj crc.obj user32.lib -fe=mp3val.exe main.obj: main.cpp wcl386 -d0 -xd -c main.cpp mpegparse.obj: mpegparse.cpp wcl386 -d0 -xd -c mpegparse.cpp out.obj: out.cpp wcl386 -d0 -xd -c out.cpp report.obj: report.cpp wcl386 -d0 -xd -c report.cpp crossapi.obj: crossapi.cpp wcl386 -d0 -xd -c crossapi.cpp crc.obj: crc.cpp crc.h wcl386 -d0 -xd -c crc.cpp clean: del *.exe del *.obj mp3val-0.1.8-src/manual.html 777 0 0 23331 11220755157 10737 0 MP3val 0.1.8: Documentation

MP3val 0.1.8: Documentation

  1. Introduction
  2. Why to use it?
  3. How to use it?
  4. Interpreting the output
  5. Licensing and copyright

1. Introduction.

MP3val is a small, high-speed tool for MPEG audio files validation and (optionally) fixing problems. It was primarily designed for verification of MPEG 1 Layer III (MP3) files, but supports also other MPEG versions and layers. It can be useful for finding corrupted files (e.g. incompletely downloaded).

MP3val supports:

  • MPEG-1, 2, 2.5; Layers I, II, III
  • ID3v1 tags (must be at the very end of the file)
  • ID3v2 tags (must be at the very beginning of the file)
  • APEv2 tags

This program can be compiled both for Windows and major Unix systems.

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

The latest version of MP3val (including sources) can be downloaded from the official home page.

2. Why to use it?

MPEG is a streamable format, that is, it is optimized for quick and easy recovery from errors. MP3 decoders are very tolerant to inconsistencies in the input file. Most players even don't report to user about stream errors. So, as a rule, user doesn't know whether his files are valid or broken. But using broken files can eventually lead to problems during playback on certain software/hardware.

MP3val can assure you that your files are consistent in the terms of MPEG frames, that is, it ensures that the file can be easily split into the frames and doesn't contain garbage. It checks also some other issues, such as track length stored in the VBR header. Checking by MP3val isn't a full test for compliance with existing formal and informal standards. MP3val neither decodes audio data nor checks for data validity in the frame.

MP3val can also fix most of the problems. Be careful: although MP3val can repair even files with MPEG stream errors, it is recommended that you find a "good" copy of this file, because a "click" sound usually can't be removed, the repaired file will only look like good.

3. How to use it?

MP3val is a console program. Command-line syntax:

	mp3val <files to validate> <options>
		

<files to validate> - MPEG audio file(s) name(s). Can contain wildcards.

Options:

Option Description
-l<log file> Log file name. If this argument is missing, all the information will be written to stdout.
-f Try to fix errors.
-si Suppress INFO messages.
-nb Delete .bak files that were created during file rebuilding. Use this option together with -f.
-t Keep file timestamps. Use this option together with -f.
-p Pipe mode (receive input file names from stdin). Intended for interaction with frontends. <files to validate> is ignored in this case.
-v Print version and exit

Example:

	mp3val my_song.mp3 -lout.log -f
		

MP3val will give information about the file with the name specified. Any errors or inconsistencies will result in a "WARNING" message. This doesn't necessarily mean that the file is corrupted. See the next section for details. If the file doesn't look like a MPEG audio file, an "ERROR: invalid file format" message will be generated.

4. Interpreting the output.

WARNING message Fixable? Comments
Too few MPEG frames (it's unlikely that this is a MPEG audio file) - Probably this is not a MPEG audio file, but MP3val has detected a couple of MPEG frames in it. Most likely this is a false positive.
Garbage at the beginning of the file + There are some unknown data at the beginning of the file (before the first MPEG frame). It can be an unsupported tag with metadata, but in most cases it is only garbage. "Fixing" means here a removal of these data.
Garbage at the end of the file + Like previous.
MPEG stream error, resynchronized successfully + Normally, each MPEG frame must be followed by a next MPEG frame (or a metadata block), otherwise this message is generated. MPEG stream errors can be caused by garbage in the middle of the file (e.g. the file was split into several parts, the tags were appended, and then these parts were improperly merged) or by a data loss during transfer or storage. Note that "fixing" this error will remove garbage, but in most cases "fixed" file will not sound better, that's why it is strongly recommended to find a "good" copy of the file.
This is a RIFF file, not MPEG stream + A common way for storing a MPEG audio file is simply to write MPEG frames one-by-one. MP1/MP2/MP3 files are organized so. MPEG audio data can also be encapsulated in the RIFF container (better known as WAV file). The RIFF container shouldn't be used unless the file has "WAV" extension.
It seems that file is truncated or there is garbage at the end of the file + This message is generated when the length of the last frame (according to its header) is greater than the amount of data from its beginning to the end of the file. As a rule, it means that the file was truncated, however, there can be garbage at its end. "Fixing" means here a removal of the last frame.
Wrong number of MPEG frames specified in Xing header + MPEG audio files don't have any special header, each frame has its own header instead. However, it can cause problems when "seeking" in variable bitrate files, because a decoder can't determine the exact place in the file corresponding to the selected time. That's why a "VBR header" is sometimes included in the first MPEG frame. This message is generated if this header contains false information about the total number of MPEG frames.
Wrong number of MPEG data bytes specified in Xing header + This message is generated when the Xing header contains false information about the total size of MPEG data in the file. See the previous message.
Wrong number of MPEG frames specified in VBRI header + Like with Xing header. VBRI is the other way to store VBR information in the first MPEG frame, but it seems to be used much more rarely.
Wrong number of MPEG data bytes specified in VBRI header + Like with Xing header. VBRI is the other way to store VBR information in the first MPEG frame, but it seems to be used much more rarely.
VBR detected, but no VBR header is present. Seeking may not work properly - Files encoded with VBR should have a VBR header (either Xing or VBRI), otherwise seeking can be broken. This will be fixable in the future versions.
Wrong CRC in ... frames + Some frames in the file are protected by CRC, but the checksum is wrong. It means that either the file was encoded or processed by broken software, or it was broken during storage or transmission. MP3val reports a number of frames with incorrect CRC, which can be used as a hint (if this number equals or is about the total number of frames, then it's likely due to a bad encoder). Note that only a minority of files is protected by CRC.
Non-layer-III frame encountered - MP3val was primarily designed for MP3 files. That's why it warns about MPEG frames with layers other than III. If it is an MP2 or MP1 file, this warning should be ignored. If you want to fix this issue, you should reencode the file.
Different MPEG versions or layers in one file - Mixing different MPEG versions and/or layers in one file is not very good. As in the previous case, this issue can be fixed only by reencoding.
Several APEv2 tags in one file + Normally there would be only one APEv2 tag in the file.
No supported tags in the file - This is only a warning. It's a good practice to store metadata in tags.

5. Licensing and copyright

Copyright (c) 2005-2009 by Alexey Kuznetsov (ring0) and Eugen Tikhonov (jetsys).

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

Contacts: mp3val at ring0 dot pp dot ru mp3val-0.1.8-src/mpegparse.cpp 777 0 0 41112 11220755231 11251 0/* * MP3val - a program for MPEG audio file validation * Copyright (C) 2005-2009 Alexey Kuznetsov (ring0) and Eugen Tikhonov (jetsys) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "crossapi.h" #include "mpegparse.h" #include "report.h" #include "out.h" #include "crc.h" #include #include #include using namespace std; int mpeg1layer1_bitrates[]={-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448,-1}; int mpeg1layer2_bitrates[]={-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384,-1}; int mpeg1layer3_bitrates[]={-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1}; int mpeg2layer1_bitrates[]={-1,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1}; int mpeg2layers23_bitrates[]={-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1}; int ValidateMPEGFrame(unsigned char *baseptr,int index, MPEGINFO *mpginfo); int CheckMP3CRC(unsigned char *baseptr,int index,MPEGINFO *mpginfo,bool fix); int ValidateID3v2Tag(unsigned char *baseptr,int index, MPEGINFO *mpginfo); int ValidateAPEv2Tag(unsigned char *baseptr,int index, MPEGINFO *mpginfo); int ParseXingHeader(unsigned char *baseptr,int index,MPEGINFO *mpginfo); int ParseVBRIHeader(unsigned char *baseptr,int index,MPEGINFO *mpginfo); int ParseRIFFHeader(unsigned char *baseptr,int index,int iFileSize,int *iNewFileSize); int MPEGResync(unsigned char *baseptr,int index,int iFileSize,int frames); DWORD rotate_dword(DWORD x); int ValidateFile(unsigned char *baseptr,int iFileSize,MPEGINFO *mpginfo,ostream *out,char *filename,bool fix,int hFile) { int iFrame; int iFrameSize=0; int iLastMPEGFrame=0,iNewFrame; bool WasFirstFrame=false; int iXingOffset=0; int iID3v1Offset=0; int iFirstMPEGFrameOffset=0; DWORD dwTemp; int mpeg_total; bool LastFrameWasMPEG=false; iFrame=0; mpginfo->clear(); if(iFileSize>=128&&!memcmp(&baseptr[iFileSize-128],"TAG",3)) { mpginfo->id3v1=1; iFileSize-=128; iID3v1Offset=iFileSize; } if((iFileSize>=4)&&!memcmp(&baseptr[iFrame],"ID3",3)) { if(iFrame+10>iFileSize) { mpginfo->truncated=iFrame; } else { iFrame+=ValidateID3v2Tag(baseptr,iFrame,mpginfo); if(fix) { if(WriteToFile(hFile,(char *)baseptr,0,iFrame,iFileSize)==-1) return -1; LastFrameWasMPEG=false; } } } while(iFrame!=iFileSize) { if(iFrame+4>iFileSize) { //Bad (unknown) frame mpginfo->truncated=iFrame; break; } if(!memcmp(&baseptr[iFrame],"RIFF",4)) { if(!WasFirstFrame) { //This is actually a WAV file, not MPEG. Parsing RIFF header mpginfo->riff=iFrame; iNewFrame=ParseRIFFHeader(baseptr,iFrame,iFileSize,&iFileSize); if(iNewFrame!=-1) { iFrame=iNewFrame; continue; } } } if((baseptr[iFrame]==0xFF)&&((baseptr[iFrame+1]&0xE0)==0xE0)) { //MPEG frame iFrameSize=ValidateMPEGFrame(baseptr,iFrame,mpginfo); if(iFrameSize!=-1) { if(iFrameSize+iFrame<=iFileSize&&mpginfo->iLastMPEGLayer==3&&mpginfo->bLastFrameCRC) CheckMP3CRC(baseptr,iFrame,mpginfo,fix); if(fix&&!WasFirstFrame) iFirstMPEGFrameOffset=CrossAPI_SetFilePointer(hFile,0,true); if(fix) { if(WriteToFile(hFile,(char *)baseptr,iFrame,iFrameSize,iFileSize)==-1) return -1; LastFrameWasMPEG=true; } if(!WasFirstFrame) { WasFirstFrame=true; mpginfo->iFirstMPEGFrameSize=iFrameSize; if(mpginfo->iLastMPEGVersion==1) { if(mpginfo->LastFrameStereo) { iXingOffset=32; } else { iXingOffset=17; } } else { if(mpginfo->LastFrameStereo) { iXingOffset=17; } else { iXingOffset=9; } } ParseXingHeader(baseptr,iFrame+4+iXingOffset,mpginfo); if(!mpginfo->VBRHeaderPresent) ParseVBRIHeader(baseptr,iFrame+4+32,mpginfo); } iLastMPEGFrame=iFrame; iFrame+=iFrameSize; continue; } } //APEv2 tag if(!memcmp(&baseptr[iFrame],"APET",4)) { if(iFrame+16>iFileSize) { mpginfo->truncated=iFrame; break; } iFrameSize=ValidateAPEv2Tag(baseptr,iFrame,mpginfo); if(fix) { if(WriteToFile(hFile,(char *)baseptr,iFrame,iFrameSize,iFileSize)==-1) return -1; LastFrameWasMPEG=false; } iFrame+=iFrameSize; continue; } if(fix) { if(LastFrameWasMPEG) { mpginfo->iDeletedFrames++; mpginfo->iTotalMPEGBytes-=WriteToFile(hFile,NULL,0,-1,-1); } /* else { if(WriteToFile(hFile,NULL,0,-1,-1)==-1) return -1; }*/ } else if(LastFrameWasMPEG) { mpginfo->iDeletedFrames++; mpginfo->iTotalMPEGBytes-=GetLastFrameSize(); } if(!iFrame) { iNewFrame=MPEGResync(baseptr,iFrame,iFileSize,8); if(iNewFrame==-1) { mpginfo->unknown_format=0; break; } mpginfo->garbage_at_the_begin=0; if(!fix) PrintMessage(out,"WARNING",filename,"Garbage at the beginning of the file",mpginfo->garbage_at_the_begin); mpginfo->iErrors++; iFrame=iNewFrame; } else { iNewFrame=MPEGResync(baseptr,iLastMPEGFrame?(iLastMPEGFrame+1):iFrame,iFileSize,6); if(iNewFrame==-1) { mpginfo->garbage_at_the_end=iFrame; if(!fix) PrintMessage(out,"WARNING",filename,"Garbage at the end of the file",mpginfo->garbage_at_the_end); mpginfo->iErrors++; break; } mpginfo->mpeg_stream_error=iFrame; if(!fix) PrintMessage(out,"WARNING",filename,"MPEG stream error, resynchronized successfully",mpginfo->mpeg_stream_error); mpginfo->iErrors++; iFrame=iNewFrame; } } mpeg_total= mpginfo->mpeg1layer1+ mpginfo->mpeg1layer2+ mpginfo->mpeg1layer3+ mpginfo->mpeg2layer1+ mpginfo->mpeg2layer2+ mpginfo->mpeg2layer3+ mpginfo->mpeg25layer1+ mpginfo->mpeg25layer2+ mpginfo->mpeg25layer3; if(mpginfo->truncated>=0) { if(fix) { if(WriteToFile(hFile,NULL,0,-1,-1)==-1) return -1; if(LastFrameWasMPEG) { mpginfo->iTotalMPEGBytes-=iFrameSize; mpginfo->iDeletedFrames++; } } else if(LastFrameWasMPEG) { mpginfo->iTotalMPEGBytes-=iFrameSize; mpginfo->iDeletedFrames++; } } if(fix&&mpginfo->id3v1) { if(WriteToFile(hFile,(char *)baseptr,iID3v1Offset,128,-1)==-1) return -1; } if(fix) CrossAPI_SetEndOfFile(hFile); if(fix&&mpginfo->VBRHeaderPresent) { if(mpginfo->IsXingHeader) { if(mpginfo->BytesPresent&&mpginfo->FramesPresent) { CrossAPI_SetFilePointer(hFile,iFirstMPEGFrameOffset+iXingOffset+12,false); dwTemp=rotate_dword(mpeg_total-mpginfo->iDeletedFrames); if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1; dwTemp=rotate_dword(mpginfo->iTotalMPEGBytes); if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1; } else if(mpginfo->BytesPresent) { CrossAPI_SetFilePointer(hFile,iFirstMPEGFrameOffset+iXingOffset+12,false); dwTemp=rotate_dword(mpginfo->iTotalMPEGBytes); if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1; } else if(mpginfo->FramesPresent) { CrossAPI_SetFilePointer(hFile,iFirstMPEGFrameOffset+iXingOffset+12,false); dwTemp=rotate_dword(mpeg_total-mpginfo->iDeletedFrames); if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1; } } else { CrossAPI_SetFilePointer(hFile,iFirstMPEGFrameOffset+46,false); dwTemp=rotate_dword(mpginfo->iTotalMPEGBytes); if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1; dwTemp=rotate_dword(mpeg_total-mpginfo->iDeletedFrames); if(WriteToFile(hFile,(char *)&dwTemp,0,4,-1)==-1) return -1; } } if(fix) mpginfo->iErrors=1; return 0; } int ValidateMPEGFrame(unsigned char *baseptr,int index, MPEGINFO *mpginfo) { int mpeg_version, mpeg_layer; int mpeg_bitrate, mpeg_sampling_rate, mpeg_padding; int bitrate_index=0; int iFrameSize; //Check if the frame contains CRC if(baseptr[index+1]&0x01) { mpginfo->bLastFrameCRC=false; } else { mpginfo->bLastFrameCRC=true; mpginfo->bCRC=true; } // Determine MPEG version and layer switch((baseptr[index+1]>>1)&0x0F) { case 0x0F: mpginfo->mpeg1layer1++; mpeg_version=1; mpeg_layer=1; break; case 0x0E: mpginfo->mpeg1layer2++; mpeg_version=1; mpeg_layer=2; break; case 0x0D: mpginfo->mpeg1layer3++; mpeg_version=1; mpeg_layer=3; break; case 0x0B: mpginfo->mpeg2layer1++; mpeg_version=2; mpeg_layer=1; break; case 0x0A: mpginfo->mpeg2layer2++; mpeg_version=2; mpeg_layer=2; break; case 0x09: mpginfo->mpeg2layer3++; mpeg_version=2; mpeg_layer=3; break; case 0x03: mpginfo->mpeg25layer1++; mpeg_version=25; mpeg_layer=1; break; case 0x02: mpginfo->mpeg25layer2++; mpeg_version=25; mpeg_layer=2; break; case 0x01: mpginfo->mpeg25layer3++; mpeg_version=25; mpeg_layer=3; break; default: mpginfo->mpeg_stream_error=index; return -1; } // Calculate bit rate *((unsigned char *)&bitrate_index)=((baseptr[index+2])>>4)&0x0F; if(mpeg_version==1) { if(mpeg_layer==1) { mpeg_bitrate=mpeg1layer1_bitrates[bitrate_index]; } else if(mpeg_layer==2) { mpeg_bitrate=mpeg1layer2_bitrates[bitrate_index]; } else { mpeg_bitrate=mpeg1layer3_bitrates[bitrate_index]; } } else { if(mpeg_layer==1) { mpeg_bitrate=mpeg2layer1_bitrates[bitrate_index]; } else { mpeg_bitrate=mpeg2layers23_bitrates[bitrate_index]; } } if(mpeg_bitrate==-1) { mpginfo->mpeg_stream_error=index; return -1; } if(mpginfo->iLastBitrate>0&&mpginfo->iLastBitrate!=mpeg_bitrate) mpginfo->bVariableBitrate=true; mpginfo->iLastBitrate=mpeg_bitrate; //Determine sampling rate switch((baseptr[index+2]>>2)&0x03) { case 0x00: if(mpeg_version==1) mpeg_sampling_rate=44100; else if(mpeg_version==2) mpeg_sampling_rate=22050; else mpeg_sampling_rate=11025; break; case 0x01: if(mpeg_version==1) mpeg_sampling_rate=48000; else if(mpeg_version==2) mpeg_sampling_rate=24000; else mpeg_sampling_rate=12000; break; case 0x02: if(mpeg_version==1) mpeg_sampling_rate=32000; else if(mpeg_version==2) mpeg_sampling_rate=16000; else mpeg_sampling_rate=8000; break; default: mpginfo->mpeg_stream_error=index; return -1; } //Check if padding is being used if((baseptr[index+2]>>1)&0x01) mpeg_padding=1; else mpeg_padding=0; //Check if frame is stereo if((baseptr[index+3]&0xC0)==0xC0) mpginfo->LastFrameStereo=false; else mpginfo->LastFrameStereo=true; mpginfo->iLastMPEGVersion=mpeg_version; mpginfo->iLastMPEGLayer=mpeg_layer; if(mpeg_layer==1) iFrameSize=(12*mpeg_bitrate*1000/mpeg_sampling_rate+mpeg_padding)*4; else if(mpeg_layer==2) iFrameSize=144*mpeg_bitrate*1000/mpeg_sampling_rate+mpeg_padding; else if(mpeg_layer==3&&mpeg_version==1) iFrameSize=144*mpeg_bitrate*1000/mpeg_sampling_rate+mpeg_padding; else iFrameSize=72*mpeg_bitrate*1000/mpeg_sampling_rate+mpeg_padding; mpginfo->iTotalMPEGBytes+=iFrameSize; return iFrameSize; } int CheckMP3CRC(unsigned char *baseptr,int index,MPEGINFO *mpginfo,bool fix) { int crc=0xFFFF; int storedcrc=0; int iSideInfoSize; crc=CalculateCRC16(crc,0x8005,(char *)&baseptr[index+2],2); if(mpginfo->LastFrameStereo) { if(mpginfo->iLastMPEGVersion==1) { iSideInfoSize=32; } else { iSideInfoSize=17; } } else { if(mpginfo->iLastMPEGVersion==1) { iSideInfoSize=17; } else { iSideInfoSize=9; } } crc=CalculateCRC16(crc,0x8005,(char *)&baseptr[index+6],iSideInfoSize); ((char *)&storedcrc)[1]=baseptr[index+4]; ((char *)&storedcrc)[0]=baseptr[index+5]; if(storedcrc!=crc) { mpginfo->bCRCError=true; mpginfo->iCRCErrors++; if(fix) { baseptr[index+4]=((char *)&crc)[1]; baseptr[index+5]=((char *)&crc)[0]; } } return 0; } int ValidateID3v2Tag(unsigned char *baseptr,int index, MPEGINFO *mpginfo) { int iDataSize; mpginfo->id3v2++; iDataSize=baseptr[index+9]; iDataSize+=128*baseptr[index+8]; iDataSize+=16384*baseptr[index+7]; iDataSize+=2097152*baseptr[index+6]; if(baseptr[index+5]&0x10) return iDataSize+20; return iDataSize+10; } int ValidateAPEv2Tag(unsigned char *baseptr,int index, MPEGINFO *mpginfo) { mpginfo->apev2++; return *((int *)&baseptr[index+12])+32; } int MPEGResync(unsigned char *baseptr,int index,int iFileSize,int frames) { unsigned char *p=&baseptr[index]; int sync_frames=0; int new_frame=0; int iFrameSize; MPEGINFO tmp_mpginfo; int iMPEGVersion=0,iMPEGLayer=0; do { if(iFileSize-(p-baseptr)-3<=0) return -1; p=(unsigned char *)memchr(p,'\xFF',iFileSize-(p-baseptr)-3); if(!p) break; if((p[1]&0xE0)!=0xE0) { p++; sync_frames=0; iMPEGVersion=0; iMPEGLayer=0; continue; } iFrameSize=ValidateMPEGFrame(baseptr,p-baseptr,&tmp_mpginfo); if(iFrameSize==-1) { p++; sync_frames=0; iMPEGVersion=0; iMPEGLayer=0; continue; } new_frame=iFrameSize+(p-baseptr); sync_frames++; iMPEGVersion=tmp_mpginfo.iLastMPEGVersion; iMPEGLayer=tmp_mpginfo.iLastMPEGLayer; while(sync_framesiFileSize) { sync_frames=0; iMPEGVersion=0; iMPEGLayer=0; p++; break; } iFrameSize=ValidateMPEGFrame(baseptr,new_frame,&tmp_mpginfo); if(iFrameSize==-1) { sync_frames=0; iMPEGVersion=0; iMPEGLayer=0; p++; break; } new_frame+=iFrameSize; sync_frames++; if(iMPEGVersion&&iMPEGVersion!=tmp_mpginfo.iLastMPEGVersion) { sync_frames=0; iMPEGVersion=0; iMPEGLayer=0; p++; break; } if(iMPEGLayer&&iMPEGLayer!=tmp_mpginfo.iLastMPEGLayer) { sync_frames=0; iMPEGVersion=0; iMPEGLayer=0; p++; break; } } } while(sync_frames=frames) return (p-baseptr); return -1; } int ParseXingHeader(unsigned char *baseptr,int index,MPEGINFO *mpginfo) { if(memcmp(&baseptr[index],"Xing",4)&&memcmp(&baseptr[index],"Info",4)) return 0; mpginfo->VBRHeaderPresent=true; mpginfo->IsXingHeader=true; switch(baseptr[index+7]&0x03) { case 0x00: return 0; case 0x01: mpginfo->iFrames=16777216*baseptr[index+8]+65536*baseptr[index+9]+256*baseptr[index+10]+baseptr[index+11]; mpginfo->FramesPresent=true; mpginfo->BytesPresent=false; return 0; case 0x02: mpginfo->iBytes=16777216*baseptr[index+8]+65536*baseptr[index+9]+256*baseptr[index+10]+baseptr[index+11]; mpginfo->FramesPresent=false; mpginfo->BytesPresent=true; return 0; case 0x03: mpginfo->iFrames=16777216*baseptr[index+8]+65536*baseptr[index+9]+256*baseptr[index+10]+baseptr[index+11]; mpginfo->iBytes=16777216*baseptr[index+12]+65536*baseptr[index+13]+256*baseptr[index+14]+baseptr[index+15]; mpginfo->FramesPresent=true; mpginfo->BytesPresent=true; return 0; } return 0; } int ParseVBRIHeader(unsigned char *baseptr,int index,MPEGINFO *mpginfo) { if(memcmp(&baseptr[index],"VBRI",4)) return 0; mpginfo->VBRHeaderPresent=true; mpginfo->IsXingHeader=false; mpginfo->iBytes=16777216*baseptr[index+10]+65536*baseptr[index+11]+256*baseptr[index+12]+baseptr[index+13]; mpginfo->iFrames=16777216*baseptr[index+14]+65536*baseptr[index+15]+256*baseptr[index+16]+baseptr[index+17]; mpginfo->FramesPresent=true; mpginfo->BytesPresent=true; return 0; } int ParseRIFFHeader(unsigned char *baseptr,int index,int iFileSize,int *iNewFileSize) { int iDataLength; if(index+11>iFileSize) return -1; if(memcmp(&baseptr[index],"RIFF",4)) return -1; if(memcmp(&baseptr[index+8],"WAVE",4)) return -1; index+=12; do { if(index+7>iFileSize) return -1; iDataLength=*(int *)&baseptr[index+4]; if(memcmp(&baseptr[index],"data",4)) { index+=iDataLength+8; continue; } *iNewFileSize=index+8+iDataLength; if(*iNewFileSize>iFileSize) *iNewFileSize=iFileSize; return index+8; }while(true); } DWORD rotate_dword(DWORD x) { DWORD res; ((unsigned char *)&res)[0]=((unsigned char *)&x)[3]; ((unsigned char *)&res)[1]=((unsigned char *)&x)[2]; ((unsigned char *)&res)[2]=((unsigned char *)&x)[1]; ((unsigned char *)&res)[3]=((unsigned char *)&x)[0]; return res; } mp3val-0.1.8-src/mpegparse.h 777 0 0 5726 11220755236 10716 0/* * MP3val - a program for MPEG audio file validation * Copyright (C) 2005-2009 Alexey Kuznetsov (ring0) and Eugen Tikhonov (jetsys) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __MPEGPARSE_H__ #define __MPEGPARSE_H__ #include /* * MPEGINFO structure is used to contain both information about the last analyzed * frame (filled by ValidateMPEGFrame) and for the entire stream. */ struct MPEGINFO { //MPEG frames counts int mpeg1layer1; int mpeg1layer2; int mpeg1layer3; int mpeg2layer1; int mpeg2layer2; int mpeg2layer3; int mpeg25layer1; int mpeg25layer2; int mpeg25layer3; //Tag counts int id3v1; int id3v2; int apev2; //VBR header info bool VBRHeaderPresent; bool IsXingHeader; //otherwise it's Fraunhofer VBRI header bool BytesPresent; int iBytes; bool FramesPresent; int iFrames; int iFirstMPEGFrameSize; //because Foobar2000 doesn't count the first frame (with Xing header) as MPEG data //Error flags int riff; int unknown_format; int truncated; int mpeg_stream_error; int garbage_at_the_begin; int garbage_at_the_end; //MPEG-related data bool LastFrameStereo; bool bLastFrameCRC; bool bCRC; bool bCRCError; int iLastBitrate; int iLastMPEGLayer; int iLastMPEGVersion; //Miscellaneous data bool bVariableBitrate; int iTotalMPEGBytes; int iErrors; int iDeletedFrames; int iCRCErrors; MPEGINFO() { clear(); } void clear() { mpeg1layer1=0; mpeg1layer2=0; mpeg1layer3=0; mpeg2layer1=0; mpeg2layer2=0; mpeg2layer3=0; mpeg25layer1=0; mpeg25layer2=0; mpeg25layer3=0; id3v1=0; id3v2=0; apev2=0; VBRHeaderPresent=false; IsXingHeader=true; BytesPresent=false; iBytes=-1; FramesPresent=false; iFrames=-1; riff=-1; unknown_format=-1; mpeg_stream_error=-1; truncated=-1; garbage_at_the_begin=-1; garbage_at_the_end=-1; LastFrameStereo=false; bLastFrameCRC=false; bCRC=false; bCRCError=false; bVariableBitrate=false; iLastBitrate=-2; iLastMPEGLayer=0; iLastMPEGVersion=0; iCRCErrors=0; iTotalMPEGBytes=0; iErrors=0; iDeletedFrames=0; } }; int ValidateFile(unsigned char *baseptr,int iFileSize, MPEGINFO *mpginfo,std::ostream *out,char *filename,bool fix,int hFile); #endif mp3val-0.1.8-src/out.cpp 777 0 0 3075 11220755241 10064 0/* * MP3val - a program for MPEG audio file validation * Copyright (C) 2005-2009 Alexey Kuznetsov (ring0) and Eugen Tikhonov (jetsys) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "out.h" #include "crossapi.h" static int iPrevSize=0; int GetLastFrameSize() { return iPrevSize; } int WriteToFile(int hFile,char *baseptr,int index,int bytes,int iFileSize) { int tmp; int iBytesWritten,iBytesWrittenTotal=0; if(bytes<0) { if(iPrevSize) CrossAPI_SetFilePointer(hFile,-iPrevSize,true); tmp=iPrevSize; iPrevSize=0; return tmp; } if(iFileSize>=0) { if(index+bytes>iFileSize) bytes=iFileSize-index; } while(iBytesWrittenTotal #include #include #include extern bool bSuppressInfo; int PrintMessage(ostream *out,char *caption,char *filename,char *message,int iErrorFrame); int PrintReport(ostream *out,char *filename,MPEGINFO *mpginfo) { int frame_types=0; int mpeg_total; int tags_total; char szMsgBuf[256]; mpeg_total= mpginfo->mpeg1layer1+ mpginfo->mpeg1layer2+ mpginfo->mpeg1layer3+ mpginfo->mpeg2layer1+ mpginfo->mpeg2layer2+ mpginfo->mpeg2layer3+ mpginfo->mpeg25layer1+ mpginfo->mpeg25layer2+ mpginfo->mpeg25layer3; //Errors if(mpginfo->unknown_format>=0) { PrintMessage(out,"ERROR",filename,"Unknown file format",-1); return 0; } //Warnings if(mpeg_total<10) { PrintMessage(out,"WARNING",filename,"Too few MPEG frames (it's unlikely that this is a MPEG audio file)",-1); } if(mpginfo->riff>=0) { PrintMessage(out,"WARNING",filename,"This is a RIFF file, not MPEG stream",-1); mpginfo->iErrors++; } if(mpginfo->truncated>=0) { PrintMessage(out,"WARNING",filename,"It seems that file is truncated or there is garbage at the end of the file",mpginfo->truncated); mpginfo->iErrors++; } if(mpginfo->bCRCError) { sprintf(szMsgBuf,"Wrong CRC in %d frames",mpginfo->iCRCErrors); PrintMessage(out,"WARNING",filename,szMsgBuf,-1); mpginfo->iErrors++; } if(mpginfo->VBRHeaderPresent) { if(mpginfo->IsXingHeader) { /* * LAME and Foobar2000 write (TotalFrames-1) as frames number in Xing header. * Some other encoders seem to write TotalFrames as this value. * We'll consider both first and second methods right. */ /* * Foobar2000 (at least version 0.9.4) doesn't count the first frame (with Xing header) as MPEG data when fixing VBR header. * LAME does the other way round. * We'll consider both first and second methods right. */ if(mpginfo->FramesPresent&&mpginfo->iFrames!=mpeg_total&&mpginfo->iFrames+1!=mpeg_total) { sprintf(szMsgBuf,"Wrong number of MPEG frames specified in Xing header (%d instead of %d)",mpginfo->iFrames,mpeg_total); PrintMessage(out,"WARNING",filename,szMsgBuf,-1); mpginfo->iErrors++; } if(mpginfo->BytesPresent&&mpginfo->iBytes!=mpginfo->iTotalMPEGBytes&&mpginfo->iBytes!=mpginfo->iTotalMPEGBytes-mpginfo->iFirstMPEGFrameSize) { sprintf(szMsgBuf,"Wrong number of MPEG data bytes specified in Xing header (%d instead of %d)",mpginfo->iBytes,mpginfo->iTotalMPEGBytes); PrintMessage(out,"WARNING",filename,szMsgBuf,-1); mpginfo->iErrors++; } } else { if(mpginfo->FramesPresent&&mpginfo->iFrames!=mpeg_total) { sprintf(szMsgBuf,"Wrong number of MPEG frames specified in VBRI header (%d instead of %d)",mpginfo->iFrames,mpeg_total); PrintMessage(out,"WARNING",filename,szMsgBuf,-1); mpginfo->iErrors++; } if(mpginfo->BytesPresent&&mpginfo->iBytes!=mpginfo->iTotalMPEGBytes) { sprintf(szMsgBuf,"Wrong number of MPEG data bytes specified in VBRI header (%d instead of %d)",mpginfo->iBytes,mpginfo->iTotalMPEGBytes); PrintMessage(out,"WARNING",filename,szMsgBuf,-1); mpginfo->iErrors++; } } } if(mpginfo->bVariableBitrate&&!mpginfo->VBRHeaderPresent) { PrintMessage(out,"WARNING",filename,"VBR detected, but no VBR header is present. Seeking may not work properly.",-1); } if(mpginfo->mpeg1layer1|| mpginfo->mpeg1layer2|| mpginfo->mpeg2layer1|| mpginfo->mpeg2layer2|| mpginfo->mpeg25layer1|| mpginfo->mpeg25layer2) { PrintMessage(out,"WARNING",filename,"Non-layer-III frame encountered. See related INFO message for details.",-1); mpginfo->iErrors++; } if(mpginfo->mpeg1layer1) frame_types++; if(mpginfo->mpeg1layer2) frame_types++; if(mpginfo->mpeg1layer3) frame_types++; if(mpginfo->mpeg2layer1) frame_types++; if(mpginfo->mpeg2layer2) frame_types++; if(mpginfo->mpeg2layer3) frame_types++; if(mpginfo->mpeg25layer1) frame_types++; if(mpginfo->mpeg25layer2) frame_types++; if(mpginfo->mpeg25layer3) frame_types++; if(frame_types>1) { PrintMessage(out,"WARNING",filename,"Different MPEG versions or layers in one file. See related INFO message for details.",-1); } if(mpginfo->apev2>1) { PrintMessage(out,"WARNING",filename,"Several APEv2 tags in one file. See related INFO message for details.",-1); mpginfo->iErrors++; } if(!(mpginfo->id3v1)&&!(mpginfo->id3v2)&&!(mpginfo->apev2)) { PrintMessage(out,"WARNING",filename,"No supported tags in the file",-1); } tags_total= mpginfo->id3v1+ mpginfo->id3v2+ mpginfo->apev2; if(!bSuppressInfo) { (*out)<<"INFO: "; (*out)<<"\""<1) { (*out)<mpeg1layer1<<" V1L1, "; (*out)<mpeg1layer2<<" V1L2, "; (*out)<mpeg1layer3<<" V1L3, "; (*out)<mpeg2layer1<<" V2L1, "; (*out)<mpeg2layer2<<" V2L2, "; (*out)<mpeg2layer3<<" V2L3, "; (*out)<mpeg25layer1<<" V2.5L1, "; (*out)<mpeg25layer2<<" V2.5L2, "; (*out)<mpeg25layer3<<" V2.5L3"; } else { if(mpginfo->mpeg1layer1) (*out)<<"MPEG 1 Layer I"; else if(mpginfo->mpeg1layer2) (*out)<<"MPEG 1 Layer II"; else if(mpginfo->mpeg1layer3) (*out)<<"MPEG 1 Layer III"; else if(mpginfo->mpeg2layer1) (*out)<<"MPEG 2 Layer I"; else if(mpginfo->mpeg2layer2) (*out)<<"MPEG 2 Layer II"; else if(mpginfo->mpeg2layer3) (*out)<<"MPEG 2 Layer III"; else if(mpginfo->mpeg25layer1) (*out)<<"MPEG 2.5 Layer I"; else if(mpginfo->mpeg25layer2) (*out)<<"MPEG 2.5 Layer II"; else if(mpginfo->mpeg25layer3) (*out)<<"MPEG 2.5 Layer III"; } (*out)<<"), "; } else { (*out)<<"No MPEG frames, "; } if(tags_total) { if(mpginfo->id3v1>1||mpginfo->id3v2>1||mpginfo->apev2>1) { (*out)<id3v1<<" ID3v1, "; (*out)<id3v2<<" ID3v2, "; (*out)<apev2<<" APEv2"; (*out)<<")"; } else { if(mpginfo->id3v1) (*out)<<"+ID3v1"; if(mpginfo->id3v2) (*out)<<"+ID3v2"; if(mpginfo->apev2) (*out)<<"+APEv2"; } } else { (*out)<<"no tags"; } (*out)<<", "; if(!mpginfo->bVariableBitrate) { (*out)<<"CBR"; } else if(mpginfo->VBRHeaderPresent) { if(mpginfo->IsXingHeader) (*out)<<"Xing header"; else (*out)<<"VBRI header"; } else { (*out)<<"no VBR header"; } if(mpginfo->bCRC) { (*out)<<", CRC"; } (*out)<<"\n"; } return 0; } int PrintMessage(ostream *out,char *caption,char *filename,char *message,int iErrorFrame) { (*out)<=0) { (*out)<<"\""< using namespace std; #include "mpegparse.h" int PrintReport(ostream *out,char *filename,MPEGINFO *mpginfo); int PrintMessage(ostream *out,char *caption,char *filename,char *message,int iErrorFrame); #endif