# include // getopt # include // per esborrar... # include "qmp3frameheader.hh" # include "qmp3.hh" # include "qfile.hh" # include "qtag.hh" # include "qexception.hh" #ifdef NLS # include # include # define _(s) gettext (s) #else # define _(s) (s) #endif void usage () { cerr << APPNAME << ": " << _("check and clean mp3 streams") << '\n'; cerr << ' ' << _("syntax") << APPNAME << ' ' << _("[option]... file...") << '\n'; cerr << _(" -D, --delete: delete invalid frames and garbage. use with care\n"); cerr << _(" -h, --help: show this help and exit\n"); cerr << _(" -q, --quiet: no output messages\n"); cerr << _(" -T, --delete-tag: delete tag (if exists). option -D must be set\n"); cerr << _(" -v, --verbose: show more detailed info\n"); cerr << _(" -V, --version: show version and exit\n"); } int main (int argc, char **argv) { int option; bool verbose=false, del=false, delTag=false, quiet=false; static struct option long_options[] = { {"delete",no_argument,0,'D'}, {"help",no_argument,0,'h'}, {"quiet",no_argument,0,'q'}, {"delete-tag",no_argument,0,'T'}, {"verbose",no_argument,0,'v'}, {"version",no_argument,0,'V'}, {0,0,0,0} }; #ifdef NLS setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif // un altre dia, per defecte llegir *.mp3 ... if (argc==1) { usage(); return 1; } // supress getopt error message opterr = 0; while ((option = getopt_long(argc, argv, "DhqTvV",long_options,0)) != EOF) switch (option) { case 'D': del=true; break; case 'h': usage(); return 0; break; case 'q': quiet=true; verbose=false; break; case 'T': delTag=true; break; case 'v': verbose=true; quiet=false; break; case 'V': cerr << APPNAME << " - " << _("version") << ' ' << VERSION << _("build") << ' ' << __DATE__ << '\n'; return 0; default: cerr << APPNAME << ": " << _("option") << " '" << argv[optind-1] << "' " << _("is not recognized or bad used") << '\n'; usage(); return 1; } if (delTag && !del) { cerr << APPNAME << _(": flag -T requires -D. ignoring -T") << endl; delTag = false; } if (argc<=optind) { // hauríem de fer *.mp3 ... ? cerr << APPNAME << _(": no input file(s)") << endl; usage(); return 1; } argv += optind; u_int32_t error_files = 0; u_int32_t frames, stream_length; u_int32_t mode = del?qfile::READWRITE:qfile::READ; caddr_t clean_offset, clean_block_begin, clean_block_end; qmp3frameheader *frame; u_int32_t skipped, total_skipped; do { total_skipped = 0; try { qfile file(*argv,mode); bool hasTag; qtag *tag; if (file.getSize()isValid(); if (hasTag) cerr << *argv << ": " << *tag << endl; else if (verbose) cerr << *argv << _(": no tag") << endl; } frames = 0; stream_length = file.getSize()-(hasTag?qtag::LENGTH:0); try { frame = new qmp3frameheader(file.getMap(),file.getSize()); } catch (qexception e) { cerr << file.getName() << ": " << e << endl; error_files++; continue; // sembla que no xuti...potser si: quan prova de desmapejar el qfile pq surt del seu àmbit, i crec que peta sempre que vol desmapejar un fitxer de mida zero. ok. } clean_offset = file.getMap()-1; clean_block_begin = frame->getMap(); skipped = frame->getMap()-file.getMap(); if (skipped) { if (!quiet) cerr << *argv << ": " << _("skipped") << ' ' << skipped << ' ' << _("bytes of garbage at the beginning") << '\n'; total_skipped += skipped; stream_length -= skipped; } if (stream_length >= frame->getLength()) { stream_length -= frame->getLength(); clean_block_end = frame->getMap()+frame->getLength()-1; frames++; } else if (!quiet) cerr << *argv << ": " << _("first frame incomplete") << ": " << stream_length << _(" of ") << frame->getLength() << ' ' << _("bytes") << '\n'; while (stream_length) { try { skipped = frame->setNext(stream_length); } catch (qexception e) { if (!quiet) cerr << *argv << ": " << stream_length << _(" bytes of garbage at the end"); if (verbose) cerr << " (" << file.getSize()-stream_length << ',' << file.getSize() << ')'; if (!quiet) cerr << endl; total_skipped += stream_length; stream_length = 0; break; } if (skipped) { if (!quiet) cerr << *argv << _(": skipped") << skipped << _(" bytes"); if (verbose) cerr << " (" << clean_block_end-file.getMap()+1 << ".." << frame->getMap()-file.getMap()-1 << ')'; if (!quiet) cerr << endl; if ( clean_block_begin!=clean_offset && (clean_offset!=file.getMap()-1)) { if (del) { if (!quiet) cerr << *argv << _(": moving ") << clean_block_end-clean_block_begin+1 << _(" bytes"); if (verbose) cerr << " (" << clean_offset-file.getMap()+1 << ".." << clean_offset-file.getMap()+1+clean_block_end-clean_block_begin << ") <-- (" << clean_block_begin-file.getMap() << ".." << clean_block_end-file.getMap() << ")"; if (!quiet) cerr << endl; file.move ((u_int32_t)(clean_block_begin-file.getMap()), (u_int32_t)(clean_block_end-file.getMap()), (u_int32_t)(clean_offset+1-file.getMap())); } clean_offset += clean_block_end-clean_block_begin+1; } else clean_offset = clean_block_end; clean_block_begin = frame->getMap(); total_skipped += skipped; stream_length -= skipped; } if (stream_length >= frame->getLength()) { stream_length -= frame->getLength(); clean_block_end = frame->getMap()+frame->getLength()-1; frames++; } else { if (!quiet) cerr << *argv << _(": last frame (") << frames << _(") truncated: ") << stream_length << _(" of ") << frame->getLength() << _(" bytes\n"); total_skipped += stream_length; stream_length = 0; break; } } if (clean_block_end>clean_block_begin && clean_block_begin>clean_offset && (clean_offsetgetMap()-file.getMap()), (u_int32_t)(tag->getMap()-file.getMap()+qtag::LENGTH-1), (u_int32_t)(clean_offset+1-file.getMap())); if (!quiet) cerr << *argv << _(": moving tag (") << qtag::LENGTH << ")"; if (verbose) cerr << " (" << clean_offset-file.getMap()+1 << ".." << clean_offset-file.getMap()+1+qtag::LENGTH-1 << ") <-- (" << tag->getMap()-file.getMap() << ".." << tag->getMap()-file.getMap()+qtag::LENGTH-1 << ')'; if (!quiet) cerr << endl; } clean_offset += qtag::LENGTH; } } else clean_offset += qtag::LENGTH; } if (total_skipped) { if (!quiet) cerr << *argv << ": " << total_skipped << _(" of ") << file.getSize() << _(" discardable bytes\n"); if (del) { if (!quiet) cerr << *argv << _(": truncating to ") << file.getSize()-total_skipped << _(" bytes\n"); file.truncate(file.getSize()-total_skipped); } } if (verbose) { if (del) { qmp3 mp3(*argv); cerr << mp3 << endl; // quedaria millor la versió 'verbose...' } else cerr << *argv << ": " << frames << _(" frames, ") << clean_offset-file.getMap()+1 << _(" bytes\n"); } if (hasTag) delete tag; } catch (qexception e) { cerr << *argv << ": " << e << endl; error_files++; } if (total_skipped) error_files++; } while (*++argv); if (error_files && verbose) cerr << error_files << _(" error files found\n"); }