pax_global_header00006660000000000000000000000064146163734570014532gustar00rootroot0000000000000052 comment=9086b36d2b434af3eb7977e17653b41d01da92b2 libcdio-paranoia-release-10.2-2.0.2/000077500000000000000000000000001461637345700167245ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/.circleci/000077500000000000000000000000001461637345700205575ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/.circleci/config.yml000066400000000000000000000042561461637345700225560ustar00rootroot00000000000000version: 2.1 jobs: build: working_directory: ~/rocky/libcdio-paranoia parallelism: 1 shell: /bin/bash --login environment: CIRCLE_ARTIFACTS: /tmp/circleci-artifacts CIRCLE_TEST_REPORTS: /tmp/circleci-test-results docker: - image: cimg/base:2022.09 auth: username: rockyb password: $DOCKERHUB_PASSWORD steps: - checkout # Stuff we want to do - run: sudo apt-get update && sudo apt-get install -y libcdio-dev automake libtool - run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS - run: sh ./autogen.sh - run: sh ./configure --enable-maintainer-mode - run: make - restore_cache: keys: # This branch if available - v2-dependencies-{{ .Branch }}- # Default branch if not - v2-dependencies-master- # Any branch if there are none on the default branch - this should be unnecessary if you have your default branch configured correctly - v2-dependencies- # Save dependency cache - save_cache: key: v2-dependencies-{{ .Branch }}-{{ epoch }} paths: # This is a broad list of cache paths to include many possible development environments # You can probably delete some of these entries - vendor/bundle - ~/virtualenvs - ~/.m2 - ~/.ivy2 - ~/.bundle - ~/.go_workspace - ~/.gradle - ~/.cache/bower # Test # This would typically be a build job when using workflows, possibly combined with build # This is based on your 1.0 configuration file or project settings - run: make check - store_test_results: path: /tmp/circleci-test-results # Save artifacts - store_artifacts: path: /tmp/circleci-artifacts - store_artifacts: path: /tmp/circleci-test-results # The resource_class feature allows configuring CPU and RAM resources for each job. Different resource classes are available for different executors. https://circleci.com/docs/2.0/configuration-reference/#resourceclass resource_class: large libcdio-paranoia-release-10.2-2.0.2/.github/000077500000000000000000000000001461637345700202645ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/.github/FUNDING.yml000066400000000000000000000013461461637345700221050ustar00rootroot00000000000000# These are supported funding model platforms github: [rocky] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: rocky issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry polar: # Replace with a single Polar username custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] libcdio-paranoia-release-10.2-2.0.2/.gitignore000066400000000000000000000011371461637345700207160ustar00rootroot00000000000000*.exe *.log *.stackdump *.trs *~ /*.directive /*.directive.asc /.python-version /.vscode /ChangeLog /INSTALL /Makefile /Makefile.in /README /aclocal.m4 /autom4te.cache /cd-paranoia /compile /config.guess /config.h /config.h.in /config.log /config.rpath /config.status /config.sub /configure /cov-int /depcomp /dist /install-sh /libcdio-*.sig /libcdio-*.tar.bz2 /libcdio-*.tar.gz /libcdio-paranoia-10.2* /libcdio-paranoia.tgz /libcdio_cdda.pc /libcdio_paranoia.pc /libtool /ltmain.sh /missing /stamp-h1 /test-driver /test/data/cdda-be.bin /test/data/cdda-be.cue /test/data/cdda-le.bin /test/data/cdda-le.cue libcdio-paranoia-release-10.2-2.0.2/.travis.yml000066400000000000000000000005401461637345700210340ustar00rootroot00000000000000language: c # just to make the config validator happy os: osx compiler: - gcc addons: homebrew: packages: - [ autoconf, automake, libcdio, pkg-config ] update: true jobs: include: - os: osx name: macOS env: osx_image: xcode9.4 # run the tests script: autoreconf -i -f && ./configure && make && make check libcdio-paranoia-release-10.2-2.0.2/AUTHORS000066400000000000000000000003571461637345700200010ustar00rootroot00000000000000This is a port to libcdio from cdparanoia Monty wrote cdparanoa Rocky Bernstein did the initial port to libcdio Robert Kausch updated library to include cdparanoia 10.2 features libcdio-paranoia-release-10.2-2.0.2/COPYING000066400000000000000000001045131461637345700177630ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state 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) 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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 Lesser General Public License instead of this License. But first, please read . libcdio-paranoia-release-10.2-2.0.2/INSTALL.md000066400000000000000000000366761461637345700203760ustar00rootroot00000000000000# Installation Instructions Copyright (C) 1994-1996, 1999-2002, 2004-2012 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. ## Basic Installation Briefly, the shell commands `./configure; make; make install` should configure, build, and install this package. GNU make or a GNU-make-compatible "make" program, like[`remake`](http://bashdb.sourceforge.net/remake). The following more-detailed instructions are generic; see the `README.md` file for instructions specific to this package. Some packages provide this `INSTALL` file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages ca be found in *note Makefile Conventions: (standards)Makefile Conventions. The `configure` shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile` in each directory of the package. It may also create one or more `.h` files containing system-dependent definitions. Finally, it creates a shell script `config.status` that you can run in the future to recreate the current configuration, and a file `config.log` containing compiler output (useful mainly for debugging `configure`). It can also use an optional file (typically called `config.cache` and enabled with `--cache-file=config.cache` or simply `-C`) that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure` could check whether to do them, and mail diffs or instructions to the address given in the `README.md` so they can be considered for the next release. If you are using the cache, and at some point `config.cache` contains results you don't want to keep, you may remove or edit it. The file `configure.ac` (or `configure.in`) is used to create `configure` by a program called `autoconf`. You need `configure.ac` if you want to change it or regenerate `configure` using a newer version of `autoconf`. The simplest way to compile this package is: 1. `cd` to the directory containing the package's source code and type `./configure` to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make` to compile the package. 3. Optionally, type `make check` to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install` to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck` to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean`. To also remove the files that `configure` created (so you can compile the package for a different kind of computer), type `make distclean`. There isalso a `make maintainer-clean` target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall` to remove the installed files again. In practice, not all packages have tested that uninstallationa works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck`, which can by used by developers to test that all other targets like `make install` and `make uninstall` work correctly.This target is generally not run by end users. ## Compilers and Options Some systems require unusual options for compilation or linking that he `configure` script does not know about. Run `./configure --help` for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix See [Defining Variables](#defining-variables) for more details. ## Compiling For Multiple Architectures You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make`. `cd` to the directory where you want the object files and executables to go and run the `configure` script. `configure` automatically checks for the source code in the directory that `configure` is in and in `..`. This is known as a "VPATH" build. With a non-GNU `make`, it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean` before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch` option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo` tool if you have problems. ## Installation Names By default, `make install` installs the package's commands under `/usr/local/bin`, include files under `/usr/local/include`, etc. You can specify an installation prefix other than `/usr/local` by giving `configure` the option `--prefix=PREFIX`, where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX` to `configure', the package uses *PREFIX* as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR` to specify different values for particular kinds of files. Run `configure --help` for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}`, so that specifying just `--prefix` will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure`; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install` command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory` will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}`. Any directories that were specified during `configure`, but not in terms of `${prefix}`, must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. 1The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. ## Optional Features If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. ## Particular systems On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX `make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as `configure' are involved. Use GNU `make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb` early in your `PATH`. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin`. So, if you need `/usr/ucb` in your `PATH`, put it _after_ `/usr/bin`. On Haiku, software installed for all users goes in `/boot/common`, not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common On FreeBSD and other BSD-derived OS's, use GNU `make' to build. FreeBSD `make' doesn't support 100% of GNU `make` syntax and builds may fail. Install GNU `make` or `remake` on FreeBSD 10.0 and newer as follows: /usr/sbin/pkg install gmake after that use `gmake` instead of `make` for all building tasks, e.g.: /usr/local/bin/gmake install ## Specifying the System Type There may be some features `configure` cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure` can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE` option. *TYPE* can either be a short name for the system type, such as `sun4`, or a canonical name which has the form: CPU-COMPANY-SYSTEM where *SYSTEM* can have one of these forms: OS KERNEL-OS See the file `config.sub` for the possible values of each field. If `config.sub` isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE` to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE`. ## Sharing Defaults If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site` that gives default values for variables like `CC`, `cache_file`, and `prefix'. `configure' looks for `PREFIX/share/config.site` if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE` environment variable to the location of the site script. A warning: not all `configure` scripts look for a site script. ## Defining Variables Variables not defined in a site shell script can be set in the environment passed to `configure`. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure` command line, using `VAR=value`. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc` to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL` due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash ## `configure' Invocation `configure' recognizes the following options to control how it operates. `--help` `-h` Print a summary of all of the options to `configure`, and exit. `--help=short` `--help=recursive` Print a summary of the options unique to this package's `configure`, and exit. The `short` variant lists options used only in the top level, while the `recursive` variant lists options also present in any nested packages. `--version` `-V` Print the version of Autoconf used to generate the `configure` script, and exit. `--cache-file=FILE` Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache` `-C` Alias for `--cache-file=config.cache`. `--quiet` `--silent` `-q` Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null` (any error messages will still be shown). `--srcdir=DIR` Look for the package's source code in directory *DIR*. Usually `configure' can determine that directory automatically. `--prefix=DIR` Use DIR as the installation prefix. See [Installation Names](#installation-names) for more details, including other options available for fine-tuning the installation locations. `--no-create` `-n` Run the configure checks, but stop before creating any output files. `configure` also accepts some other, not widely useful, options. Run `configure --help` for more details. libcdio-paranoia-release-10.2-2.0.2/Makefile.am000066400000000000000000000031241461637345700207600ustar00rootroot00000000000000# Copyright (C) 2011, 2012, 2015, 2020, 2024 # Rocky Bernstein # ## Process this file with automake to produce Makefile.in ## which configure then turns into a Makefile ... ## which make can then use to produce stuff. Isn't configuration simple? AUTOMAKE_OPTIONS = dist-bzip2 EXTRA_DIST = \ THANKS \ NEWS.md \ INSTALL.md \ README.md \ make-check-filter.rb \ example/README \ COPYING \ $(wildcard test/data/*.bin) \ $(wildcard test/data/*.cue) \ $(wildcard test/data/*.iso) \ $(wildcard test/*.right) SUBDIRS = doc include lib src test example paranoiapcs = libcdio_paranoia.pc libcdio_cdda.pc # Note that README and INSTALL are not made by # default nor should the need to be #: README text from Markdown README: README.md pandoc -f markdown -t plain --wrap=none $< -o $@ #: INSTALL text from Markdown INSTALL: INSTALL.md pandoc -f markdown -t plain --wrap=none $< -o $@ # pkg-config(1) related rules pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libcdio_paranoia.pc libcdio_cdda.pc $(pkgconfig_DATA): config.status #: run regression tests test: check #: Run all tests without bloated output check-short: $(MAKE) check 2>&1 | ruby @abs_top_srcdir@/make-check-filter.rb #: Make documentation via Doxygen http://www.stack.nl/~dimitri/doxygen/ doxygen: -( cd ${top_srcdir}/doc/doxygen && /bin/sh ${srcdir}/run_doxygen ) MAINTAINERCLEANFILES = ChangeLog *.rej *.orig if MAINTAINER_MODE .PHONY: ChangeLog #: Create ChangeLog from version control ChangeLog: git log --pretty --numstat --summary | $(GIT2CL) >$@ ACLOCAL_AMFLAGS=-I m4 endif libcdio-paranoia-release-10.2-2.0.2/NEWS.md000066400000000000000000000051271461637345700200270ustar00rootroot0000000000000010.2+2.0.2 --------- 2019-05-0-7 - A 6-year-old bug, seen primarily by Whipper users, concerning adjusting of CD-drives that have large sample offsets, or negative offsets has been fixed. Fix is from and thanks are due to buddyabaddon. https://github.com/rocky/libcdio-paranoia/issues/14 and https://github.com/rocky/libcdio-paranoia/pull/38 - Code has moved from savannah.gnu.org to github. CircleCI testing is now incorporated into builds. - Add test on LSN on span check errors, and give a better message when there is a problem. https://github.com/rocky/libcdio-paranoia/pull/39 - Require libcdio at least 2.0.0 - Remove dead code after exit. https://github.com/rocky/libcdio-paranoia/pull/32 - Fix manpage for Japanese. https://github.com/rocky/libcdio-paranoia/pull/27 - Add notes for using gmake for building on FreeBSD. https://github.com/rocky/libcdio-paranoia/pull/26 10.2+2.0.1 --------- 2019-09-16 - cdda toc routines now included (fixes #21) - "make distcheck" broken in 2.0.0 works properly again - Remove some gcc/clang warnings 10.2+2.0.0 --------- 2019-01-26 This work was done by Edd Barrett and Thomas Schmitt - OpenBSD tolerance - typos in manual page and README - Do not attempt to call a NULL callback (issue #15) from mskamp - Switch to semantic versioning number in libcdio portion and match up with libcdio version 10.2+0.94+2 ----------- 2017-08-22 - Add `--force-overread` Force overreading into the lead-out portion of the disc. This option is only applicable when using the `-O` option with a positive sample offset value. Many drives are not capable of reading into this portion of the disc and attempting to do so on those drives will produce read errors and possibly hard lockups 10.2+0.94+1 ----------- 2017-03-25 - Fix problem where end of span seems to default to last track. Savannah bug 43444 - Fix NULL pointer dereference that occurs when byte swapping is needed. MR #4 - Re-silence recently added gcc -Wunused-result warnings - Use `@LIBS@` figured out by autoconf when linking (for `-lrt` on Linux). - Incorrect track was getting used in matching. See Savannah bug 49831 and MR #7, #8 and #10 10.2+0.93+1 ----------- 2014-09-29 - Add `cdio_cddap_free_messages` function - Start using Coverty Static analysis - Update OS versions we recognize - Upgrade libcdio-paranoia to paranoia version 10.2 - Bug fixes on MS Windows and other bug fixes - Redo license so everything is GPL3 10.2+0.90 --------- 2012-12-24 Split off from libcdio to allow more flexible licensing and to be compatible with cdparanoia-III-10.2's license. And also, libcdio is just too large. libcdio-paranoia-release-10.2-2.0.2/README.md000066400000000000000000000012751461637345700202100ustar00rootroot00000000000000[![Build Status Circle](https://circleci.com/gh/rocky/libcdio-paranoia.svg?&style=shield)](https://circleci.com/gh/rocky/libcdio-paranoia) [![Packaging status](https://repology.org/badge/tiny-repos/libcdio-paranoia.svg)](https://repology.org/project/libcdio-paranoia/versions) [![Packaging status](https://repology.org/badge/vertical-allrepos/libcdio-paranoia.svg)](https://repology.org/project/libcdio-paranoia/versions) This is a port of xiph.org's [cdda paranoia](https://www.xiph.org/paranoia/) to use libcdio for CDROM access. By doing this, cdparanoia runs on platforms other than GNU/Linux. See the [CDDA FAQ](https://www.xiph.org/paranoia/faq.html) for more information about cdparanoia. libcdio-paranoia-release-10.2-2.0.2/THANKS000066400000000000000000000006271461637345700176440ustar00rootroot00000000000000Adrian Reber Redhat packaging and going over licensing to make like CD-Paranoia Daniel Schwarz log-summary option in cd-paranoia. Peter J. Creath removal of libpopt, paranoia documentation, some bug fixes to cd-* programs and the paranoia lib Robert Kausch Update paranoia from 0.98 to 0.10.2 which includes drive cache management a10footsquirrel Paranoia bug in not finding the right track libcdio-paranoia-release-10.2-2.0.2/autogen.sh000077500000000000000000000005441461637345700207300ustar00rootroot00000000000000#!/bin/sh # Run this to generate all the initial makefiles, etc. # Additional options go to configure. # For OpenBSD export AUTOCONF_VERSION=2.69 export AUTOMAKE_VERSION=1.15 echo "Rebuilding ./configure with autoreconf..." autoreconf -f -i rc=$? if [ $rc -ne 0 ]; then echo "autoreconf failed" exit $rc fi ./configure --enable-maintainer-mode "$@" libcdio-paranoia-release-10.2-2.0.2/configure.ac000066400000000000000000000372451461637345700212250ustar00rootroot00000000000000dnl Copyright (C) 2011-2017, 2019, 2024 dnl Rocky Bernstein dnl dnl This program is free software: you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation, either version 3 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the dnl GNU General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program. If not, see . define(RELEASE_NUM, 2.0.2) define(PARANOIA_VERSION, 10.2) define(LIBCDIO_PARANOIA_VERSION_STR, $1+$2) AC_DEFINE([PACKAGE], [libcdio-paranoia], [cdparanoia using libcdio]) AC_PREREQ([2.71]) AC_INIT([libcdio-paranoia],[LIBCDIO_PARANOIA_VERSION_STR(PARANOIA_VERSION,RELEASE_NUM)],[libcdio-help@gnu.org]) AC_CONFIG_SRCDIR(src/cd-paranoia.c) AM_INIT_AUTOMAKE([foreign]) AC_CANONICAL_HOST AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) AM_MISSING_PROG(HELP2MAN, help2man, $missing_dir) AM_MISSING_PROG(GIT2CL, git2cl, $missing_dir) AM_MAINTAINER_MODE AM_SANITY_CHECK AC_ARG_WITH(cd-paranoia-name, AS_HELP_STRING([--with-cd-paranoia-name],[name to use as the cd-paranoia program name (default cd-paranoia)]), cd_paranoia_name="${withval}", cd_paranoia_name="cd-paranoia") CDPARANOIA_NAME="$cd_paranoia_name" AC_SUBST(CDPARANOIA_NAME) AC_ARG_WITH(versioned-libs, AS_HELP_STRING([--without-versioned-libs],[build versioned library symbols (default enabled if you have GNU ld)]), enable_versioned_libs="${withval}", enable_versioned_libs=yes) AC_ARG_ENABLE(example-progs, AS_HELP_STRING([--disable-example-progs],[Don't build libcdio-paranoia sample programs])) AC_ARG_ENABLE([cxx], AS_HELP_STRING([--disable-cxx],[Disable C++ bindings (default enabled)])) AM_CONDITIONAL([ENABLE_CXX_BINDINGS], [test "x$enable_cxx" != "xno"]) AC_ARG_ENABLE(cpp-progs, AS_HELP_STRING([--enable-cpp-progs],[make C++ example programs (default enabled)])) AM_CONDITIONAL(ENABLE_CPP, test x"$enable_cpp_progs" = "xyes") dnl cheeck whether ld supports --version-script AC_ARG_ENABLE(ld-version-script, AS_HELP_STRING([--disable-ld-version-script], [Disable linker version script for libraries (Defauilt is to use linker script if the linger supports it)]), [enable_version_script=$enableval], [enable_version_script=yes]) AM_CONDITIONAL(VERSION_SCRIPT, test "x$enable_version_script" = "xyes") # Do we have GNU ld? If we don't, we can't build versioned symbols. AC_ARG_ENABLE(example-progs, AS_HELP_STRING([--disable-example-progs],[Don't build libcdio sample programs])) AM_CONDITIONAL(BUILD_EXAMPLES, test "x$enable_example_progs" != "xno") AM_CONDITIONAL(BUILD_VERSIONED_LIBS, test "x$enable_versioned_libs" = "xyes") dnl We use C AC_PROG_CC AM_PROG_CC_C_O dnl We also use C++ in example programs and for CXX bindings AC_PROG_CXX dnl Checks for programs. AC_USE_SYSTEM_EXTENSIONS AC_PROG_MKDIR_P AC_PROG_AWK AC_SUBST(AWK) AC_ARG_VAR([NM], [utility for listing symbols from object files]) AC_CHECK_TOOL([NM], [nm]) if test "x$GCC" != "xyes" then AC_MSG_WARN([ *** non GNU CC compiler detected. *** This package has not been tested very well with non GNU compilers *** you should try to use 'gcc' for compiling this package.]) else WARN_CFLAGS="-Wall -Wchar-subscripts -Wmissing-prototypes -Wmissing-declarations -Wunused -Wpointer-arith -Wwrite-strings -Wnested-externs -Wno-sign-compare" for WOPT in $WARN_CFLAGS; do SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $WOPT" AC_MSG_CHECKING([whether $CC understands $WOPT]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[has_option=yes],[has_option=no]) CFLAGS="$SAVE_CFLAGS" AC_MSG_RESULT($has_option) if test $has_option = yes; then warning_flags="$warning_flags $option" fi unset has_option unset SAVE_CFLAGS done WARNING_FLAGS="$warning_flags" unset warning_flags fi PKG_CHECK_MODULES(LIBCDIO, libcdio >= 2.0.0, [], [AC_MSG_ERROR(Required libcdio library not found. Please get libcdio from http://www.gnu.org/software/libcdio/ and install it.)]) AC_SUBST(LIBCDIO_LIBS) AC_SUBST(LIBCDIO_CFLAGS) # We use Perl for documentation and regression tests AC_PATH_PROG(PERL, perl, false) AC_SUBST(PERL) AM_CONDITIONAL(HAVE_PERL, test "$PERL" != "false") # We use a diff in regression testing AC_PATH_PROG(DIFF, diff, no) DIFF_OPTS= if test "$DIFF" = no ; then AC_PATH_PROG(DIFF, cmp, no) else # Try for GNU diff options. # MSDOG output uses \r\n rather than \n in tests for diff_opt in -w --unified ; do if $DIFF $diff_opt ./configure ./configure > /dev/null 2>&1; then AC_MSG_RESULT([adding $diff_opt to diff in regression tests]) DIFF_OPTS="$DIFF_OPTS $diff_opt" fi done fi AC_SUBST(DIFF) AC_SUBST(DIFF_OPTS) # We use cmp, dd, and wc in cd-paranoia regression testing AC_PATH_PROG([CMP], [cmp], [no]) AC_SUBST([CMP]) AC_PATH_PROG([DD], [dd], [no]) AC_SUBST([DD]) AC_PATH_PROG([WC], [wc], [no]) AC_SUBST([WC]) dnl headers AC_CHECK_HEADERS(assert.h errno.h fcntl.h glob.h limits.h pwd.h) AC_CHECK_HEADERS(stdarg.h stdbool.h stdio.h sys/cdio.h sys/param.h \ sys/time.h sys/timeb.h sys/utsname.h) # FreeBSD 4 has getopt in unistd.h. So we include that before # getopt.h AC_CHECK_HEADERS(unistd.h getopt.h) AC_SUBST(SBPCD_H) AC_SUBST(TYPESIZES) dnl compiler AC_C_BIGENDIAN AC_C_CONST AC_C_INLINE dnl ISOC99_PRAGMA AC_MSG_CHECKING([whether $CC supports ISOC99 _Pragma()]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[_Pragma("pack(1)")]])],[ ISOC99_PRAGMA=yes AC_DEFINE(HAVE_ISOC99_PRAGMA, [], [Supports ISO _Pragma() macro]) ],[ISOC99_PRAGMA=no]) AC_MSG_RESULT($ISOC99_PRAGMA) ## ## Check for S_ISSOCK() and S_ISLNK() macros ## AC_MSG_CHECKING(for S_ISLNK() macro) AC_LINK_IFELSE([AC_LANG_PROGRAM([ #ifdef HAVE_SYS_STAT_H # include #endif ],[return S_ISLNK(0);])], [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_S_ISLNK, [], [Define this defines S_ISLNK()]) ], [ AC_MSG_RESULT(no) ]) AC_MSG_CHECKING([for S_ISSOCK() macro]) AC_LINK_IFELSE([AC_LANG_PROGRAM([ #ifdef HAVE_SYS_STAT_H # include #endif ],[return S_ISSOCK(0);])], [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_S_ISSOCK, [], [Define this defines S_ISSOCK()]) ], [ AC_MSG_RESULT(no) ]) AC_MSG_CHECKING([for struct timespec]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #ifdef HAVE_SYS_TIME_H #include #endif ],[struct timespec ts;])], [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_STRUCT_TIMESPEC, [], [Define this if you have struct timespec]) ], [ AC_MSG_RESULT(no) ]) dnl empty_array_size AC_MSG_CHECKING([how to create empty arrays]) empty_array_size="xxxx" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[struct { int foo; int bar[]; } doo;]])],[empty_array_size=""],[]) if test "x$empty_array_size" = "xxxx";then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[struct { int foo; int bar[0]; } doo;]])],[empty_array_size="0"],[]) fi if test "x$empty_array_size" = "xxxx" then AC_MSG_ERROR([compiler is unable to creaty empty arrays]) else AC_DEFINE_UNQUOTED(EMPTY_ARRAY_SIZE, $empty_array_size, [what to put between the brackets for empty arrays]) changequote(`,') msg="[${empty_array_size}]" changequote([,]) AC_MSG_RESULT($msg) fi dnl dnl Enable the creation of shared libraries under Win32. dnl AC_REQUIRE(AC_CANONICAL_HOST)_LT_SET_OPTION([LT_INIT],[win32-dll]) dnl m4_warn([obsolete],[AC_LIBTOOL_WIN32_DLL: Remove this warning and the call to _LT_SET_OPTION when you dnl put the 'win32-dll' option into LT_INIT's first parameter.]) dnl LT_INIT tests whether we have GNU ld dnl this must come before checking --with-versioned-libs dnl which requires GNU ld. LT_INIT dnl regression tests need native-style absolute paths. dnl native_abs_top_srcdir is used here. case $srcdir in .) # We are building in place. native_abs_top_srcdir=$ac_pwd ;; changequote(`,') [\\/]* | ?:[\\/]* ) # Absolute name. changequote([,]) native_abs_top_srcdir=$srcdir ;; *) # Relative name. native_abs_top_srcdir=$ac_pwd/$srcdir ;; esac AC_SUBST(native_abs_top_srcdir) dnl system # FIXME: # I believe some OS's require -lm, but I don't recall for what function # When we find it, put it in below instead of "cos". AC_CHECK_LIB(m, cos, [LIBS="$LIBS -lm"; COS_LIB="-lm"]) CFLAGS="$CFLAGS $WARN_CFLAGS" AC_SUBST(COS_LIB) # Linux has clock_gettime in librt AC_CHECK_LIB(rt, clock_gettime) if test "$with_gnu_ld" != yes; then AC_MSG_WARN([I don't see GNU ld. I'm going to assume --without-versioned-libs]) enable_versioned_libs='no' fi # We also need GNU make to build versioned symbols. if test "x$enable_versioned_libs" = "xyes" ; then if test "x$enable_version_script" = "xyes"; then if test -n "$MAKE" ; then $MAKE --version 2>/dev/null >/dev/null if test "$?" -ne 0 ; then AC_MSG_ERROR(Either set MAKE variable to GNU make or use --without-versioned-libs option) fi else make --version 2>/dev/null >/dev/null if test "$?" -ne 0 ; then AC_MSG_ERROR(Either set MAKE variable to GNU make or use --without-versioned-libs option) fi fi else make --version 2>/dev/null >/dev/null if test "$?" -ne 0 ; then AC_MSG_ERROR(Either set MAKE variable to GNU make or use --without-versioned-libs option) fi fi fi AM_CONDITIONAL(CYGWIN, test "x$CYGWIN" = "xyes") dnl include check if LD supports linker scripts gl_LD_VERSION_SCRIPT dnl Checks for header files. LIBCDIO_CDDA_LIBS='$(top_builddir)/lib/cdda_interface/libcdio_cdda.la' LIBCDIO_PARANOIA_CFLAGS='-I$(top_builddir)/include -I$(top_srcdir)/include/' LIBCDIO_PARANOIA_LIBS='$(top_builddir)/lib/paranoia/libcdio_paranoia.la' AC_SUBST(LIBCDIO_CDDA_LIBS) AC_SUBST(LIBCDIO_PARANOIA_CFLAGS) AC_SUBST(LIBCDIO_PARANOIA_LIBS) dnl Libtool flag for strict linkage LT_NO_UNDEFINED= case $host_os in aix*) ## Don't use AIX driver until starts to really work ## cd_drivers="${cd_drivers}, AIX" ## AC_DEFINE([HAVE_AIX_CDROM], [1], ## [Define 1 if you have AIX CD-ROM support]) ;; darwin[[6-9]].*|darwin1[[0-4]].*) AC_CHECK_HEADERS(IOKit/IOKitLib.h CoreFoundation/CFBase.h, [have_iokit_h="yes"]) if test "x$have_iokit_h" = "xyes" ; then AC_DEFINE([HAVE_DARWIN_CDROM], [1], [Define 1 if you have Darwin OS X-type CD-ROM support]) DARWIN_PKG_LIB_HACK="-Wl,-framework,CoreFoundation -Wl,-framework,IOKit" dnl Prior to Mac OS X 10.4 (Tiger), DiskArbitration was a private framework. dnl It's now public, and it's needed to do cd/dvd unmount/eject. AC_MSG_CHECKING([for DiskArbitration framework]) ac_save_LIBS="$LIBS" LIBS="$LIBS -framework CoreFoundation -framework DiskArbitration" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[]])], [have_diskarbitration_framework=yes], [have_diskarbitration_framework=no]) LIBS="$ac_save_LIBS" AC_MSG_RESULT([$have_diskarbitration_framework]) if test x"$have_diskarbitration_framework" = x"yes"; then AC_DEFINE([HAVE_DISKARBITRATION], 1, [Define to 1 if you have the Apple DiskArbitration framework]) DARWIN_PKG_LIB_HACK="$DARWIN_PKG_LIB_HACK -Wl,-framework,DiskArbitration" fi AC_SUBST(DARWIN_PKG_LIB_HACK) LIBCDIO_LIBS="$LIBCDIO_LIBS $DARWIN_PKG_LIB_HACK" cd_drivers="${cd_drivers}, Darwin" fi ;; linux*|uclinux) AC_CHECK_HEADERS(linux/version.h linux/major.h) AC_CHECK_HEADERS(linux/cdrom.h, [have_linux_cdrom_h="yes"]) if test "x$have_linux_cdrom_h" = "xyes" ; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ #include struct cdrom_generic_command test; int has_timeout=sizeof(test.timeout);]])],[AC_DEFINE([HAVE_LINUX_CDROM_TIMEOUT], [1], [Define 1 if timeout is in cdrom_generic_command struct])],[]) AC_DEFINE([HAVE_LINUX_CDROM], [1], [Define 1 if you have Linux-type CD-ROM support]) cd_drivers="${cd_drivers}, GNU/Linux" fi ;; bsdi*) AC_CHECK_HEADERS(dvd.h, [have_bsdi_dvd_h="yes"]) if test "x$have_bsdi_dvd_h" = "xyes" ; then AC_DEFINE([HAVE_BSDI_CDROM], [1], [Define 1 if you have BSDI-type CD-ROM support]) LIBS="$LIBS -ldvd -lcdrom" LIBCDIO_LIBS="$LIBCDIO_LIBS -lcdrom" cd_drivers="${cd_drivers}, BSDI" fi ;; sunos*|sun*|solaris*) AC_DEFINE([HAVE_SOLARIS_CDROM], [1], [Define 1 if you have Solaris CD-ROM support]) cd_drivers="${cd_drivers}, Solaris" ;; cygwin*) AC_DEFINE([CYGWIN], [1], [Define 1 if you are compiling using cygwin]) AC_DEFINE([HAVE_WIN32_CDROM], [1], [Define 1 if you have MinGW CD-ROM support]) LIBS="$LIBS -lwinmm" LT_NO_UNDEFINED="-no-undefined" cd_drivers="${cd_drivers}, MinGW" AC_DEFINE([NEED_TIMEZONEVAR], [1], [Define 1 if you need timezone defined to get timzone defined as a variable. In cygwin it is a function too]) ;; mingw*) AC_CHECK_HEADERS(windows.h) AC_DEFINE([MINGW32], [1], [Define 1 if you are compiling using MinGW]) AC_DEFINE([HAVE_WIN32_CDROM], [1], [Define 1 if you have MinGW CD-ROM support]) LIBS="$LIBS -lwinmm" LT_NO_UNDEFINED="-no-undefined" cd_drivers="${cd_drivers}, MinGW " ;; freebsd[[4-9]].*|freebsd10.*|dragonfly*|kfreebsd*) AC_DEFINE([HAVE_FREEBSD_CDROM], [1], [Define 1 if you have FreeBSD CD-ROM support]) LIBS="$LIBS -lcam" cd_drivers="${cd_drivers}, FreeBSD " ;; netbsd*|openbsd*) AC_DEFINE([HAVE_NETBSD_CDROM], [1], [Define 1 if you have NetBSD CD-ROM support]) # LIBS="$LIBS -lcam" cd_drivers="${cd_drivers}, NetBSD " ;; os2*) AC_DEFINE([HAVE_OS2_CDROM], [1], [Define 1 if you have OS/2 CD-ROM support]) LT_NO_UNDEFINED="-no-undefined" LDFLAGS="$LDFLAGS -Zbin-files" cd_drivers="${cd_drivers}, OS2 " ;; *) AC_MSG_WARN([Don't have OS CD-reading support for ${host_os}...]) AC_MSG_WARN([Will use generic support.]) ;; esac AC_SUBST(LT_NO_UNDEFINED) AC_SUBST(DARWIN_PKG_LIB_HACK) LIBCDIO_PARANOIA_SOURCE_PATH="`pwd`" AC_DEFINE_UNQUOTED(LIBCDIO_PARANOIA_SOURCE_PATH, "$LIBCDIO_SOURCE_PATH", [Full path to libcdio-paranoia top_sourcedir.]) AC_SUBST(LIBCDIO_PARANOIA_SOURCE_PATH) AC_CHECK_FUNCS( [bzero chdir drand48 ftruncate geteuid getgid \ getuid getpwuid gettimeofday lstat memcpy memset \ rand seteuid setegid snprintf setenv unsetenv tzset \ sleep usleep vsnprintf readlink realpath gmtime_r \ localtime_r clock_gettime] ) dnl dnl Output configuration files dnl ## AC_CONFIG_FILES([ po/Makefile.in\ AC_CONFIG_FILES([ Makefile \ doc/Makefile \ doc/doxygen/Doxyfile \ doc/en/Makefile \ doc/en/cd-paranoia.1 \ doc/ja/Makefile \ doc/ja/cd-paranoia.1 \ example/Makefile \ example/C++/Makefile \ include/Makefile \ include/cdio/Makefile \ include/cdio/paranoia/Makefile \ include/cdio/paranoia/version.h \ lib/Makefile \ lib/cdda_interface/Makefile \ lib/paranoia/Makefile \ libcdio_cdda.pc \ libcdio_paranoia.pc \ src/Makefile \ src/usage.txt \ test/data/Makefile test/cdda_interface/Makefile test/cdda_interface/toc.c test/Makefile ]) # AC_CONFIG_FILES([po/Makefile]) AC_CONFIG_FILES([test/check_paranoia.sh], [chmod +x test/check_paranoia.sh]) AC_CONFIG_FILES([test/endian.sh], [chmod +x test/endian.sh]) AC_CONFIG_FILES([test/check_start_track_not_one.sh], [chmod +x test/check_start_track_not_one.sh]) AC_OUTPUT AC_MSG_NOTICE([ Building C++ programs: $(test "x$enable_cxx" != "xno" && echo yes || echo no)]) libcdio-paranoia-release-10.2-2.0.2/doc/000077500000000000000000000000001461637345700174715ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/doc/.gitignore000066400000000000000000000000331461637345700214550ustar00rootroot00000000000000/Makefile /Makefile.in /*~ libcdio-paranoia-release-10.2-2.0.2/doc/Makefile.am000066400000000000000000000017361461637345700215340ustar00rootroot00000000000000# Copyright (C) 2005, 2007, 2008 Rocky Bernstein # # 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 3 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, see . SUBDIRS = en ja EXTRA_DIST = overlapdef.txt mostlyclean-generic: -rm -f *~ \#* .*~ .\#* maintainer-clean-generic: -@echo "This command is intended for maintainers to use;" -@echo "it deletes files that may require special tools to rebuild." -rm -f Makefile.in libcdio-paranoia-release-10.2-2.0.2/doc/doxygen/000077500000000000000000000000001461637345700211465ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/doc/doxygen/.gitignore000066400000000000000000000001101461637345700231260ustar00rootroot00000000000000/Doxyfile /Doxyfile.bak /html /latex /libcdio-paranoia.xml /libcdio.xml libcdio-paranoia-release-10.2-2.0.2/doc/doxygen/Doxyfile.in000066400000000000000000002161421461637345700232670ustar00rootroot00000000000000# Doxyfile 1.7.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = @PACKAGE@ # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class " \ "The $name widget " \ "The $name file " \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = @LIBCDIO_PARANOIA_SOURCE_PATH@ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text " # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../../include/cdio/paranoia ../../lib ../../src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.h *.c # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = ../../example # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is adviced to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the stylesheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the # mathjax.org site, so you can quickly see the result without installing # MathJax, but it is strongly recommended to install a local copy of MathJax # before deployment. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = letter # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = libcdio-paranoia.xml # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will write a font called Helvetica to the output # directory and reference it in all dot files that doxygen generates. # When you want a differently looking font you can specify the font name # using DOT_FONTNAME. You need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES libcdio-paranoia-release-10.2-2.0.2/doc/doxygen/run_doxygen000077500000000000000000000052761461637345700234470ustar00rootroot00000000000000#!/bin/sh # $Id: run_doxygen,v 1.1 2003/11/09 14:11:02 rocky Exp $ # Runs doxygen and massages the output files. # Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. # # Synopsis: run_doxygen --mode=[user|maint|man] v3srcdir v3builddir # # Originally hacked together by Phil Edwards # We can check now that the version of doxygen is >= this variable. DOXYVER=1.2.15 doxygen= find_doxygen() { v_required=`echo $DOXYVER | \ awk -F. '{if(NF<3)$3=0;print ($1*100+$2)*100+$3}'` testing_version= # thank you goat book set `IFS=:; X="$PATH:/usr/local/bin:/bin:/usr/bin"; echo $X` for dir do # AC_EXEEXT could come in useful here maybedoxy="$dir/doxygen" test -f "$maybedoxy" && testing_version=`$maybedoxy --version` if test -n "$testing_version"; then v_found=`echo $testing_version | \ awk -F. '{if(NF<3)$3=0;print ($1*100+$2)*100+$3}'` if test $v_found -ge $v_required; then doxygen="$maybedoxy" break fi fi done if test -z "$doxygen"; then echo run_doxygen error: Could not find Doxygen $DOXYVER in path. 1>&2 print_usage fi } print_usage() { cat 1>&2 <] MODE is one of: user Generate user-level HTML library documentation. maint Generate maintainers' HTML documentation (lots more; exposes non-public members, etc). man Generate user-level man pages. more options when i think of them Note: Requires Doxygen ${DOXYVER} or later; get it at ftp://ftp.stack.nl/pub/users/dimitri/doxygen-${DOXYVER}.src.tar.gz EOF exit 1 } parse_options() { for o do # Blatantly ripped from autoconf, er, I mean, "gratefully standing # on the shoulders of those giants who have gone before us." case "$o" in -*=*) arg=`echo "$o" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) arg= ;; esac case "$o" in --mode=*) mode=$arg ;; --mode | --help | -h) print_usage ;; *) # this turned out to be a mess, maybe change to --srcdir=, etc if test $srcdir = unset; then srcdir=$o elif test $outdir = unset; then builddir=${o} outdir=${o}/doc/doxygen else echo run_doxygen error: Too many arguments 1>&2 exit 1 fi ;; esac done } # script begins here mode=unset srcdir=unset outdir=unset do_html=no do_man=no enabled_sections= DATEtext=`date '+%Y-%m-%d'` parse_options $* find_doxygen $doxygen ./Doxyfile exit 0 # vim:ts=4:et: libcdio-paranoia-release-10.2-2.0.2/doc/en/000077500000000000000000000000001461637345700200735ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/doc/en/.gitignore000066400000000000000000000000461461637345700220630ustar00rootroot00000000000000/Makefile /Makefile.in /cd-paranoia.1 libcdio-paranoia-release-10.2-2.0.2/doc/en/Makefile.am000066400000000000000000000021751461637345700221340ustar00rootroot00000000000000# $Id: Makefile.am,v 1.3 2008/04/17 17:39:48 karl Exp $ # # Copyright (C) 2005, 2008 Rocky Bernstein # # 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 3 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, see . manfiles = cd-paranoia.1 man_MANS = $(manfiles) transform = s,cd-paranoia,@CDPARANOIA_NAME@, EXTRA_DIST = $(manfiles) cd-paranoia.1.in mostlyclean-generic: -rm -f *~ \#* .*~ .\#* maintainer-clean-generic: -@echo "This command is intended for maintainers to use;" -@echo "it deletes files that may require special tools to rebuild." -rm -f Makefile.in $(manfiles) libcdio-paranoia-release-10.2-2.0.2/doc/en/cd-paranoia.1.in000066400000000000000000000262761461637345700227550ustar00rootroot00000000000000.TH @CDPARANOIA_NAME@ 1 "version III release alpha 9.8 libcdio" .SH NAME @CDPARANOIA_NAME@ \- an audio CD reading utility which includes extra data verification features .SH SYNOPSIS .B @CDPARANOIA_NAME@ .RB [ options ] .B span .RB [ outfile ] .SH DESCRIPTION .B @CDPARANOIA_NAME@ retrieves audio tracks from CDDA capable CD-ROM drives. The data can be saved to a file or directed to standard output in WAV, AIFF, AIFF-C or raw format. Most ATAPI, SCSI and several proprietary CD-ROM drive makes are supported; .B @CDPARANOIA_NAME@ can determine if the target drive is CDDA capable. .P In addition to simple reading, .B @CDPARANOIA_NAME@ adds extra-robust data verification, synchronization, error handling and scratch reconstruction capability. .P This version uses the libcdio library for interaction with a CD-ROM drive. The jitter and error correction however are the same as used in Xiph's cdparanoia. .SH OPTIONS .TP .B \-A --analyze-drive Run and log a complete analysis of drive caching, timing and reading behavior; verifies that cdparanoia is correctly modelling a specific drive's cache and read behavior. Implies -vQL. .TP .B \-v --verbose Be absurdly verbose about the autosensing and reading process. Good for setup and debugging. .TP .B \-q --quiet Do not print any progress or error information during the reading process. .TP .B \-e --stderr-progress Force output of progress information to stderr (for wrapper scripts). .TP .B \-V --version Print the program version and quit. .TP .B \-Q --query Perform CD-ROM drive autosense, query and print the CD-ROM table of contents, then quit. .TP .B \-h --help Print a brief synopsis of .B @CDPARANOIA_NAME@ usage and options. .TP .BI "\-l --log-summary " file Save result summary to file. .TP .BI "\-L --log-debug " file Save detailed device autosense and debugging output to a file. .TP .B \-p --output-raw Output headerless data as raw 16 bit PCM data with interleaved samples in host byte order. To force little or big endian byte order, use .B \-r or .B \-R as described below. .TP .B \-r --output-raw-little-endian Output headerless data as raw 16 bit PCM data with interleaved samples in LSB first byte order. .TP .B \-R --output-raw-big-endian Output headerless data as raw 16 bit PCM data with interleaved samples in MSB first byte order. .TP .B \-w --output-wav Output data in Microsoft RIFF WAV format (note that WAV data is always LSB first byte order). .TP .B \-f --output-aiff Output data in Apple AIFF format (note that AIFC data is always in MSB first byte order). .TP .B \-a --output-aifc Output data in uncompressed Apple AIFF-C format (note that AIFF-C data is always in MSB first byte order). .TP .BI "\-B --batch " Cdda2wav-style batch output flag; @CDPARANOIA_NAME@ will split the output into multiple files at track boundaries. Output file names are prepended with 'track#.' .TP .B \-c --force-cdrom-little-endian Some CD-ROM drives misreport their endianness (or do not report it at all); it's possible that @CDPARANOIA_NAME@ will guess wrong. Use .B \-c to force @CDPARANOIA_NAME@ to treat the drive as a little endian device. .TP .B \-C --force-cdrom-big-endian As above but force @CDPARANOIA_NAME@ to treat the drive as a big endian device. .TP .BI "\-n --force-default-sectors " n Force the interface backend to do atomic reads of .B n sectors per read. This number can be misleading; the kernel will often split read requests into multiple atomic reads (the automated Paranoia code is aware of this) or allow reads only wihin a restricted size range. .B This option should generally not be used. .TP .BI "\-d --force-cdrom-device " device Force the interface backend to read from .B device rather than the first readable CD-ROM drive it finds containing a CD-DA disc. This can be used to specify devices of any valid interface type (ATAPI, SCSI or proprietary). .TP .BI "\-g --force-generic-device " device This option is an alias for .B \-d and is retained for compatibility. .TP .BI "\-S --force-read-speed " number Use this option explicitly to set the read rate of the CD drive (where supported). This can reduce underruns on machines with slow disks, or which are low on memory. .TP .BI "\-t --toc-offset " number Use this option to force the entire disc LBA addressing to shift by the given amount; the value is added to the beginning offsets in the TOC. This can be used to shift track boundaries for the whole disc manually on sector granularity. The next option does something similar... .TP .BI "\-T --toc-bias " Some drives (usually random Toshibas) report the actual track beginning offset values in the TOC, but then treat the beginning of track 1 index 1 as sector 0 for all read operations. This results in every track seeming to start too late (losing a bit of the beginning and catching a bit of the next track). \-T accounts for this behavior. Note that this option will cause @CDPARANOIA_NAME@ to attempt to read sectors before or past the known user data area of the disc, resulting in read errors at disc edges on most drives and possibly even hard lockups on some buggy hardware. .TP .BI "\-O --sample-offset " number Some CD-ROM/CD-R drives will add an offset to the position on reading audio data. This is usually around 500-700 audio samples (ca. 1/75 second) on reading. So when @CDPARANOIA_NAME@ queries a specific sector, it might not receive exactly that sector, but shifted by some amount. .P Use this option to force the entire disc to shift sample position output by the given amount; This can be used to shift track boundaries for the whole disc manually on sample granularity. Note that if you are ripping something including the ending of the CD (e.g. the entire disk), this option will cause @CDPARANOIA_NAME@ to attempt to read partial sectors before or past the known user data area, probably causing read errors on most drives and possibly even hard lockups on some buggy hardware. .TP .BI \-E --force-overread Force overreading into the lead-out portion of the disc. This option is only applicable when using the +.B -O +option with a positive sample offset value. Many drives are not capable of reading into this portion of the disc and attempting to do so on those drives will produce read errors and possibly hard lockups. .TP .B \-Z --disable-paranoia Disable .B all data verification and correction features. When using -Z, @CDPARANOIA_NAME@ reads data exactly as would cdda2wav with an overlap setting of zero. This option implies that .B \-Y is active. .TP .B \-z --never-skip[=max_retries] Do not accept any skips; retry forever if needed. An optional maximum number of retries can be specified; for comparison, default without -z is currently 20. .TP .B \-Y --disable-extra-paranoia Disables intra-read data verification; only overlap checking at read boundaries is performed. It can wedge if errors occur in the attempted overlap area. Not recommended. .TP .B \-X --abort-on-skip If the read skips due to imperfect data, a scratch, whatever, abort reading this track. If output is to a file, delete the partially completed file. .TP .B \-x --test-flags mask Simulate CD-reading errors. This is used in regression testing, but other uses might be to see how well a CD-ROM performs under (simulated) CD degradation. mask specifies the artificial kinds of errors to introduced; "or"-ing values from the selection below will simulate the kind of specified failure. .P 0x10 - Simulate under-run reading .TP .SH OUTPUT SMILIES .TP .B :-) Normal operation, low/no jitter .TP .B :-| Normal operation, considerable jitter .TP .B :-/ Read drift .TP .B :-P Unreported loss of streaming in atomic read operation .TP .B 8-| Finding read problems at same point during reread; hard to correct .TP .B :-0 SCSI/ATAPI transport error .TP .B :-( Scratch detected .TP .B ;-( Gave up trying to perform a correction .TP .B 8-X Aborted read due to known, uncorrectable error .TP .B :^D Finished extracting .SH PROGRESS BAR SYMBOLS .TP .B No corrections needed .TP .B - Jitter correction required .TP .B + Unreported loss of streaming/other error in read .TP .B ! Errors found after stage 1 correction; the drive is making the same error through multiple re-reads, and @CDPARANOIA_NAME@ is having trouble detecting them. .TP .B e SCSI/ATAPI transport error (corrected) .TP .B V Uncorrected error/skip .SH SPAN ARGUMENT The span argument specifies which track, tracks or subsections of tracks to read. This argument is required. .B NOTE: Unless the span is a simple number, it's generally a good idea to quote the span argument to protect it from the shell. .P The span argument may be a simple track number or an offset/span specification. The syntax of an offset/span takes the rough form: .P 1[ww:xx:yy.zz]-2[aa:bb:cc.dd] .P Here, 1 and 2 are track numbers; the numbers in brackets provide a finer grained offset within a particular track. [aa:bb:cc.dd] is in hours/minutes/seconds/sectors format. Zero fields need not be specified: [::20], [:20], [20], [20.], etc, would be interpreted as twenty seconds, [10:] would be ten minutes, [.30] would be thirty sectors (75 sectors per second). .P When only a single offset is supplied, it is interpreted as a starting offset and ripping will continue to the end of the track. If a single offset is preceeded or followed by a hyphen, the implicit missing offset is taken to be the start or end of the disc, respectively. Thus: .TP .B 1:[20.35] Specifies ripping from track 1, second 20, sector 35 to the end of track 1. .TP .B 1:[20.35]- Specifies ripping from 1[20.35] to the end of the disc .TP .B \-2 Specifies ripping from the beginning of the disc up to (and including) track 2 .TP .B \-2:[30.35] Specifies ripping from the beginning of the disc up to 2:[30.35] .TP .B 2-4 Specifies ripping from the beginning of track 2 to the end of track 4. .P Again, don't forget to protect square brackets and preceeding hyphens from the shell. .SH EXAMPLES A few examples, protected from the shell: .TP Query only with exhaustive search for a drive and full reporting of autosense: .P @CDPARANOIA_NAME@ -vsQ .TP Extract an entire disc, putting each track in a separate file: .P @CDPARANOIA_NAME@ -B .TP Extract from track 1, time 0:30.12 to 1:10.00: .P @CDPARANOIA_NAME@ "1[:30.12]-1[1:10]" .TP Extract from the beginning of the disc up to track 3: .P @CDPARANOIA_NAME@ -- "-3" .TP The "--" above is to distinguish "-3" from an option flag. .SH OUTPUT The output file argument is optional; if it is not specified, @CDPARANOIA_NAME@ will output samples to one of .BR cdda.wav ", " cdda.aifc ", or " cdda.raw depending on whether .BR \-w ", " \-a ", " \-r " or " \-R " is used (" \-w is the implicit default). The output file argument of .B \- specifies standard output; all data formats may be piped. .SH ACKNOWLEDGEMENTS @CDPARANOIA_NAME@ sprang from and once drew heavily from the interface of Heiko Eissfeldt's (heiko@colossus.escape.de) 'cdda2wav' package. @CDPARANOIA_NAME@ would not have happened without it. .P Joerg Schilling has also contributed SCSI expertise through his generic SCSI transport library. .P .SH AUTHOR Monty .P Cdparanoia's homepage may be found at: https://www.xiph.org/paranoia/ .P Revised for use with libcdio by Rocky .P The libcdio homepage may be found at: https://www.gnu.org/software/libcdio/ libcdio-paranoia-release-10.2-2.0.2/doc/ja/000077500000000000000000000000001461637345700200635ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/doc/ja/.gitignore000066400000000000000000000000461461637345700220530ustar00rootroot00000000000000/Makefile /Makefile.in /cd-paranoia.1 libcdio-paranoia-release-10.2-2.0.2/doc/ja/Makefile.am000066400000000000000000000046301461637345700221220ustar00rootroot00000000000000# $Id: Makefile.am,v 1.2 2008/04/17 17:39:48 karl Exp $ # # Copyright (C) 2005, 2008 Rocky Bernstein # # 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 3 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, see . mansubdir=/ja/man1 manfiles = cd-paranoia.1 man_MANS = $(manfiles) cd-paranoia.1 transform = s,cd-paranoia,@CDPARANOIA_NAME@, EXTRA_DIST = $(manfiles) cd-paranoia.1.in install-man1: $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(mandir)$(mansubdir)" @list='$(man1_MANS)'; \ l2='$(man_MANS)'; for i in $$l2; do \ case "$$i" in \ *.1*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 1*) ;; \ *) ext='1' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(mandir)$(mansubdir)/$$inst"; \ $(INSTALL_DATA) $$file $(DESTDIR)$(mandir)$(mansubdir)/$$inst; \ done uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; \ l2='$(man_MANS)'; for i in $$l2; do \ case "$$i" in \ *.1*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f $(DESTDIR)$(mandir)$(mansubdir)/$$inst"; \ rm -f $(DESTDIR)$(mandir)$(mansubdir)/$$inst; \ done mostlyclean-generic: -rm -f *~ \#* .*~ .\#* maintainer-clean-generic: -@echo "This command is intended for maintainers to use;" -@echo "it deletes files that may require special tools to rebuild." -rm -f Makefile.in $(manfiles) libcdio-paranoia-release-10.2-2.0.2/doc/ja/cd-paranoia.1.in000066400000000000000000000230251461637345700227320ustar00rootroot00000000000000.TH @CDPARANOIA_NAME@ 1 .\" Translated Sun Aug 22 18:02:41 JST 1999 .\" by FUJIWARA Teruyoshi .SH ̾Á° @CDPARANOIA_NAME@ (Paranoia release III libcdio) \- ¥ª¡¼¥Ç¥£¥ª CD ÆÉ¤ß¼è¤ê¥æ¡¼¥Æ¥£¥ê¥Æ¥£¡£ÆÃÊ̤ʥǡ¼¥¿¾È¹çµ¡Ç½¤ò»ý¤Ä¡£ .SH ÆüÉÕ ¥Ð¡¼¥¸¥ç¥óIII ¥ê¥ê¡¼¥¹¦Á9.6 (17 Aug 1999) .SH ½ñ¼° .B @CDPARANOIA_NAME@ .RB [ options ] .B span .RB [ outfile ] .SH ÀâÌÀ .B @CDPARANOIA_NAME@ ¤Ï CD-DA µ¡Ç½¤ò»ý¤Ä CD-ROM ¥É¥é¥¤¥Ö¤«¤é¥ª¡¼¥Ç¥£¥ª¥È¥é¥Ã¥¯¤ò¼è¤ê½Ð¤·¤Þ ¤¹¡£¤³¤Î¥Ç¡¼¥¿¤Ï WAV, AIFF, AIFF-C, raw ·Á¼°¤Ç¥Õ¥¡¥¤¥ë¤Ë¥»¡¼¥Ö¤¹¤ë¤³¤È ¤ä¡¢É¸½à½ÐÎϤËÁ÷¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£¤Û¤È¤ó¤É¤Î ATAPI, SCSI, ¥á¡¼¥«¡¼ÆÈ¼« ¤Î CD-ROM ¥É¥é¥¤¥Ö¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤¹¡£ .B @CDPARANOIA_NAME@ ¤ÏÂоݤΥɥ饤¥Ö¤¬ CD-DA µ¡Ç½¤ò»ý¤Ã¤Æ¤¤¤ë¤«¤É¤¦¤«¤òȽÊ̤Ǥ­¤Þ¤¹¡£ .P ñ½ã¤ÊÆÉ¤ß¼è¤ê¤À¤±¤Ç¤Ê¤¯¡¢ .B @CDPARANOIA_NAME@ ¤ÏÆÃÊ̤˴è·ò¤Ê¥Ç¡¼¥¿¾È¹çµ¡Ç½¡¢Æ±´üµ¡Ç½¡¢¥¨¥é¡¼½èÍýµ¡Ç½¡¢ÇË»¥Ç¡¼¥¿¤ÎºÆ ¹½À®µ¡Ç½¤ò»ý¤Ã¤Æ¤¤¤Þ¤¹¡£ .SH ¥ª¥×¥·¥ç¥ó .TP .B \-v --verbose ¼«Æ°¸¡½Ð¤ÈÆÉ¤ß¼è¤ê¤Î½èÍý¤Ë¤Ä¤¤¤Æ¡¢¤Ð¤«¤Ð¤«¤·¤¤¤Û¤É¾éŤÊɽ¼¨¤ò¹Ô¤¤¤Þ¤¹¡£ ÀßÄê¤ä¥Ç¥Ð¥Ã¥°¤ÎºÝ¤ËÊØÍø¤Ç¤¹¡£ .TP .B \-q --quiet ÆÉ¤ß¼è¤ê½èÍý¤ÎÅÓÃæ¤Ë¡¢¿Ê¹Ô¾õ¶·¤ä¥¨¥é¡¼¾ðÊó¤òÁ´¤¯É½¼¨¤·¤Þ¤»¤ó¡£ .TP .B \-e --stderr-progress ¿Ê¹Ô¾õ¶·¤ò(¥é¥Ã¥Ñ¥¹¥¯¥ê¥×¥È¤Î¤¿¤á¤Ë)ɸ½à¥¨¥é¡¼½ÐÎϤ˽ÐÎϤ·¤Þ¤¹¡£ .TP .B \-V --version ¥×¥í¥°¥é¥à¤Î¥Ð¡¼¥¸¥ç¥ó¤òɽ¼¨¤·¤Æ½ªÎ»¤·¤Þ¤¹¡£ .TP .B \-Q --query CD-ROM ¥É¥é¥¤¥Ö¤Î¼«Æ°¸¡½Ð¤ò¹Ô¤¤¡¢CD-ROM ¤Î TOC ¤ÎÌ䤤¹ç¤ï¤»¤Èɽ¼¨¤ò¹Ô ¤¤¡¢½ªÎ»¤·¤Þ¤¹¡£ .TP .B \-s --search-for-drive ¤¿¤È¤¨ /dev/cdrom ¤Î¥ê¥ó¥¯¤¬Â¸ºß¤·¤Æ¤¤¤Æ¤â¡¢CD-ROM ¥É¥é¥¤¥Ö¤Î´°Á´¤Ê ¸¡º÷¤ò¹Ô¤¤¤Þ¤¹¡£ .TP .B \-h --help .B @CDPARANOIA_NAME@ ¤Î»È¤¤Êý¤È¥ª¥×¥·¥ç¥ó¤ò´Êñ¤ÊÀâÌÀ¤ò½ÐÎϤ·¤Þ¤¹¡£ .TP .B \-p --output-raw ¥Ø¥Ã¥À̵¤·¤Î¥Ç¡¼¥¿¤ò¥Û¥¹¥È¤Î¥Ð¥¤¥È½ç¤Ç¡¢¥¤¥ó¥¿¥ê¡¼¥Ö½èÍý¤ò»Ü¤·¤¿ ¥µ¥ó¥×¥ë²»À¼¤ò´Þ¤à raw ·Á¼°¤Î 16 ¥Ó¥Ã¥È PCM ¥Ç¡¼¥¿¤È¤·¤Æ½ÐÎϤ·¤Þ¤¹¡£ ¥Ð¥¤¥È½ç¤È¤·¤Æ¥ê¥È¥ë¥¨¥ó¥Ç¥£¥¢¥ó¤¢¤ë¤¤¤Ï¥Ó¥Ã¥°¥¨¥ó¥Ç¥£¥¢¥ó¤ò»ØÄꤹ¤ë¤Ë ¤Ï¡¢¸å½Ò¤Î .B \-r ¤Þ¤¿¤Ï .B \-R ¥ª¥×¥·¥ç¥ó¤ò»È¤Ã¤Æ¤¯¤À¤µ¤¤¡£ .TP .B \-r --output-raw-little-endian ¥Ø¥Ã¥À̵¤·¤Î¥Ç¡¼¥¿¤ò LSB first ¤Î¥Ð¥¤¥È½ç¤Ç¡¢¥¤¥ó¥¿¥ê¡¼¥Ö½èÍý¤ò»Ü¤·¤¿ ¥µ¥ó¥×¥ë²»À¼¤ò´Þ¤à raw ·Á¼°¤Î 16 ¥Ó¥Ã¥È PCM ¥Ç¡¼¥¿¤È¤·¤Æ½ÐÎϤ·¤Þ¤¹¡£ .TP .B \-R --output-raw-big-endian ¥Ø¥Ã¥À̵¤·¤Î¥Ç¡¼¥¿¤ò MSB first ¤Î¥Ð¥¤¥È½ç¤Ç¡¢¥¤¥ó¥¿¥ê¡¼¥Ö½èÍý¤ò»Ü¤·¤¿ ¥µ¥ó¥×¥ë²»À¼¤ò´Þ¤à raw ·Á¼°¤Î 16 ¥Ó¥Ã¥È PCM ¥Ç¡¼¥¿¤È¤·¤Æ½ÐÎϤ·¤Þ¤¹¡£ .TP .B \-w --output-wav ¥Ç¡¼¥¿¤ò Micro$oft ¤Î RIFF WAV ·Á¼°¤Ç½ÐÎϤ·¤Þ¤¹(WAV ¥Ç¡¼¥¿¤Î¥Ð¥¤¥È½ç¤Ï ɬ¤º LSB first ¤Ç¤¢¤ëÅÀ¤ËÃí°Õ)¡£ .TP .B \-f --output-aiff ¥Ç¡¼¥¿¤ò Apple ¤Î AIFF ·Á¼°¤Ç½ÐÎϤ·¤Þ¤¹(AIFC ¥Ç¡¼¥¿¤Î¥Ð¥¤¥È½ç¤Ïɬ¤º MSB first ¤Ç¤¢¤ëÅÀ¤ËÃí°Õ)¡£ .TP .B \-a --output-aifc ¥Ç¡¼¥¿¤ò̵°µ½Ì ¤Î Apple AIFF-C ·Á¼°¤Ç½ÐÎϤ·¤Þ¤¹(AIFF-C ¥Ç¡¼¥¿¤Î¥Ð¥¤¥È ½ç¤Ïɬ¤º MSB first ¤Ç¤¢¤ëÅÀ¤ËÃí°Õ)¡£ .TP .BI "\-B --batch " cdda2wav ·Á¼°¤Î¥Ð¥Ã¥Á½ÐÎϤò¹Ô¤¤¤Þ¤¹¡£@CDPARANOIA_NAME@ ¤Ï½ÐÎϤò¥È¥é¥Ã¥¯¶­³¦¤Ç Ê£¿ô¥Õ¥¡¥¤¥ë¤Ëʬ³ä¤·¤Þ¤¹¡£½ÐÎÏ¥Õ¥¡¥¤¥ë¤Î¥Õ¥¡¥¤¥ë̾¤ÎÀèÆ¬Éôʬ¤Ï¡¢'track(ÈÖ¹æ)' ¤È¤Ê¤ê¤Þ¤¹¡£ .TP .B \-c --force-cdrom-little-endian °ìÉô¤Î CD-ROM ¤Ï´Ö°ã¤Ã¤¿¥¨¥ó¥Ç¥£¥¢¥ó¤òÊó¹ð¤·¤Þ¤¹(¤¢¤ë¤¤¤Ï¥¨¥ó¥Ç¥£¥¢¥ó ¤Ë´Ø¤¹¤ë¾ðÊó¤òÁ´¤¯Êó¹ð¤·¤Þ¤»¤ó)¡£¤½¤Î¤¿¤á¡¢@CDPARANOIA_NAME@ ¤¬¥¨¥ó¥Ç¥£¥¢¥ó¤ò ´Ö°ã¤¨¤ë¤³¤È¤¬¤¢¤ê¤Þ¤¹¡£¥É¥é¥¤¥Ö¤ò¥ê¥È¥ë¥¨¥ó¥Ç¥£¥¢¥ó¤Î¥Ç¥Ð¥¤¥¹¤È¤·¤Æ @CDPARANOIA_NAME@ ¤Ë°·¤ï¤»¤ë¤Ë¤Ï¡¢ .B \-c ¥ª¥×¥·¥ç¥ó¤ò»È¤¤¤Þ¤¹¡£ .TP .B \-C --force-cdrom-big-endian Á°¤Î¥ª¥×¥·¥ç¥ó¤ÎµÕ¤Ç¡¢¥Ç¥Ð¥¤¥¹¤ò¥Ó¥Ã¥°¥¨¥ó¥Ç¥£¥¢¥ó¤Î¥Ç¥Ð¥¤¥¹¤È¤·¤Æ @CDPARANOIA_NAME@ ¤Ë°·¤ï¤»¤Þ¤¹¡£ .TP .BI "\-n --force-default-sectors " n ¥¤¥ó¥¿¥Õ¥§¡¼¥¹¤Î¥Ð¥Ã¥¯¥¨¥ó¥É¤¬¹Ô¤¦ºÇ¾®Ã±°Ì¤ÎÆÉ¤ß¼è¤ê¤ò¡¢ 1 ²ó¤ÎÆÉ¤ß¼è¤ê¤´¤È¤Ë .B n ¥»¥¯¥¿¤È¤·¤Þ¤¹¡£¤³¤Î¿ô¤ÏÌäÂê¤òµ¯¤³¤¹¤ª¤½¤ì¤¬¤¢¤ê¤Þ¤¹¡£¥«¡¼¥Í¥ë¤Ï¿¤¯¤Î ¾ì¹ç¡¢ÆÉ¤ß¼è¤êÍ×µá¤òºÇ¾®Ã±°Ì¤ÎÆÉ¤ß¼è¤ê(@CDPARANOIA_NAME@ ¤Ë¤è¤ë¼«Æ°½èÍý¤Ï¤³¤ì ¤ËÂбþ¤·¤Æ¤¤¤Þ¤¹)Ê£¿ô¸Ä¤Ëʬ³ä¤¹¤ë¤«¡¢À©¸Â¤µ¤ì¤¿Â礭¤µ¤ÎÈϰϤǤ·¤« ÆÉ¤ß¼è¤ê¤òµö²Ä¤·¤Þ¤»¤ó¡£ .B ÉáÄ̤Ϥ³¤Î¥ª¥×¥·¥ç¥ó¤ò»È¤¦¤Ù¤­¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó¡£ .TP .BI "\-d --force-cdrom-device " device ¥¤¥ó¥¿¥Õ¥§¡¼¥¹¤Î¥Ð¥Ã¥¯¥¨¥ó¥É¤Ë¤è¤ëÆÉ¤ß¼è¤ê¤ò¡¢ºÇ½é¤Ë¸«¤Ä¤±¤¿ÆÉ¤ß¼è¤ê²Ä ǽ¤Ê CD-ROM ¥É¥é¥¤¥Ö¤Ç¤Ï¤Ê¤¯¡¢»ØÄꤷ¤¿ .B device ¤«¤é¹Ô¤¦¤è¤¦¤Ë¤·¤Þ¤¹¡£¤³¤Î¥ª¥×¥·¥ç¥ó¤Ç¤Ï¡¢ÍøÍѲÄǽ¤Ç¤¢¤ëǤ°Õ¤Î ¥¤¥ó¥¿¥Õ¥§¡¼¥¹(ATAPI, SCSI, ¥á¡¼¥«¡¼ÆÈ¼«)¤ò»ý¤Ä¥Ç¥Ð¥¤¥¹¤ò»ØÄꤹ¤ë¤³¤È ¤¬¤Ç¤­¤Þ¤¹¡£ .TP .BI "\-g --force-generic-device " device ¤³¤Î¥ª¥×¥·¥ç¥ó¤Ï¡¢SCSI CD-ROM ¤ÈÈÆÍѥǥХ¤¥¹¤ÎÀßÄê¤òÌÀ¼¨Åª¤ËÊÌ¡¹¤ËÀ©¸æ ¤·¤¿¤¤»þ¤Ë .B \-d ¥ª¥×¥·¥ç¥ó¤ÈÁȤ߹ç¤ï¤»¤Æ»È¤¤¤Þ¤¹¡£¤³¤Î¥ª¥×¥·¥ç¥ó¤¬ÌòΩ¤Ä¤Î¤Ï¡¢SCSI ¤Î ÀßÄ꤬ɸ½à¤È°Û¤Ê¤ë¾ì¹ç¤À¤±¤Ç¤¹¡£ .TP .BI "\-S --force-read-speed " number CD ¥É¥é¥¤¥Ö¤«¤é¤ÎÆÉ¤ß¹þ¤ß®ÅÙ¤òÀßÄꤹ¤ë¤Ë¤Ï¡¢¤³¤Î¥ª¥×¥·¥ç¥ó¤òÌÀ¼¨Åª¤Ë »È¤Ã¤Æ¤¯¤À¤µ¤¤(¥É¥é¥¤¥Ö¤¬Âбþ¤·¤Æ¤¤¤ë¾ì¹ç)¡£¤³¤Î¥ª¥×¥·¥ç¥ó¤òÍѤ¤¤ë¤È¡¢ ¥Ç¥£¥¹¥¯¤¬ÃÙ¤¤¾ì¹ç¤ä¥á¥â¥ê¤¬¾¯¤Ê¤¤¾ì¹ç¤Ëµ¯¤³¤ë¥¢¥ó¥À¡¼¥é¥ó¤ò¸º¤é¤¹¤³¤È ¤¬¤Ç¤­¤Þ¤¹¡£ .TP .B \-Z --disable-paranoia ¥Ç¡¼¥¿¾È¹ç¤ÈÄûÀµµ¡Ç½¤ò .b Á´¤Æ ̵¸ú¤Ë¤·¤Þ¤¹¡£-Z ¥ª¥×¥·¥ç¥ó¤òÍѤ¤¤ë¤È¡¢@CDPARANOIA_NAME@ ¤Ï ¥ª¡¼¥Ð¡¼¥é¥Ã¥×¤ÎÀßÄ꤬ 0 ¤Ç¤¢¤ë cdda2wav ¤ÈÁ´¤¯Æ±¤¸¤è¤¦¤Ë¥Ç¡¼¥¿¤Î ÆÉ¤ß¼è¤ê¤ò¹Ô¤¤¤Þ¤¹¡£ ¤³¤Î¥ª¥×¥·¥ç¥ó¤ò»ØÄꤹ¤ë¤È .B \-W , .B \-X , .B \-Y ¥ª¥×¥·¥ç¥ó¤âÍ­¸ú¤Ë¤Ê¤ê¤Þ¤¹¤¬¡¢ .B \-Z \-W \-X \-Y ¤ÈÁ´¤¯Æ±¤¸¤Ç¤Ï .B ¤¢¤ê¤Þ¤»¤ó¡£ ¤Ê¤¼¤Ê¤é¡¢ .B \-W ¤«¤é .B \-Z ¤Þ¤Ç¤Î¥ª¥×¥·¥ç¥ó¤Ë¤è¤ê¾È¹ç¤Î¥ì¥Ù¥ë¤¬³¬ÁØÅª¤ËÊѤï¤ë¤«¤é¤Ç¤¹¡£¼ÂºÝ¤ËÍ­¸ú ¤Ë¤Ê¤ë¤Î¤ÏºÇ¸å¤Ë»ØÄꤷ¤¿¥ª¥×¥·¥ç¥ó¤À¤±¤Ç¤¹¡£ .TP .B \-Y --disable-extra-paranoia ÆÉ¤ß¼è¤Ã¤¿¥Ç¡¼¥¿¤ÎÃæ´Ö¤Ë¤ª¤±¤ë¥Ç¡¼¥¿¾È¹ç¤ò¹Ô¤¤¤Þ¤»¤ó¡£¤Ä¤Þ¤ê¡¢ ¥Ç¡¼¥¿¤ÎÆÉ¤ß¼è¤ê¶­³¦¤Ë¤ª¤±¤ë¥ª¡¼¥Ð¡¼¥é¥Ã¥×Éôʬ¤Î¥Á¥§¥Ã¥¯¤·¤«¹Ô¤¤¤Þ¤»¤ó¡£ .TP .B \-X --disable-scratch-detection ¾È¹ç¤ÎÅÓÃæ¤Ç¤Ï½ý¤Îõºº¤â¹Ô¤ï¤º¡¢½ý¤ËÂФ·¤Æ´è·ò¤ÊƱ´ü½èÍý¤â¹Ô¤¤¤Þ¤»¤ó¡£ .B \-X ¥ª¥×¥·¥ç¥ó¤ò»ØÄꤷ¤¿¾ì¹ç¡¢½ý¤Ä¤¤¤¿ CD ¤òÍ¿¤¨¤ë¤È @CDPARANOIA_NAME@ ¤ÏÆÉ¤ß¼è¤ê ¤Î¼ºÇÔ¤òµ¯¤³¤·¤Þ¤¹¡£ .TP .B \-W --disable-scratch-repair ½ý¤ò¸¡½Ð¤·¡¢Æ±´ü¤òÊݤĽèÍý¤ò¹Ô¤¤¤Þ¤¹¡£¤¿¤À¤·²õ¤ì¤¿¥Ç¡¼¥¿¤Î½¤Éü¤Ï¹Ô¤¤¤Þ ¤»¤ó¡£¥í¥°¥Õ¥¡¥¤¥ë¤Î½ÐÎϤò¹Ô¤¦¤È( .RB \-i ¥ª¥×¥·¥ç¥ó)¡¢Á´¤Æ¤Î½ý¤Î¥Õ¥ì¡¼¥à°ÌÃÖ¤¬¥í¥°¥Õ¥¡¥¤¥ë¤Ë½ÐÎϤµ¤ì¤Þ¤¹¡£ .SH ½ÐÎϤµ¤ì¤ë´éʸ»ú .TP .B :-) Àµ¾ïưºî¡£¥¸¥Ã¥¿¤Ï¾¯¤Ê¤¤¤«¡¢Á´¤¯¤Ê¤¤ .TP .B :-| Àµ¾ïưºî¡£¥¸¥Ã¥¿¤ÏµöÍÆÈÏ°Ï .TP .B :-/ ÆÉ¤ß¼è¤ê¤Ç¥É¥ê¥Õ¥È¤¬È¯À¸ .TP .B :-P ºÇ¾®Ã±°Ì¤ÎÆÉ¤ß¼è¤êÁàºî¤Ë¤ª¤¤¤Æ¡¢Êó¹ð¤µ¤ì¤Æ¤¤¤Ê¤¤Â»¼º¤¬¥¹¥È¥ê¡¼¥ß¥ó¥°¤Ë¤¢¤ë .TP .B 8-| ·«¤êÊÖ¤·¤ÆÆÉ¤ß¼è¤ê¤ò¹Ô¤Ã¤¿¤¬¡¢Æ±¤¸°ÌÃÖ¤ÇÌäÂ꤬µ¯¤­¤¿¡£½¤Àµ¤Ïº¤Æñ¤Ç¤¢¤ë .TP .B :-0 SCSI/ATAPI ¤Î¥Ç¡¼¥¿Å¾Á÷¥¨¥é¡¼ .TP .B :-( ½ý¤¬¸¡½Ð¤µ¤ì¤¿ .TP .B ;-( ¥Ç¡¼¥¿¤ÎÄûÀµ¤ò¤¢¤­¤é¤á¤¿ .TP .B :^D ÆÉ¤ß¼è¤ê½ªÎ» .SH ¿Ê¹Ôɽ¼¨¤Î°ÕÌ£ .TP .B <¥¹¥Ú¡¼¥¹> ÄûÀµ¤ÏÉÔÍ× .TP .B - ¥¸¥Ã¥¿¤ÎÄûÀµ¤¬É¬Í× .TP .B + Êó¹ð¤µ¤ì¤Æ¤¤¤Ê¤¤Â»¼º¤¬¥¹¥È¥ê¡¼¥ß¥ó¥°¤Ë¤¢¤ë¡£¤¢¤ë¤¤¤ÏÊ̤Υ¨¥é¡¼¤¬ÆÉ¤ß¼è¤ê »þ¤ËȯÀ¸¤·¤¿ .TP .B ! ¥¹¥Æ¡¼¥¸ 1 ÄûÀµ¤Î¸å¤Ë¥¨¥é¡¼¤¬¸«¤Ä¤«¤Ã¤¿¡£ÆÉ¤ß¼è¤ê¤òÊ£¿ô²ó·«¤êÊÖ¤·¤Æ¤â Ʊ¤¸¥¨¥é¡¼¤¬È¯À¸¤·¡¢@CDPARANOIA_NAME@ ¤Ï¤½¤Î¥¨¥é¡¼¤ò¤¦¤Þ¤¯¸¡½Ð¤Ç¤­¤Ê¤¤¡£ .TP .B e SCSI/ATAPI ¤Î¥Ç¡¼¥¿Å¾Á÷¥¨¥é¡¼(ÄûÀµºÑ¤ß) .TP .B V ÄûÀµ¤Ç¤­¤Ê¤¤¥¨¥é¡¼/¥Ç¡¼¥¿¤Î¥¹¥­¥Ã¥× .SH °ú¤­¿ô 'span' °ú¤­¿ô span ¤Ï¡¢ÆÉ¤ß¼è¤ê¤ò¹Ô¤¦¥È¥é¥Ã¥¯¤Þ¤¿¤Ï¥È¥é¥Ã¥¯¤Î°ìÉô¤ò»ØÄꤷ¤Þ¤¹¡£ ¤³¤Î°ú¤­¿ô¤Ïɬ¤ºÉ¬ÍפǤ¹¡£ .B Ãí°Õ: span ¤¬Ã±¤Ê¤ë¿ô»ú¤Ç¤Ê¤±¤ì¤Ð¡¢¥·¥§¥ë¤¬°ú¤­¿ô span ¤òŸ³«¤·¤Æ¤·¤Þ¤ï¤Ê¤¤ ¤è¤¦¤Ë¥¯¥©¡¼¥È¤¹¤ë¤Î¤¬ÉáÄ̤Ǥ·¤ç¤¦¡£ .P °ú¤­¿ô span ¤Ï¡¢Ã±¤Ê¤ë¥È¥é¥Ã¥¯Èֹ椫¡¢¥ª¥Õ¥»¥Ã¥È¤È¥¹¥Ñ¥ó¤ÎÁȹ礻¤Î»ØÄê ¤È¤Ê¤ê¤Þ¤¹¡£¥ª¥Õ¥»¥Ã¥È¤È¥¹¥Ñ¥ó¤ÎÁȹ礻¤ò»ØÄꤹ¤ëÊýË¡¤Ï¡¢¤À¤¤¤¿¤¤°Ê²¼¤Î ¤è¤¦¤Ë¤Ê¤ê¤Þ¤¹: .P 1[ww:xx:yy.zz]-2[aa:bb:cc.dd] .P ¤³¤³¤Ç 1 ¤È 2 ¤Ï¥È¥é¥Ã¥¯ÈÖ¹æ¤Ç¤¹¡£³Ñ³ç¸Ì¤ÎÃæ¤Î¿ôÃͤϡ¢»ØÄꤵ¤ì¤¿¥È¥é¥Ã¥¯ ¤Ë¤ª¤±¤ë¡¢¤è¤êºÙ¤«¤¤¥ª¥Õ¥»¥Ã¥È»ØÄê¤Ç¤¹¡£[aa:bb:cc.dd] ¤Ï ¡Ö»þ´Ö/ʬ/ÉÃ/¥»¥¯¥¿¡×¤Î·Á¼°¤Ç¤¹¡£Ãͤ¬ 0 ¤Ç¤¢¤ë¥Õ¥£¡¼¥ë¥É¤Ï»ØÄꤷ¤Ê¤¯¤Æ ¤â¹½¤¤¤Þ¤»¤ó¡£¤Ä¤Þ¤ê [::20], [:20], [20], [20.] Åù¤Ï 20 ÉäȲò¼á¤µ¤ì¡¢ [10:] ¤Ï 10 ÉäȲò¼á¤µ¤ì¡¢[.30] ¤Ï 30 ¥»¥¯¥¿¤È²ò¼á¤µ¤ì¤Þ¤¹(75 ¥»¥¯¥¿¤Ç 1 ÉäǤ¹)¡£ .P ¥ª¥Õ¥»¥Ã¥È¤ò 1 ¤Ä¤·¤«»ØÄꤷ¤Ê¤±¤ì¤Ð¡¢¤³¤ì¤Ï³«»Ï°ÌÃ֤Υª¥Õ¥»¥Ã¥È¤òɽ¤·¡¢ µÛ¤¤½Ð¤·¤Ï¤½¤Î¥È¥é¥Ã¥¯¤Î½ª¤ï¤ê¤Þ¤Ç¹Ô¤ï¤ì¤Þ¤¹¡£¥ª¥Õ¥»¥Ã¥È¤¬ 1 ¤Ä¤À¤±¤¢ ¤ê¡¢¤½¤ÎÁ°¸å¤Ë¥Ï¥¤¥Õ¥ó(-)¤¬¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢¾Êά¤µ¤ì¤Æ¤¤¤ë¥ª¥Õ¥»¥Ã¥È¤Ï ¥Ç¥£¥¹¥¯¤ÎÀèÆ¬¤¢¤ë¤¤¤ÏËöÈø¤È¤·¤Æ²ò¼á¤µ¤ì¤Þ¤¹¡£Îã¤ò°Ê²¼¤Ë¼¨¤·¤Þ¤¹: .TP .B 1:[20.35] ¥È¥é¥Ã¥¯ 1 ¤Î 20 Éá¢35 ¥»¥¯¥¿¤Î°ÌÃÖ¤«¤é¡¢¥È¥é¥Ã¥¯ 1 ¤ÎËöÈø¤Þ¤Ç¤òµÛ¤¤ ½Ð¤·¤Þ¤¹¡£ .TP .B 1:[20.35]- 1[20.35] ¤Î°ÌÃÖ¤«¤é¥Ç¥£¥¹¥¯¤ÎËöÈø¤Þ¤Ç¤òµÛ¤¤½Ð¤·¤Þ¤¹¡£ .TP .B \-2 ¥Ç¥£¥¹¥¯¤ÎÀèÆ¬¤«¤é¥È¥é¥Ã¥¯ 2 ¤Þ¤Ç(¥È¥é¥Ã¥¯ 2 ¤â´Þ¤ß¤Þ¤¹)¤òµÛ¤¤½Ð¤·¤Þ¤¹¡£ .TP .B \-2:[30.35] ¥Ç¥£¥¹¥¯¤ÎÀèÆ¬¤«¤é 2:[30.35] ¤Î°ÌÃ֤ޤǵۤ¤½Ð¤·¤Þ¤¹¡£ .TP .B 2-4 ¥È¥é¥Ã¥¯ 2 ¤ÎÀèÆ¬¤«¤é¥È¥é¥Ã¥¯ 4 ¤ÎËöÈø¤Þ¤Ç¤òµÛ¤¤½Ð¤·¤Þ¤¹¡£ .P ·«¤êÊÖ¤·¤Ë¤Ê¤ê¤Þ¤¹¤¬¡¢³Ñ³ç¸Ì¤ª¤è¤Óñ¸ì¤ÎÀèÆ¬¤Ë¤¢¤ë¥Ï¥¤¥Õ¥ó¤Ïɬ¤º¥¯¥©¡¼¥È ¤·¤Æ¡¢¥·¥§¥ë¤ËŸ³«¤µ¤ì¤Ê¤¤¤è¤¦¤Ë¤·¤Æ¤¯¤À¤µ¤¤¡£ .SH »ØÄêÎã ¥¯¥©¡¼¥È¤â´Þ¤á¤¿»ØÄêÎã¤ò¤¤¤¯¤Ä¤«¼¨¤·¤Þ¤¹: .TP ¥É¥é¥¤¥Ö¤ÎÄ´ºº¤À¤±¤òŰÄìŪ¤Ë¹Ô¤¤¡¢¼«Æ°¸¡½Ð¤Î·ë²Ì¤òÁ´¤ÆÊó¹ð¤·¤Þ¤¹: .P @CDPARANOIA_NAME@ -vsQ .TP ¥Ç¥£¥¹¥¯Á´ÂΤòµÛ¤¤½Ð¤·¤Þ¤¹¡£¤½¤ì¤¾¤ì¤Î¥È¥é¥Ã¥¯¤ÏÊÌ¡¹¤Î¥Õ¥¡¥¤¥ë¤Ë¤·¤Þ¤¹: .P @CDPARANOIA_NAME@ -B "1-" .TP ¥È¥é¥Ã¥¯ 1 ¤Î»þ¹ï 0:30.12 ¤«¤é»þ¹ï 1:10.00 ¤Þ¤Ç¤òµÛ¤¤½Ð¤·¤Þ¤¹: .P @CDPARANOIA_NAME@ "1[:30.12]-1[1:10]" .TP ¥È¥é¥Ã¥¯ 1 ¤Î»þ¹ï 0:30.12 ¤«¤é 1 ʬ´Ö¤Î¥Ç¡¼¥¿¤òµÛ¤¤½Ð¤·¤Þ¤¹: .P @CDPARANOIA_NAME@ "1[:30.12]-[1:00]" .SH ½ÐÎÏ ½ÐÎÏ¥Õ¥¡¥¤¥ë¤ò»ØÄꤹ¤ë°ú¤­¿ô¤Ï¾Êά²Äǽ¤Ç¤¹¡£»ØÄꤵ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢ @CDPARANOIA_NAME@ ¤Ï¥µ¥ó¥×¥ë²»À¼¤ò .BR cdda.wav ", " cdda.aifc ", " cdda.raw ¤Î¤¤¤º¤ì¤«¤Ë½ÐÎϤ·¤Þ¤¹¡£¤É¤Î¥Õ¥¡¥¤¥ë¤Ë½ÐÎϤµ¤ì¤ë¤Î¤«¤Ï¡¢¥ª¥×¥·¥ç¥ó .BR \-w ", " \-a ", " \-r "," \-R ¤Î¤¦¤Á¤¤¤º¤ì¤ò»È¤¦¤«¤Ë¤è¤Ã¤Æ·è¤Þ¤ê¤Þ¤¹(²¿¤â»ØÄꤷ¤Ê¤±¤ì¤Ð .BR \-w ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¹)¡£½ÐÎÏ¥Õ¥¡¥¤¥ë¤ò»ØÄꤹ¤ë°ú¤­¿ô¤¬ .B \- ¤Ê¤é¤Ð¡¢½ÐÎϤÏɸ½à½ÐÎϤËÂФ·¤Æ¹Ô¤ï¤ì¤Þ¤¹¡£¤É¤Î¥Ç¡¼¥¿·Á¼°¤Ç¤â¥Ñ¥¤¥×¤ËÁ÷ ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ .SH ¼Õ¼­ @CDPARANOIA_NAME@ ¤Î´ð¤È¤Ê¤Ã¤¿¤Î¤Ï Heiko Eissfeldt ¤µ¤ó (heiko@colossus.escape.de)¤¬ºîÀ®¤·¤¿ 'cdda2wav' ¥Ñ¥Ã¥±¡¼¥¸¤Ç¤¢¤ê¡¢ °ÊÁ°¤Ï @CDPARANOIA_NAME@ ¤Î¥¤¥ó¥¿¥Õ¥§¡¼¥¹¤ÎÂçÉôʬ¤Ï cdda2wav ¤«¤é¤â¤é¤Ã¤Æ¤­¤¿ ¤â¤Î¤Ç¤·¤¿¡£cdda2wav ¤¬¤Ê¤±¤ì¤Ð¡¢@CDPARANOIA_NAME@ ¤¬ºî¤é¤ì¤ë¤³¤È¤Ï¤Ê¤«¤Ã¤¿¤Ç ¤·¤ç¤¦¡£ .P Joerg Schilling ¤µ¤ó¤¬ºîÀ®¤·¤¿ÈÆÍÑ SCSI ¥Ç¡¼¥¿Å¾Á÷¥é¥¤¥Ö¥é¥ê¤«¤é¡¢SCSI ¤ÎÀìÌçÃ챤ò¿¤¯³Ø¤Ð¤»¤Æ¤¤¤¿¤À¤­¤Þ¤·¤¿¡£ .P .SH ºî¼Ô Monty .P cdparanoia ¤Î¥Û¡¼¥à¥Ú¡¼¥¸¤Ï°Ê²¼¤Î¾ì½ê¤Ë¤¢¤ê¤Þ¤¹: .P .ce http://www.xiph.org/paranoia/ .P libcdio ¤Î¥Û¡¼¥à¥Ú¡¼¥¸¤Ï°Ê²¼¤Î¾ì½ê¤Ë¤¢¤ê¤Þ¤¹: .P .ce http://www.gnu.org/libcdio/ libcdio-paranoia-release-10.2-2.0.2/doc/overlapdef.txt000066400000000000000000000003731461637345700223640ustar00rootroot00000000000000 0 70 100 A |----------|-----| B |-----|---------| 0 40 100 offset=-30 begin=30 end=100 0 70 100 A |----------|-----| B |-----|---------| 50 90 150 offset=20 begin=30 end=100 libcdio-paranoia-release-10.2-2.0.2/example/000077500000000000000000000000001461637345700203575ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/example/.gitignore000066400000000000000000000001441461637345700223460ustar00rootroot00000000000000/*~ /.deps /.libs /Makefile /Makefile.in /paranoia /paranoia.o /paranoia2 /paranoia2.o /track1s.wav libcdio-paranoia-release-10.2-2.0.2/example/C++/000077500000000000000000000000001461637345700206675ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/example/C++/.gitignore000066400000000000000000000000421461637345700226530ustar00rootroot00000000000000/*~ /.deps /Makefile /Makefile.in libcdio-paranoia-release-10.2-2.0.2/example/C++/Makefile.am000066400000000000000000000026711461637345700227310ustar00rootroot00000000000000# Copyright (C) 2005, 2006, 2008, 2009 Rocky Bernstein # # 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 3 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, see . ########################################################## # Sample C++ programs using libcdio (without OO wrapper) ######################################################### # paranoia_progs = paranoia paranoia2 if BUILD_EXAMPLES noinst_PROGRAMS = $(paranoia_progs) endif AM_CPPFLAGS = -I$(top_srcdir) $(LIBCDIO_CFLAGS) paranoia_SOURCES = paranoia.cpp paranoia_LDADD = $(LIBCDIO_PARANOIA_LIBS) $(LIBCDIO_CDDA_LIBS) \ $(LIBCDIO_LIBS) paranoia2_SOURCES = paranoia.cpp paranoia2_LDADD = $(LIBCDIO_PARANOIA_LIBS) $(LIBCDIO_CDDA_LIBS) \ $(LIBCDIO_LIBS) check_PROGRAMS = $(noinst_PROGRAMS) TESTS = $(check_PROGRAMS) # iso programs create file "copying" MOSTLYCLEANFILES = copying *.wav libcdio-paranoia-release-10.2-2.0.2/example/C++/paranoia.cpp000066400000000000000000000115711461637345700231720ustar00rootroot00000000000000/* Copyright (C) 2005, 2008, 2009 Rocky Bernstein 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 3 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, see . */ /* Simple program to show using libcdio's version of the CD-DA paranoia. library. */ #ifdef HAVE_CONFIG_H #include "config.h" #define __CDIO_CONFIG_H__ 1 #endif #include #include #include #include using namespace std; extern "C"{ #ifdef HAVE_STDIO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #include #include } int main(int argc, const char *argv[]) { cdrom_drive_t *d = NULL; /* Place to store handle given by cd-paranoia. */ char **ppsz_cd_drives; /* List of all drives with a loaded CDDA in it. */ /* See if we can find a device with a loaded CD-DA in it. */ ppsz_cd_drives = cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false); if (ppsz_cd_drives) { /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in the list. */ d = cdda_identify(*ppsz_cd_drives, 1, NULL); } else { cerr << "Unable to access to a CD-ROM drive with audio CD in it"; return -1; } /* Don't need a list of CD's with CD-DA's any more. */ cdio_free_device_list(ppsz_cd_drives); if ( !d ) { cerr << "Unable to identify audio CD disc.\n"; return -1; } /* We'll set for verbose paranoia messages. */ cdda_verbose_set(d, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT); if ( 0 != cdda_open(d) ) { cerr << "Unable to open disc.\n"; return -1; } /* Okay now set up to read up to the first 300 frames of the first audio track of the Audio CD. */ { cdrom_paranoia_t *p = paranoia_init(d); lsn_t i_first_lsn = cdda_disc_firstsector(d); if ( -1 == i_first_lsn ) { printf("Trouble getting starting LSN\n"); } else { lsn_t i_cursor; track_t i_track = cdda_sector_gettrack(d, i_first_lsn); lsn_t i_last_lsn = cdda_track_lastsector(d, i_track); /* For demo purposes we'll read only 300 frames (about 4 seconds). We don't want this to take too long. On the other hand, I suppose it should be something close to a real test. */ if ( i_last_lsn - i_first_lsn > 300) i_last_lsn = i_first_lsn + 299; printf("Reading track %d from LSN %ld to LSN %ld\n", i_track, (long int) i_first_lsn, (long int) i_last_lsn); /* Set reading mode for full paranoia, but allow skipping sectors. */ paranoia_modeset(p, PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP); paranoia_seek(p, i_first_lsn, SEEK_SET); //Get the track size in bytes and conver it to string unsigned int byte_count = ( i_last_lsn - i_first_lsn + 1 ) * CDIO_CD_FRAMESIZE_RAW; // Open the output file ofstream outfile ("track01.wav", ofstream::binary | ofstream::app | ofstream::out); // Write format header specification const int waweChunkLength = byte_count + 44 - 8; const int fmtChunkLength = 16; const int compressionCode = 1; const int numberOfChannels = 2; const int sampleRate = 44100; // Hz const int blockAlign = sampleRate*2*2; const int significantBps = 4; const int extraFormatBytes = 16; #define writestr(str) outfile.write(str, sizeof(str)-1) writestr("RIFF"); outfile.write((char*)&waweChunkLength, 4); writestr("WAVEfmt "); outfile.write((char*) &fmtChunkLength, 4); outfile.write((char*) &compressionCode, 2); outfile.write((char*) &numberOfChannels, 2); outfile.write((char*) &sampleRate, 4); outfile.write((char*) &blockAlign, 4); outfile.write((char*) &significantBps, 2); outfile.write((char*) &extraFormatBytes, 2); writestr("data"); outfile.write((char*) &byte_count,4); for ( i_cursor = i_first_lsn; i_cursor <= i_last_lsn; i_cursor ++) { /* read a sector */ int16_t *p_readbuf=paranoia_read(p, NULL); char *psz_err=cdda_errors(d); char *psz_mes=cdda_messages(d); if (psz_mes || psz_err) cerr << psz_err << psz_mes; if (psz_err) free(psz_err); if (psz_mes) free(psz_mes); if( !p_readbuf ) { cerr << "paranoia read error. Stopping.\n"; break; } char *temp= (char*) p_readbuf; outfile.write(temp, CDIO_CD_FRAMESIZE_RAW); } } paranoia_free(p); } cdda_close(d); exit(0); } libcdio-paranoia-release-10.2-2.0.2/example/C++/paranoia2.cpp000066400000000000000000000057701461637345700232600ustar00rootroot00000000000000/* Copyright (C) 2005, 2008, 2009 Rocky Bernstein 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 3 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, see . */ /* Simple program to show using libcdio's version of the CD-DA paranoia library. But in this version, we'll open a cdio object before calling paranoia's open. I imagine in many cases such as media players this may be what will be done since, one may want to get CDDB/CD-Text info beforehand. */ #ifdef HAVE_CONFIG_H #include "config.h" #define __CDIO_CONFIG_H__ 1 #endif #ifdef HAVE_STDIO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #include #include int main(int argc, const char *argv[]) { cdrom_drive_t *d = NULL; /* Place to store handle given by cd-paranoia. */ char **ppsz_cd_drives; /* List of all drives with a loaded CDDA in it. */ CdIo_t *p_cdio = NULL; /* See if we can find a device with a loaded CD-DA in it. */ ppsz_cd_drives = cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false); if (ppsz_cd_drives) { /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in the list. */ p_cdio = cdio_open(*ppsz_cd_drives, DRIVER_UNKNOWN); d=cdio_cddap_identify_cdio(p_cdio, CDDA_MESSAGE_PRINTIT, NULL); } else { printf("Unable find or access a CD-ROM drive with an audio CD in it.\n"); exit(1); } /* Don't need a list of CD's with CD-DA's any more. */ cdio_free_device_list(ppsz_cd_drives); if ( !d ) { printf("Unable to identify audio CD disc.\n"); exit(1); } /* We'll set for verbose paranoia messages. */ cdio_cddap_verbose_set(d, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT); if ( 0 != cdio_cddap_open(d) ) { printf("Unable to open disc.\n"); exit(1); } /* In the paranoia example was a reading. Here we are going to do something trivial (but I think neat any way - get the Endian-ness of the drive. */ { const int i_endian = data_bigendianp(d); switch (i_endian) { case 0: printf("Drive returns audio data Little Endian." " Your drive is like most.\n"); break; case 1: printf("Drive returns audio data Big Endian.\n"); break; case -1: printf("Don't know whether drive is Big or Little Endian.\n"); break; default: printf("Whoah - got a return result I'm not expecting %d.\n", i_endian); break; } } cdio_cddap_close_no_free_cdio(d); cdio_destroy( p_cdio ); exit(0); } libcdio-paranoia-release-10.2-2.0.2/example/Makefile.am000066400000000000000000000011511461637345700224110ustar00rootroot00000000000000#################################################### # Sample programs #################################################### # if ENABLE_CPP SUBDIRS = C++ endif noinst_PROGRAMS = paranoia paranoia2 AM_CPPFLAGS = -I$(top_srcdir) $(LIBCDIO_PARANOIA_CFLAGS) $(LIBCDIO_CFLAGS) paranoia_LDADD = $(LIBCDIO_PARANOIA_LIBS) $(LIBCDIO_CDDA_LIBS) $(LIBCDIO_LIBS) $(LTLIBICONV) paranoia2_LDADD = $(LIBCDIO_PARANOIA_LIBS) $(LIBCDIO_CDDA_LIBS) $(LIBCDIO_LIBS) $(LTLIBICONV) check_PROGRAMS = $(noinst_PROGRAMS) TESTS = $(check_PROGRAMS) # iso programs create file "copying" MOSTLYCLEANFILES = copying *.wav libcdio-paranoia-release-10.2-2.0.2/example/README000066400000000000000000000016431461637345700212430ustar00rootroot00000000000000This directory contains some simple examples of the use of the libcdio-paranoia library. One might also possibly find useful C code among the regression tests (directory test), e.g. testcdparanoia.c. In some cases you may have to make small changes to compile these programs. Descriptions of the programs in this example directory are as follows... paranoia: A program to show using CD-DA paranoia (a library for jitter detection and audio-read error correction). This program uses an interface compatible (mostly) with cdparanoia. It looks for a CD-ROM with an audio CD in it and rips up to the first 300 sectors of track 1 to file track01s.wav. paranoia2: Another program to show using CD-DA paranoia using a more libcdio-oriented initialization. Probably more suited to things that otherwise use libcdio such as media players (e.g. for getting CDDB or CD-Text info) libcdio-paranoia-release-10.2-2.0.2/example/paranoia.c000066400000000000000000000125551461637345700223250ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2008, 2009, 2010, 2011, 2012 Rocky Bernstein 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 3 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, see . */ /* Simple program to show using libcdio's version of the CD-DA paranoia. library. */ /* config.h has to come first else _FILE_OFFSET_BITS are redefined in say opensolaris. */ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #ifdef HAVE_ASSERT_H # include #endif #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_UNISTD_H # include #endif # ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #include #include #include static void put_num(long int num, int f, int bytes) { unsigned int i; unsigned char c; for (i=0; bytes--; i++) { c = (num >> (i<<3)) & 0xff; if (write(f, &c, 1)==-1) { perror("Could not write to output."); exit(1); } } } #define writestr(fd, s) \ write(fd, s, sizeof(s)-1) /* Subtract 1 for trailing '\0'. */ /* Write a the header for a WAV file. */ static void write_WAV_header(int fd, int32_t i_bytecount){ ssize_t bytes_ret __attribute__((unused)); /* quick and dirty */ bytes_ret = writestr(fd, "RIFF"); /* 0-3 */ assert(bytes_ret > 0); put_num(i_bytecount+44-8, fd, 4); /* 4-7 */ bytes_ret = writestr(fd, "WAVEfmt "); /* 8-15 */ assert(bytes_ret > 0); put_num(16, fd, 4); /* 16-19 */ put_num(1, fd, 2); /* 20-21 */ put_num(2, fd, 2); /* 22-23 */ put_num(44100, fd, 4); /* 24-27 */ put_num(44100*2*2, fd, 4); /* 28-31 */ put_num(4, fd, 2); /* 32-33 */ put_num(16, fd, 2); /* 34-35 */ bytes_ret = writestr(fd, "data"); /* 36-39 */ assert(bytes_ret > 0); put_num(i_bytecount, fd, 4); /* 40-43 */ } int main(int argc, const char *argv[]) { cdrom_drive_t *d = NULL; /* Place to store handle given by cd-paranoia. */ char **ppsz_cd_drives; /* List of all drives with a loaded CDDA in it. */ /* See if we can find a device with a loaded CD-DA in it. */ ppsz_cd_drives = cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false); if (ppsz_cd_drives && *ppsz_cd_drives) { /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in the list. */ d=cdda_identify(*ppsz_cd_drives, 1, NULL); } else { printf("Unable find or access a CD-ROM drive with an audio CD in it.\n"); exit(77); } /* Don't need a list of CD's with CD-DA's any more. */ cdio_free_device_list(ppsz_cd_drives); if ( !d ) { printf("Unable to identify audio CD disc.\n"); exit(77); } /* We'll set for verbose paranoia messages. */ cdda_verbose_set(d, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT); if ( 0 != cdda_open(d) ) { printf("Unable to open disc.\n"); exit(77); } /* Okay now set up to read up to the first 300 frames of the first audio track of the Audio CD. */ { cdrom_paranoia_t *p = paranoia_init(d); lsn_t i_first_lsn = cdda_disc_firstsector(d); if ( -1 == i_first_lsn ) { printf("Trouble getting starting LSN\n"); } else { lsn_t i_cursor; ssize_t bytes_ret; track_t i_track = cdda_sector_gettrack(d, i_first_lsn); lsn_t i_last_lsn = cdda_track_lastsector(d, i_track); int fd = creat("track1s.wav", 0644); if (-1 == fd) { printf("Unable to create track1s.wav\n"); exit(1); } /* For demo purposes we'll read only 300 frames (about 4 seconds). We don't want this to take too long. On the other hand, I suppose it should be something close to a real test. */ if ( i_last_lsn - i_first_lsn > 300) i_last_lsn = i_first_lsn + 299; printf("Reading track %d from LSN %ld to LSN %ld\n", i_track, (long int) i_first_lsn, (long int) i_last_lsn); /* Set reading mode for full paranoia, but allow skipping sectors. */ paranoia_modeset(p, PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP); paranoia_seek(p, i_first_lsn, SEEK_SET); write_WAV_header(fd, (i_last_lsn-i_first_lsn+1) * CDIO_CD_FRAMESIZE_RAW); for ( i_cursor = i_first_lsn; i_cursor <= i_last_lsn; i_cursor ++) { /* read a sector */ int16_t *p_readbuf=paranoia_read(p, NULL); char *psz_err=cdda_errors(d); char *psz_mes=cdda_messages(d); if (psz_mes || psz_err) printf("%s%s\n", psz_mes ? psz_mes: "", psz_err ? psz_err: ""); free(psz_err); free(psz_mes); if( !p_readbuf ) { printf("paranoia read error. Stopping.\n"); break; } bytes_ret = write(fd, p_readbuf, CDIO_CD_FRAMESIZE_RAW); assert(bytes_ret > 0); } close(fd); } paranoia_free(p); } cdda_close(d); exit(0); } libcdio-paranoia-release-10.2-2.0.2/example/paranoia2.c000066400000000000000000000060121461637345700223760ustar00rootroot00000000000000/* Copyright (C) 2005, 2006, 2008, 2009 Rocky Bernstein 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 3 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, see . */ /* Simple program to show using libcdio's version of the CD-DA paranoia library. But in this version, we'll open a cdio object before calling paranoia's open. I imagine in many cases such as media players this may be what will be done since, one may want to get CDDB/CD-Text info beforehand. */ #ifdef HAVE_CONFIG_H #include "config.h" #define __CDIO_CONFIG_H__ 1 #endif #ifdef HAVE_STDIO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #include #include int main(int argc, const char *argv[]) { cdrom_drive_t *d = NULL; /* Place to store handle given by cd-paranoia. */ char **ppsz_cd_drives; /* List of all drives with a loaded CDDA in it. */ CdIo_t *p_cdio = NULL; /* See if we can find a device with a loaded CD-DA in it. */ ppsz_cd_drives = cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false); if (ppsz_cd_drives) { /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in the list. */ p_cdio = cdio_open(*ppsz_cd_drives, DRIVER_UNKNOWN); d=cdio_cddap_identify_cdio(p_cdio, CDDA_MESSAGE_PRINTIT, NULL); } else { printf("Unable find or access a CD-ROM drive with an audio CD in it.\n"); exit(77); } /* Don't need a list of CD's with CD-DA's any more. */ cdio_free_device_list(ppsz_cd_drives); if ( !d ) { printf("Unable to identify audio CD disc.\n"); exit(77); } /* We'll set for verbose paranoia messages. */ cdio_cddap_verbose_set(d, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT); if ( 0 != cdio_cddap_open(d) ) { printf("Unable to open disc.\n"); exit(77); } /* In the paranoia example was a reading. Here we are going to do something trivial (but I think neat any way - get the Endian-ness of the drive. */ { const int i_endian = data_bigendianp(d); switch (i_endian) { case 0: printf("Drive returns audio data Little Endian." " Your drive is like most.\n"); break; case 1: printf("Drive returns audio data Big Endian.\n"); break; case -1: printf("Don't know whether drive is Big or Little Endian.\n"); break; default: printf("Whoah - got a return result I'm not expecting %d.\n", i_endian); break; } } cdio_cddap_close_no_free_cdio(d); cdio_destroy( p_cdio ); exit(0); } libcdio-paranoia-release-10.2-2.0.2/include/000077500000000000000000000000001461637345700203475ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/include/.gitignore000066400000000000000000000000271461637345700223360ustar00rootroot00000000000000/Makefile /Makefile.in libcdio-paranoia-release-10.2-2.0.2/include/Makefile.am000066400000000000000000000000201461637345700223730ustar00rootroot00000000000000SUBDIRS = cdio libcdio-paranoia-release-10.2-2.0.2/include/cdio/000077500000000000000000000000001461637345700212655ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/include/cdio/.gitignore000066400000000000000000000000271461637345700232540ustar00rootroot00000000000000/Makefile /Makefile.in libcdio-paranoia-release-10.2-2.0.2/include/cdio/Makefile.am000066400000000000000000000000231461637345700233140ustar00rootroot00000000000000SUBDIRS = paranoia libcdio-paranoia-release-10.2-2.0.2/include/cdio/paranoia/000077500000000000000000000000001461637345700230575ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/include/cdio/paranoia/.gitignore000066400000000000000000000000421461637345700250430ustar00rootroot00000000000000/Makefile /Makefile.in /version.h libcdio-paranoia-release-10.2-2.0.2/include/cdio/paranoia/Makefile.am000066400000000000000000000005331461637345700251140ustar00rootroot00000000000000######################################################## # Things to make the install (public) libcdio-paranoia headers ######################################################## # cdio_paranoia_includedir=$(includedir)/cdio/paranoia dist_cdio_paranoia_include_HEADERS = cdda.h paranoia.h toc.h EXTRA_DIST = version.h.in BUILT_SOURCES = version.h libcdio-paranoia-release-10.2-2.0.2/include/cdio/paranoia/cdda.h000066400000000000000000000360051461637345700241270ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2006, 2008, 2011, 2012 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) 2001 Xiph.org and Heiko Eissfeldt heiko@escape.colossus.de 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 3 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, see . */ /** \file cdda.h * * \brief The top-level interface header for libcdio_cdda. * Applications include this for paranoia access. * ******************************************************************/ #ifndef CDIO__PARANOIA__CDDA_H_ #define CDIO__PARANOIA__CDDA_H_ #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** cdrom_paranoia is an opaque structure which is used in all of the library operations. */ typedef struct cdrom_paranoia_s cdrom_paranoia_t; typedef struct cdrom_drive_s cdrom_drive_t; /** For compatibility. cdrom_drive_t is deprecated, use cdrom_drive_t instead. */ /** Flags for simulating jitter used in testing. The enumeration type one probably wouldn't really use in a program. It is here instead of defines to give symbolic names that can be helpful in debuggers where wants just to say refer to CDDA_TEST_JITTER_SMALL and get the correct value. */ typedef enum { CDDA_MESSAGE_FORGETIT = 0, CDDA_MESSAGE_PRINTIT = 1, CDDA_MESSAGE_LOGIT = 2, CD_FRAMESAMPLES = CDIO_CD_FRAMESIZE_RAW / 4, MAXTRK = (CDIO_CD_MAX_TRACKS+1) } paranoia_cdda_enums_t; #include /** We keep MAXTRK since this header is exposed publicly and other programs may have used this. */ #define MAXTRK (CDIO_CD_MAX_TRACKS+1) /** \brief Structure for cdparanoia's CD Table of Contents */ typedef struct TOC_s { unsigned char bTrack; int32_t dwStartSector; } TOC_t; /** For compatibility. TOC is deprecated, use TOC_t instead. */ #define TOC TOC_t /** \brief Structure for cdparanoia's CD-ROM access */ struct cdrom_drive_s { CdIo_t *p_cdio; int opened; /**< This struct may just represent a candidate for opening */ char *cdda_device_name; char *drive_model; int drive_type; int bigendianp; /**< Whether data returned on the CDDA is bigendian or not. 1 if big endian, 0 if little endian and -1 if we don't know. */ int nsectors; /**< Number of sectors use in reading. Multiply by CDIO_CD_FRAMESIZE_RAW to get number of bytes used in the read buffer. */ int cd_extra; /**< -1 if we can't get multisession info, 0 if there is one session only or the multi-session LBA is less than or 100 (don't ask me why -- I don't know), and 1 if the multi-session lba is greater than 100. */ bool b_swap_bytes; /**< Swap bytes if Endian-ness of drive mismatches the endian-ness of the computer? */ track_t tracks; TOC_t disc_toc[MAXTRK]; /**< info here starts origin 0 rather than the first track number (usually 1). So to take a track number and use it here, subtract off cdio_get_first_track_num() beforehand. */ lsn_t audio_first_sector; lsn_t audio_last_sector; int errordest; int messagedest; char *errorbuf; char *messagebuf; /* functions specific to particular drives/interfaces */ int (*enable_cdda) (cdrom_drive_t *d, int onoff); int (*read_toc) (cdrom_drive_t *d); long (*read_audio) (cdrom_drive_t *d, void *p, lsn_t begin, long sectors); int (*set_speed) (cdrom_drive_t *d, int speed); int error_retry; int report_all; int is_atapi; int is_mmc; int last_milliseconds; int i_test_flags; /**< Normally set 0. But if we are testing paranoia operation this can be set to one of the flag masks to simulate a particular kind of failure. */ }; /** Flags for simulating jitter used in testing. The enumeration type one probably wouldn't really use in a program. It is here instead of defines to give symbolic names that can be helpful in debuggers where wants just to say refer to CDDA_TEST_JITTER_SMALL and get the correct value. */ typedef enum { CDDA_TEST_JITTER_SMALL = 1, CDDA_TEST_JITTER_LARGE = 2, CDDA_TEST_JITTER_MASSIVE = 3, CDDA_TEST_FRAG_SMALL = (1<<3), CDDA_TEST_FRAG_LARGE = (2<<3), CDDA_TEST_FRAG_MASSIVE = (3<<3), CDDA_TEST_UNDERRUN = 64 } paranoia_jitter_t; /** jitter testing. The first two bits are set to determine the byte-distance we will jitter the data; 0 is no shifting. */ /**< jitter testing. Set the below bit to always cause jittering on reads. The below bit only has any effect if the first two (above) bits are nonzero. If the above bits are set, but the below bit isn't we'll jitter 90% of the time. */ #define CDDA_TEST_ALWAYS_JITTER 4 /** fragment testing */ #define CDDA_TEST_FRAG_SMALL (1<<3) #define CDDA_TEST_FRAG_LARGE (2<<3) #define CDDA_TEST_FRAG_MASSIVE (3<<3) /**< under-run testing. The below bit is set for testing. */ #define CDDA_TEST_UNDERRUN 64 #if TESTING_IS_FINISHED /** scratch testing */ #define CDDA_TEST_SCRATCH 128 #undef CDDA_TEST_BOGUS_BYTES 256 #undef CDDA_TEST_DROPDUPE_BYTES 512 #endif /* TESTING_IS_FINISHED */ /** autosense functions */ /** Get a CD-ROM drive with a CD-DA in it. If mesagedest is CDDA_MESSAGE_LOGIT, then any messages in the process will be stored in message. When using CDDA_MESSAGE_LOGIT, free the message buffer with cdio_cddap_free_messages() after use. */ extern cdrom_drive_t *cdio_cddap_find_a_cdrom(int messagedest, char **ppsz_message); /** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL if there was an error. @see cdio_cddap_identify_cdio When using CDDA_MESSAGE_LOGIT, free the message buffer with cdio_cddap_free_messages() after use. */ extern cdrom_drive_t *cdio_cddap_identify(const char *psz_device, int messagedest, char **ppsz_message); /** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL if there was an error. In contrast to cdio_cddap_identify, we start out with an initialized p_cdio object. For example you may have used that for other purposes such as to get CDDB/CD-Text information. @see cdio_cddap_identify When using CDDA_MESSAGE_LOGIT, free the message buffer with cdio_cddap_free_messages() after use. */ cdrom_drive_t *cdio_cddap_identify_cdio(CdIo_t *p_cdio, int messagedest, char **ppsz_messages); /** informational functions */ extern const char *cdio_cddap_version(void); /** Returns the current message buffer. Free the returned string using cdio_cddap_free_messages() if not NULL. */ extern char *cdio_cddap_messages(cdrom_drive_t *d); /** Returns the current error buffer. Free the returned string using cdio_cddap_free_messages() if not NULL. */ extern char *cdio_cddap_errors(cdrom_drive_t *d); /** Frees the message string passed in psz_messages. */ extern void cdio_cddap_free_messages(char *psz_messages); /** drive-oriented functions */ extern int cdio_cddap_speed_set(cdrom_drive_t *d, int speed); extern void cdio_cddap_verbose_set(cdrom_drive_t *d, int err_action, int mes_action); /*! Closes d and releases all storage associated with it except the internal p_cdio pointer. @param d cdrom_drive_t object to be closed. @return 0 if passed a null pointer and 1 if not in which case some work was probably done. @see cdio_cddap_close */ bool cdio_cddap_close_no_free_cdio(cdrom_drive_t *d); /*! Closes d and releases all storage associated with it. Doubles as "cdrom_drive_free()". @param d cdrom_drive_t object to be closed. @return 0 if passed a null pointer and 1 if not in which case some work was probably done. @see cdio_cddap_close_no_free_cdio */ extern int cdio_cddap_close(cdrom_drive_t *d); extern int cdio_cddap_open(cdrom_drive_t *d); extern long cdio_cddap_read(cdrom_drive_t *d, void *p_buffer, lsn_t beginsector, long sectors); extern long cdio_cddap_read_timed(cdrom_drive_t *d, void *p_buffer, lsn_t beginsector, long sectors, int *milliseconds); /*! Return the lsn for the start of track i_track */ extern lsn_t cdio_cddap_track_firstsector(cdrom_drive_t *d, track_t i_track); /*! Get last lsn of the track. This generally one less than the start of the next track. -1 is returned on error. */ extern lsn_t cdio_cddap_track_lastsector(cdrom_drive_t *d, track_t i_track); /*! Return the number of tracks on the CD. */ extern track_t cdio_cddap_tracks(cdrom_drive_t *d); /*! Return the track containing the given LSN. If the LSN is before the first track (in the pregap), 0 is returned. If there was an error or the LSN after the LEADOUT (beyond the end of the CD), then CDIO_INVALID_TRACK is returned. */ extern int cdio_cddap_sector_gettrack(cdrom_drive_t *d, lsn_t lsn); /*! Return the number of channels in track: 2 or 4; -2 if not implemented or -1 for error. Not meaningful if track is not an audio track. */ extern int cdio_cddap_track_channels(cdrom_drive_t *d, track_t i_track); /*! Return 1 is track is an audio track, 0 otherwise. */ extern int cdio_cddap_track_audiop(cdrom_drive_t *d, track_t i_track); /*! Return 1 is track has copy permit set, 0 otherwise. */ extern int cdio_cddap_track_copyp(cdrom_drive_t *d, track_t i_track); /*! Return 1 is audio track has linear preemphasis set, 0 otherwise. Only makes sense for audio tracks. */ extern int cdio_cddap_track_preemp(cdrom_drive_t *d, track_t i_track); /*! Get first lsn of the first audio track. -1 is returned on error. */ extern lsn_t cdio_cddap_disc_firstsector(cdrom_drive_t *d); /*! Get last lsn of the last audio track. The last lsn is generally one less than the start of the next track after the audio track. -1 is returned on error. */ extern lsn_t cdio_cddap_disc_lastsector(cdrom_drive_t *d); /*! Determine Endian-ness of the CD-drive based on reading data from it. Some drives return audio data Big Endian while some (most) return data Little Endian. Drives known to return data bigendian are SCSI drives from Kodak, Ricoh, HP, Philips, Plasmon, Grundig CDR100IPW, and Mitsumi CD-R. ATAPI and MMC drives are little endian. rocky: As someone who didn't write the code, I have to say this is nothing less than brilliant. An FFT is done both ways and the the transform is looked at to see which has data in the FFT (or audible) portion. (Or so that's how I understand it.) @return 1 if big-endian, 0 if little-endian, -1 if we couldn't figure things out or some error. */ extern int data_bigendianp(cdrom_drive_t *d); /** transport errors: */ typedef enum { TR_OK = 0, TR_EWRITE = 1 /**< Error writing packet command (transport) */, TR_EREAD = 2 /**< Error reading packet data (transport) */, TR_UNDERRUN = 3 /**< Read underrun */, TR_OVERRUN = 4 /**< Read overrun */, TR_ILLEGAL = 5 /**< Illegal/rejected request */, TR_MEDIUM = 6 /**< Medium error */, TR_BUSY = 7 /**< Device busy */, TR_NOTREADY = 8 /**< Device not ready */, TR_FAULT = 9 /**< Device failure */, TR_UNKNOWN = 10 /**< Unspecified error */, TR_STREAMING = 11 /**< loss of streaming */, } transport_error_t; #ifdef NEED_STRERROR_TR const char *strerror_tr[]={ "Success", "Error writing packet command to device", "Error reading command from device", "SCSI packet data underrun (too little data)", "SCSI packet data overrun (too much data)", "Illegal SCSI request (rejected by target)", "Medium reading data from medium", "Device busy", "Device not ready", "Target hardware fault", "Unspecified error", "Drive lost streaming" }; #endif /*NEED_STERROR_TR*/ /** Errors returned by lib: \verbatim 001: Unable to set CDROM to read audio mode 002: Unable to read table of contents lead-out 003: CDROM reporting illegal number of tracks 004: Unable to read table of contents header 005: Unable to read table of contents entry 006: Could not read any data from drive 007: Unknown, unrecoverable error reading data 008: Unable to identify CDROM model 009: CDROM reporting illegal table of contents 010: Unaddressable sector 100: Interface not supported 101: Drive is neither a CDROM nor a WORM device 102: Permision denied on cdrom (ioctl) device 103: Permision denied on cdrom (data) device 300: Kernel memory error 400: Device not open 401: Invalid track number 402: Track not audio data 403: No audio tracks on disc 404: No medium present 405: Option not supported by drive \endverbatim */ #ifndef DO_NOT_WANT_PARANOIA_COMPATIBILITY /** For compatibility with good ol' paranoia */ #define cdda_find_a_cdrom cdio_cddap_find_a_cdrom #define cdda_identify cdio_cddap_identify #define cdda_version cdio_cddap_version #define cdda_speed_set cdio_cddap_speed_set #define cdda_verbose_set cdio_cddap_verbose_set #define cdda_messages cdio_cddap_messages #define cdda_errors cdio_cddap_errors #define cdda_close cdio_cddap_close #define cdda_open cdio_cddap_open #define cdda_read cdio_cddap_read #define cdda_read_timed cdio_cddap_read_timed #define cdda_track_firstsector cdio_cddap_track_firstsector #define cdda_track_lastsector cdio_cddap_track_lastsector #define cdda_tracks cdio_cddap_tracks #define cdda_sector_gettrack cdio_cddap_sector_gettrack #define cdda_track_channels cdio_cddap_track_channels #define cdda_track_audiop cdio_cddap_track_audiop #define cdda_track_copyp cdio_cddap_track_copyp #define cdda_track_preemp cdio_cddap_track_preemp #define cdda_disc_firstsector cdio_cddap_disc_firstsector #define cdda_disc_lastsector cdio_cddap_disc_lastsector #define cdrom_drive cdrom_drive_t #endif /*DO_NOT_WANT_PARANOIA_COMPATIBILITY*/ #ifdef __cplusplus } #endif /* __cplusplus */ /** The below variables are trickery to force the above enum symbol values to be recorded in debug symbol tables. They are used to allow one to refer to the enumeration value names in the typedefs above in a debugger and debugger expressions */ extern paranoia_jitter_t debug_paranoia_jitter; extern paranoia_cdda_enums_t debug_paranoia_cdda_enums; #ifdef __cplusplus extern "C" { #endif extern const char *cdio_cddap_version(void); extern void cdio_cddap_free_messages(char *psz_messages); #ifdef __cplusplus } #endif #endif /*CDIO__PARANOIA__CDDA_H_*/ libcdio-paranoia-release-10.2-2.0.2/include/cdio/paranoia/paranoia.h000066400000000000000000000173611461637345700250320ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011, 2012 2017 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ /** \file paranoia.h * * \brief The top-level header for libcdda_paranoia: a device- and OS- * independent library for reading CD-DA with error tolerance and * repair. Applications include this for paranoia access. */ #ifndef CDIO__PARANOIA__PARANOIA_H_ #define CDIO__PARANOIA__PARANOIA_H_ #include /*! Paranoia likes to work with 16-bit numbers rather than (possibly byte-swapped) bytes. So there are this many 16-bit numbers block (frame, or sector) read. */ #define CD_FRAMEWORDS (CDIO_CD_FRAMESIZE_RAW/2) /** Flags used in paranoia_modeset. The enumeration type one probably wouldn't really use in a program. It is here instead of defines to give symbolic names that can be helpful in debuggers where wants just to say refer to PARANOIA_MODE_DISABLE and get the correct value. */ typedef enum { PARANOIA_MODE_DISABLE = 0x00, /**< No fixups */ PARANOIA_MODE_VERIFY = 0x01, /**< Verify data integrety in overlap area*/ PARANOIA_MODE_FRAGMENT = 0x02, /**< unsupported */ PARANOIA_MODE_OVERLAP = 0x04, /**< Perform overlapped reads */ PARANOIA_MODE_SCRATCH = 0x08, /**< unsupported */ PARANOIA_MODE_REPAIR = 0x10, /**< unsupported */ PARANOIA_MODE_NEVERSKIP = 0x20, /**< Do not skip failed reads (retry maxretries) */ PARANOIA_MODE_FULL = 0xff, /**< Maximum paranoia - all of the above (except disable) */ } paranoia_mode_t; /** Flags set in a callback. The enumeration type one probably wouldn't really use in a program. It is here instead of defines to give symbolic names that can be helpful in debuggers where wants just to say refer to PARANOIA_CB_READ and get the correct value. */ typedef enum { PARANOIA_CB_READ, /**< Read off adjust ??? */ PARANOIA_CB_VERIFY, /**< Verifying jitter */ PARANOIA_CB_FIXUP_EDGE, /**< Fixed edge jitter */ PARANOIA_CB_FIXUP_ATOM, /**< Fixed atom jitter */ PARANOIA_CB_SCRATCH, /**< Unsupported */ PARANOIA_CB_REPAIR, /**< Unsupported */ PARANOIA_CB_SKIP, /**< Skip exhausted retry */ PARANOIA_CB_DRIFT, /**< Skip exhausted retry */ PARANOIA_CB_BACKOFF, /**< Unsupported */ PARANOIA_CB_OVERLAP, /**< Dynamic overlap adjust */ PARANOIA_CB_FIXUP_DROPPED, /**< Fixed dropped bytes */ PARANOIA_CB_FIXUP_DUPED, /**< Fixed duplicate bytes */ PARANOIA_CB_READERR, /**< Hard read error */ PARANOIA_CB_CACHEERR, /**< Bad cache management */ PARANOIA_CB_WROTE, /**< Wrote block "*" */ PARANOIA_CB_FINISHED /**< Finished writing "*" */ } paranoia_cb_mode_t; extern const char *paranoia_cb_mode2str[]; #ifdef __cplusplus extern "C" { #endif /*! Get libcdio-paranoia version. @return paranoia version string */ extern const char *cdio_paranoia_version(void); /*! Get and initialize a new cdrom_paranoia object from cdrom_drive. Run this before calling any of the other paranoia routines below. @return new cdrom_paranoia object Call paranoia_free() when you are done with it */ extern cdrom_paranoia_t *cdio_paranoia_init(cdrom_drive_t *d); /*! Free any resources associated with p. @param p paranoia object to for which resources are to be freed. @see paranoia_init. */ extern void cdio_paranoia_free(cdrom_paranoia_t *p); /*! Set the kind of repair you want to on for reading. The modes are listed above @param p paranoia type @param mode_flags paranoia mode flags built from values in paranoia_mode_t, e.g. PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP */ extern void cdio_paranoia_modeset(cdrom_paranoia_t *p, int mode_flags); /*! reposition reading offset. @param p paranoia type @param seek byte offset to seek to @param whence like corresponding parameter in libc's lseek, e.g. SEEK_SET or SEEK_END. */ extern lsn_t cdio_paranoia_seek(cdrom_paranoia_t *p, int32_t seek, int whence); /*! Reads the next sector of audio data and returns a pointer to a full sector of verified samples. @param p paranoia object. @param callback callback routine which gets called with the status on each read. @return the audio data read, CDIO_CD_FRAMESIZE_RAW (2352) bytes. This data is not to be freed by the caller. It will persist only until the next call to paranoia_read() for this p. */ extern int16_t *cdio_paranoia_read(cdrom_paranoia_t *p, void(*callback)(long int, paranoia_cb_mode_t)); /*! The same as cdio_paranoia_read but the number of retries is set. @param p paranoia object. @param callback callback routine which gets called with the status on each read. @param max_retries number of times to try re-reading a block before failing. @return the block of CDIO_FRAMEIZE_RAW bytes (or CDIO_FRAMESIZE_RAW / 2 16-bit integers). Unless byte-swapping has been turned off the 16-bit integers Endian independent order. @see cdio_paranoia_read. */ extern int16_t *cdio_paranoia_read_limited(cdrom_paranoia_t *p, void(*callback)(long int, paranoia_cb_mode_t), int max_retries); /*! a temporary hack */ extern void cdio_paranoia_overlapset(cdrom_paranoia_t *p,long overlap); extern void cdio_paranoia_set_range(cdrom_paranoia_t *p, long int start, long int end); /*! Set or query the number of sectors used for paranoia cache modelling. @param p paranoia object @param sectors number of sectors to use, default is 1200 (pass -1 to query current model size without setting a new value) @return number of cache sectors before the call */ extern int cdio_paranoia_cachemodel_size(cdrom_paranoia_t *p,int sectors); #ifndef DO_NOT_WANT_PARANOIA_COMPATIBILITY /** For compatibility with good ol' paranoia */ #define cdrom_paranoia cdrom_paranoia_t #define paranoia_version cdio_paranoia_version #define paranoia_init cdio_paranoia_init #define paranoia_free cdio_paranoia_free #define paranoia_modeset cdio_paranoia_modeset #define paranoia_seek cdio_paranoia_seek #define paranoia_read cdio_paranoia_read #define paranoia_read_limited cdio_paranoia_read_limited #define paranoia_overlapset cdio_paranoia_overlapset #define paranoia_set_range cdio_paranoia_set_range #define paranoia_cachemodel_size cdio_paranoia_cachemodel_size #endif /*DO_NOT_WANT_PARANOIA_COMPATIBILITY*/ #ifdef __cplusplus } #endif /** The below variables are trickery to force the above enum symbol values to be recorded in debug symbol tables. They are used to allow one to refer to the enumeration value names in the typedefs above in a debugger and debugger expressions */ extern paranoia_mode_t debug_paranoia_mode; extern paranoia_cb_mode_t debug_paranoia_cb_mode; #endif /*CDIO__PARANOIA__PARANOIA_H_*/ libcdio-paranoia-release-10.2-2.0.2/include/cdio/paranoia/toc.h000066400000000000000000000037561461637345700240300ustar00rootroot00000000000000/* Copyright (C) 2019 Rocky Bernstein */ /** \file toc.h * * \brief Information from a CDROM TOC relevant to CD-DA disks ******************************************************************/ #ifndef CDIO__PARANOIA__TOC_H_ #define CDIO__PARANOIA__TOC_H_ #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** cdrom_paranoia is an opaque structure which is used in all of the library operations. */ typedef struct cdrom_paranoia_s cdrom_paranoia_t; typedef struct cdrom_drive_s cdrom_drive_t; /*! Return the track containing the given LSN. If the LSN is before the first track (in the pregap), 0 is returned. If there was an error or the LSN after the LEADOUT (beyond the end of the CD), then CDIO_INVALID_TRACK is returned. */ extern int cdio_cddap_sector_gettrack(cdrom_drive_t *d, lsn_t lsn); /*! Return the number of channels in track: 2 or 4; -2 if not implemented or -1 for error. Not meaningful if track is not an audio track. */ extern int cdio_cddap_track_channels(cdrom_drive_t *d, track_t i_track); /*! Return 1 is track is an audio track, 0 otherwise. */ extern int cdio_cddap_track_audiop(cdrom_drive_t *d, track_t i_track); /*! Return 1 is track has copy permit set, 0 otherwise. */ extern int cdio_cddap_track_copyp(cdrom_drive_t *d, track_t i_track); /*! Return 1 is audio track has linear preemphasis set, 0 otherwise. Only makes sense for audio tracks. */ extern int cdio_cddap_track_preemp(cdrom_drive_t *d, track_t i_track); /*! Get first lsn of the first audio track. -1 is returned on error. */ extern lsn_t cdio_cddap_disc_firstsector(cdrom_drive_t *d); /*! Get last lsn of the last audio track. The last lsn is generally one less than the start of the next track after the audio track. -1 is returned on error. */ extern lsn_t cdio_cddap_disc_lastsector(cdrom_drive_t *d); #ifdef __cplusplus } #endif #endif /*CDIO__PARANOIA__TOC_H_*/ libcdio-paranoia-release-10.2-2.0.2/include/cdio/paranoia/version.h.in000066400000000000000000000010141461637345700253160ustar00rootroot00000000000000/** \file include/cdio/paranoia/version.h * * \brief A file containing the libcdio-paranoia package version * number (@VERSION@) and OS build name. */ /*! LIBCDIO_PARANOIA_VERSION is a C-Preprocessor macro of a string that shows what version is used. cdio_paranoia_version_string has the same value, but it is a constant variable that can be accessed at run time. */ #define LIBCDIO_PARANOIA_VERSION "@VERSION@ @build@" extern const char *cdio_paranoia_version_string; /**< = LIBCDIO_PARANOIA_VERSION */ libcdio-paranoia-release-10.2-2.0.2/lib/000077500000000000000000000000001461637345700174725ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/lib/.gitignore000066400000000000000000000000331461637345700214560ustar00rootroot00000000000000/Makefile /Makefile.in /*~ libcdio-paranoia-release-10.2-2.0.2/lib/Makefile.am000066400000000000000000000000421461637345700215220ustar00rootroot00000000000000SUBDIRS = cdda_interface paranoia libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/000077500000000000000000000000001461637345700224055ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/.gitignore000066400000000000000000000001261461637345700243740ustar00rootroot00000000000000/*.lo /*.o /.deps /.libs /Makefile /Makefile.in /libcdio_cdda.la /libcdio_cdda.la.ver libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/Makefile.am000066400000000000000000000147071461637345700244520ustar00rootroot00000000000000# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011, 2012 # Rocky Bernstein # ######################################################## # Things to make the cdda_interface library ######################################################## # # From libtool documentation amended with guidance from N. Boullis: # # 1. Start with version information of `0:0:0' for each libtool library. # # 2. It is probably not a good idea to update the version information # several times between public releases, but rather once per public # release. (This seems to be more an aesthetic consideration than # a hard technical one.) # # 3. If the library source code has changed at all since the last # update, then increment REVISION (`C:R:A' becomes `C:R+1:A'). # # 4. If any interfaces have been added, removed, or changed since the # last update, increment CURRENT, and set REVISION to 0. # # 5. If any interfaces have been added since the last public release, # then increment AGE. # # 6. If any interfaces have been removed or changed since the last # public release, then set AGE to 0. A changed interface means an # incompatibility with previous versions. EXTRA_DIST = libcdio_cdda.sym libcdio_cdda_la_CURRENT = 2 libcdio_cdda_la_REVISION = 0 libcdio_cdda_la_AGE = 0 noinst_HEADERS = common_interface.h drive_exceptions.h low_interface.h \ smallft.h utils.h libcdio_cdda_sources = common_interface.c cddap_interface.c interface.c \ scan_devices.c smallft.c toc.c utils.c drive_exceptions.c lib_LTLIBRARIES = libcdio_cdda.la libcdio_cdda_la_SOURCES = $(libcdio_cdda_sources) libcdio_cdda_la_ldflags = -version-info $(libcdio_cdda_la_CURRENT):$(libcdio_cdda_la_REVISION):$(libcdio_cdda_la_AGE) @LT_NO_UNDEFINED@ AM_CPPFLAGS = $(LIBCDIO_PARANOIA_CFLAGS) $(LIBCDIO_CFLAGS) FLAGS=@LIBCDIO_CFLAGS@ @UCDROM_H@ @TYPESIZES@ @CFLAGS@ OPT=$(FLAGS) DEBUG=$(FLAGS) -DCDDA_TEST ## test: ## $(MAKE) libcdio_cdda.a CFLAGS="$(DEBUG)" ## $(CC) $(DEBUG) -c test_interface.c ## $(LD) $(DEBUG) test_interface.o $(LDFLAGS) -o cdda_test $(LIBS) libcdio_cdda.a LIBS = $(LIBCDIO_LIBS) @LIBS@ @COS_LIB@ ######################################################## # Things to version the symbols in the libraries ######################################################## # An explanation of the versioning problem from Nicolas Boullis and # the versioned symbol solution he uses below... # # Currently, libvcdinfo uses the cdio_open function from libcdio. # Let's imagine a program foobar that uses both the vcdinfo_open # function from libvcdinfo and the cdio_open function from libcdio. # Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME # libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both # libvcdinfo.so.0 and libcdio.so.0. Everything looks fine. # # Now, for some reason, you decide to change the cdio_open function. # That's your right, but you have to bump the CURRENT version and (if I # understand it correctly, athough this is not that clear in libtool's # documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is # sane since the interface changes incompatibly. # Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and # foobar still require libcdio.so.0. Everything is still fine. # Now, after some minor changes, the author of foobar recompiles foobar. # Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar # now segfaults... # What is happening? When you run foobar, if brings both libvcdinfo.so.0 # and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you # have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the # global namespace. Hence, you have to incompatible versions of the # cdio_open function in the name space. When foobar calls cdio_open, it # may choose the wrong function, and segfaults... # With versioned symbols, the cdio_open function from libcdio.so.0 may be # known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open # function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of # libcdio would still be brought in by the most recent foobar, but foobar # (and libvcdinfo) know which versioned function to use and then use the # good one. # This is some simple versioning where every symbol is versioned with # something that looks like the SONAME of the library. More complex (and # better) versioning is possible; it is for example what is used by glibc. # But good complex versioning is something that requires much more # work... # The below is a impliments symbol versioning. First of all, I # compute MAJOR as CURENT - AGE; that is what is used within libtool # (at least on GNU/Linux systems) for the number in the SONAME. The # nm command gives the list of symbols known in each of the object # files that will be part of the shared library. And the sed command # extracts from this list those symbols that will be shared. (This sed # command comes from libtool.) libcdio_cdda_la_MAJOR = $(shell expr $(libcdio_cdda_la_CURRENT) - $(libcdio_cdda_la_AGE)) if VERSION_SCRIPT if BUILD_VERSIONED_LIBS if HAVE_LD_VERSION_SCRIPT libcdio_cdda_la_LDFLAGS = $(libcdio_cdda_la_ldflags) -Wl,--version-script=libcdio_cdda.la.ver else !HAVE_LD_VERSION_SCRIPT libcdio_cdda_la_LDFLAGS = $(libcdio_cdda_la_ldflags) endif # HAVE_LD_VERSION_SCRIPT libcdio_cdda_la_DEPENDENCIES = libcdio_cdda.la.ver libcdio_cdda.la.ver: $(libcdio_cdda_la_OBJECTS) $(srcdir)/libcdio_cdda.sym echo 'CDIO_CDDA_$(libcdio_cdda_la_MAJOR) { ' > $@ objs=`for obj in $(libcdio_cdda_la_OBJECTS); do sed -ne "s/^pic_object='\(.*\)'$$/\1/p" $$obj; done`; \ if test -n "$$objs" ; then \ ${NM} $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_cdda.sym; then if test $$first = true; then echo " global:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \ ${NM} $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_cdda.sym; then :; else if test $$first = true; then echo " local:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \ fi echo '};' >> $@ else !BUILD_VERSIONED_LIBS libcdio_cdda_la_LDFLAGS = $(libcdio_cdda_la_ldflags) endif !BUILD_VERSIONED_LIBS else !VERSION_SCRIPT libcdio_cdda_la_LDFLAGS = $(libcdio_cdda_la_ldflags) endif !VERSION_SCRIPT MOSTLYCLEANFILES = libcdio_cdda.la.ver libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/cddap_interface.c000066400000000000000000000240031461637345700256430ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2007, 2008 Rocky Bernstein Copyright (C) 2014 Robert Kausch Original interface.c Copyright (C) 1994-1997 Eissfeldt heiko@colossus.escape.de Current blenderization Copyright (C) 1998-1999 Monty xiphmont@mit.edu Copyright (C) 1998 Monty xiphmont@mit.edu */ /** CD-ROM code which interfaces between user-level visible CD paranoia routines and libddio routines. (There is some GNU/Linux-specific code here too that should probably be removed. **/ #include "config.h" #include "common_interface.h" #include "low_interface.h" #include "utils.h" /** The below variables are trickery to force the above enum symbol values to be recorded in debug symbol tables. They are used to allow one to refer to the enumeration value names in the typedefs above in a debugger and debugger expressions */ paranoia_jitter_t debug_paranoia_jitter; paranoia_cdda_enums_t debug_paranoia_cdda_enums; /*! reads TOC via libcdio and returns the number of tracks in the disc. 0 is returned if there was an error. */ static int cddap_readtoc (cdrom_drive_t *d) { int i; track_t i_track; /* Save TOC Entries */ d->tracks = cdio_get_num_tracks(d->p_cdio) ; if (CDIO_INVALID_TRACK == d->tracks) return 0; i_track = cdio_get_first_track_num(d->p_cdio); for ( i=0; i < d->tracks; i++) { d->disc_toc[i].bTrack = i_track; d->disc_toc[i].dwStartSector = cdio_get_track_lsn(d->p_cdio, i_track); i_track++; } d->disc_toc[i].bTrack = i_track; d->disc_toc[i].dwStartSector = cdio_get_track_lsn(d->p_cdio, CDIO_CDROM_LEADOUT_TRACK); d->cd_extra=FixupTOC(d, d->tracks+1); /* fixup includes lead-out */ return d->tracks; /* number of tracks returned does not include lead-out */ } /* Set operating speed */ static int cddap_setspeed(cdrom_drive_t *d, int i_speed) { return cdio_set_speed(d->p_cdio, i_speed); } /* read 'i_sector' adjacent audio sectors * into buffer '*p' beginning at sector 'begin' */ static long int read_blocks (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors) { int retry_count = 0; int err; int ret = 0; char *buffer=(char *)p; if(p==NULL)buffer = malloc(i_sectors*CD_FRAMESIZE_RAW); do { struct timespec tv1; struct timespec tv2; int ret1,ret2; ret1 = gettime(&tv1); err = cdio_read_audio_sectors( d->p_cdio, buffer, begin, i_sectors); ret2 = gettime(&tv2); if(ret1<0 || ret2<0) { d->last_milliseconds=-1; } else { d->last_milliseconds = (tv2.tv_sec-tv1.tv_sec)*1000. + (tv2.tv_nsec-tv1.tv_nsec)/1000000.; } if ( DRIVER_OP_SUCCESS != err ) { if (!d->error_retry) { ret=-7; goto done; } if (i_sectors==1) { /* *Could* be I/O or media error. I think. If we're at 30 retries, we better skip this unhappy little sector. */ if (retry_count>MAX_RETRIES-1) { char b[256]; snprintf(b, sizeof(b), "010: Unable to access sector %ld: skipping...\n", (long int) begin); cderror(d, b); ret=-10; goto done; } } if(retry_count>4) if(i_sectors>1) i_sectors=i_sectors*3/4; retry_count++; if (retry_count>MAX_RETRIES) { cderror(d,"007: Unknown, unrecoverable error reading data\n"); ret=-7; goto done; } } else break; } while (err); ret=i_sectors; done: if(p==NULL && buffer)free(buffer); return ret; } typedef enum { JITTER_NONE = 0, JITTER_SMALL= 1, JITTER_LARGE= 2, JITTER_MASSIVE=3 } jitter_baddness_t; /* read 'i_sector' adjacent audio sectors * into buffer '*p' beginning at sector 'begin' */ static long int jitter_read (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors, jitter_baddness_t jitter_badness) { static int i_jitter=0; int jitter_flag; long i_sectors_orig = i_sectors; long i_jitter_offset = 0; char *p_buf=malloc(CDIO_CD_FRAMESIZE_RAW*(i_sectors+1)); if (d->i_test_flags & CDDA_TEST_ALWAYS_JITTER) jitter_flag = 1; else #ifdef HAVE_DRAND48 jitter_flag = (drand48() > .9) ? 1 : 0; #else jitter_flag = (((float)rand()/RAND_MAX) > .9) ? 1 : 0; #endif if (jitter_flag) { int i_coeff = 0; int i_jitter_sectors = 0; switch(jitter_badness) { case JITTER_SMALL : i_coeff = 4; break; case JITTER_LARGE : i_coeff = 32; break; case JITTER_MASSIVE: i_coeff = 128; break; case JITTER_NONE : default : ; } #ifdef HAVE_DRAND48 i_jitter = i_coeff * (int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8); #else i_jitter = i_coeff * (int)((((float)rand()/RAND_MAX)-.5)*CDIO_CD_FRAMESIZE_RAW/8); #endif /* We may need to add another sector to compensate for the bytes that will be dropped off when jittering, and the begin location may be a little different. */ i_jitter_sectors = i_jitter / CDIO_CD_FRAMESIZE_RAW; if (i_jitter >= 0) i_jitter_offset = i_jitter % CDIO_CD_FRAMESIZE_RAW; else { i_jitter_offset = CDIO_CD_FRAMESIZE_RAW - (-i_jitter % CDIO_CD_FRAMESIZE_RAW); i_jitter_sectors--; } if (begin + i_jitter_sectors > 0) { #if TRACE_PARANOIA char buffer[256]; sprintf(buffer, "jittering by %d, offset %ld\n", i_jitter, i_jitter_offset); cdmessage(d,buffer); #endif begin += i_jitter_sectors; i_sectors ++; } else i_jitter_offset = 0; } i_sectors = read_blocks(d, p_buf, begin, i_sectors); if (i_sectors < 0) return i_sectors; if (i_sectors < i_sectors_orig) { /* Had to reduce # of sectors due to read errors. So give full amount, with no jittering. */ if (p) memcpy(p, p_buf, i_sectors*CDIO_CD_FRAMESIZE_RAW); } else { /* Got full amount, but now adjust size for jittering. */ if (p) memcpy(p, p_buf+i_jitter_offset, i_sectors_orig*CDIO_CD_FRAMESIZE_RAW); i_sectors = i_sectors_orig; } free(p_buf); return(i_sectors); } /* read 'i_sector' adjacent audio sectors * into buffer '*p' beginning at sector 'begin' */ static long int cddap_read (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors) { jitter_baddness_t jitter_badness = d->i_test_flags & 0x3; /* read d->nsectors at a time, max. */ i_sectors = ( i_sectors > d->nsectors && d->nsectors > 0 ) ? d->nsectors : i_sectors; /* If we are testing under-run correction, we will deliberately set what we read a frame short. */ if (d->i_test_flags & CDDA_TEST_UNDERRUN ) i_sectors--; if (jitter_badness) { return jitter_read(d, p, begin, i_sectors, jitter_badness); } else return read_blocks(d, p, begin, i_sectors); } static int verify_read_command(cdrom_drive_t *d) { int i; int16_t *buff=malloc(CDIO_CD_FRAMESIZE_RAW); int audioflag=0; int i_test_flags = d->i_test_flags; int first_track = cdio_get_first_track_num(d->p_cdio); d->i_test_flags = 0; cdmessage(d,"Verifying drive can read CDDA...\n"); d->enable_cdda(d,1); for(i=first_track; itracks; i++){ if(cdda_track_audiop(d,i)==1){ long firstsector=cdda_track_firstsector(d,i); long lastsector=cdda_track_lastsector(d,i); long sector=(firstsector+lastsector)>>1; audioflag=1; if(d->read_audio(d,buff,sector,1)>0){ cdmessage(d,"\tExpected command set reads OK.\n"); d->enable_cdda(d,0); free(buff); d->i_test_flags = i_test_flags; return(0); } } } d->enable_cdda(d,0); if(!audioflag){ cdmessage(d,"\tCould not find any audio tracks on this disk.\n"); free(buff); return(-403); } cdmessage(d,"\n\tUnable to read any data; " "drive probably not CDDA capable.\n"); cderror(d,"006: Could not read any data from drive\n"); free(buff); return(-6); } #include "drive_exceptions.h" #ifdef HAVE_LINUX_MAJOR_H static void check_exceptions(cdrom_drive_t *d, const exception_t *list) { int i=0; while(list[i].model){ if(!strncmp(list[i].model,d->drive_model,strlen(list[i].model))){ if(list[i].bigendianp!=-1)d->bigendianp=list[i].bigendianp; return; } i++; } } #endif /* HAVE_LINUX_MAJOR_H */ /* set function pointers to use the ioctl routines */ int cddap_init_drive (cdrom_drive_t *d) { int ret; #if HAVE_LINUX_MAJOR_H switch(d->drive_type){ case MATSUSHITA_CDROM_MAJOR: /* sbpcd 1 */ case MATSUSHITA_CDROM2_MAJOR: /* sbpcd 2 */ case MATSUSHITA_CDROM3_MAJOR: /* sbpcd 3 */ case MATSUSHITA_CDROM4_MAJOR: /* sbpcd 4 */ /* don't make the buffer too big; this sucker don't preempt */ cdmessage(d,"Attempting to set sbpcd buffer size...\n"); d->nsectors=8; #if BUFSIZE_DETERMINATION_FIXED while(1){ /* this ioctl returns zero on error; exactly wrong, but that's what it does. */ if (ioctl(d->ioctl_fd, CDROMAUDIOBUFSIZ, d->nsectors)==0) { d->nsectors>>=1; if(d->nsectors==0){ char buffer[256]; d->nsectors=8; sprintf(buffer,"\tTrouble setting buffer size. Defaulting to %d sectors.\n", d->nsectors); cdmessage(d,buffer); break; /* Oh, well. Try to read anyway.*/ } } else { char buffer[256]; sprintf(buffer,"\tSetting read block size at %d sectors (%ld bytes).\n", d->nsectors,(long)d->nsectors*CDIO_CD_FRAMESIZE_RAW); cdmessage(d,buffer); break; } } #endif /* BUFSIZE_DETERMINATION_FIXED */ break; case IDE0_MAJOR: case IDE1_MAJOR: case IDE2_MAJOR: case IDE3_MAJOR: d->nsectors=8; /* it's a define in the linux kernel; we have no way of determining other than this guess tho */ d->bigendianp=0; d->is_atapi=1; check_exceptions(d, atapi_list); break; default: d->nsectors=25; /* The max for SCSI MMC2 */ } #else { char buffer[256]; d->nsectors = 8; sprintf(buffer,"\tSetting read block size at %d sectors (%ld bytes).\n", d->nsectors,(long)d->nsectors*CDIO_CD_FRAMESIZE_RAW); cdmessage(d,buffer); } #endif /*HAVE_LINUX_MAJOR_H*/ d->enable_cdda = dummy_exception; d->set_speed = cddap_setspeed; d->read_toc = cddap_readtoc; d->read_audio = cddap_read; ret = d->tracks = d->read_toc(d); if(d->tracks<1) return(ret); d->opened=1; if( (ret=verify_read_command(d)) ) return(ret); d->error_retry=1; return(0); } libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/common_interface.c000066400000000000000000000177221461637345700260720ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2007, 2008, 2010, 2011 Rocky Bernstein Copyright (C) 1998, 2002 Monty monty@xiph.org 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 3 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, see . */ /****************************************************************** * * CDROM communication common to all interface methods is done here * (mostly ioctl stuff, but not ioctls specific to the 'cooked' * interface) * ******************************************************************/ /* common_interface.h has to come first else _FILE_OFFSET_BITS are redefined in say opensolaris. */ #include "common_interface.h" #include #include "utils.h" #include "smallft.h" /* Variables to hold debugger-helping enumerations */ enum paranoia_cdda_enums; enum paranoia_jitter_enums; /*! Determine Endian-ness of the CD-drive based on reading data from it. Some drives return audio data Big Endian while some (most) return data Little Endian. Drives known to return data bigendian are SCSI drives from Kodak, Ricoh, HP, Philips, Plasmon, Grundig CDR100IPW, and Mitsumi CD-R. ATAPI and MMC drives are little endian. rocky: As someone who didn't write the code, I have to say this is nothing less than brilliant. An FFT is done both ways and the the transform is looked at to see which has data in the FFT (or audible) portion. (Or so that's how I understand it.) @return 1 if big-endian, 0 if little-endian, -1 if we couldn't figure things out or some error. */ int data_bigendianp(cdrom_drive_t *d) { float lsb_votes=0; float msb_votes=0; int i,checked; int endiancache=d->bigendianp; float *a=calloc(1024,sizeof(float)); float *b=calloc(1024,sizeof(float)); long readsectors=5; int16_t *buff=malloc(readsectors*CDIO_CD_FRAMESIZE_RAW*sizeof(int16_t)); memset(buff, 0, readsectors*CDIO_CD_FRAMESIZE_RAW*sizeof(int16_t)); /* look at the starts of the audio tracks */ /* if real silence, tool in until some static is found */ /* Force no swap for now */ d->bigendianp=-1; cdmessage(d,"\nAttempting to determine drive endianness from data..."); d->enable_cdda(d,1); for(i=cdio_get_first_track_num(d->p_cdio), checked=0; i<=cdio_get_last_track_num(d->p_cdio); i++){ float lsb_energy=0; float msb_energy=0; if(cdda_track_audiop(d,i)==1){ long firstsector=cdda_track_firstsector(d,i); long lastsector=cdda_track_lastsector(d,i); int zeroflag=-1; long beginsec=0; /* find a block with nonzero data */ while(firstsector+readsectors<=lastsector){ int j; if(d->read_audio(d,buff,firstsector,readsectors)>0){ /* Avoid scanning through jitter at the edges */ for(beginsec=0;beginsecenable_cdda(d,0); free(a); free(b); free(buff); return(-1); } } beginsec*=CDIO_CD_FRAMESIZE_RAW/2; /* un-interleave for an FFT */ if(!zeroflag){ int j; for(j=0;j<128;j++) a[j] = le16_to_cpu(buff[j*2+beginsec+460]); for(j=0;j<128;j++) b[j] = le16_to_cpu(buff[j*2+beginsec+461]); fft_forward(128,a,NULL,NULL); fft_forward(128,b,NULL,NULL); for(j=0;j<128;j++) lsb_energy+=fabs(a[j])+fabs(b[j]); for(j=0;j<128;j++) a[j] = be16_to_cpu(buff[j*2+beginsec+460]); for(j=0;j<128;j++) b[j] = be16_to_cpu(buff[j*2+beginsec+461]); fft_forward(128,a,NULL,NULL); fft_forward(128,b,NULL,NULL); for(j=0;j<128;j++) msb_energy+=fabs(a[j])+fabs(b[j]); } } if(lsb_energymsb_energy){ msb_votes+=lsb_energy/msb_energy; checked++; } if(checked==5 && (lsb_votes==0 || msb_votes==0))break; cdmessage(d,"."); } free(buff); free(a); free(b); d->bigendianp=endiancache; d->enable_cdda(d,0); /* How did we vote? Be potentially noisy */ if (lsb_votes>msb_votes) { char buffer[256]; cdmessage(d,"\n\tData appears to be coming back Little Endian.\n"); sprintf(buffer,"\tcertainty: %d%%\n",(int) (100.*lsb_votes/(lsb_votes+msb_votes)+.5)); cdmessage(d,buffer); return(0); } else { if(msb_votes>lsb_votes){ char buffer[256]; cdmessage(d,"\n\tData appears to be coming back Big Endian.\n"); sprintf(buffer,"\tcertainty: %d%%\n",(int) (100.*msb_votes/(lsb_votes+msb_votes)+.5)); cdmessage(d,buffer); return(1); } cdmessage(d,"\n\tCannot determine CDROM drive endianness.\n"); return(bigendianp()); } } /************************************************************************/ /*! Here we fix up a couple of things that will never happen. yeah, right. The multisession stuff is from Hannu code; it assumes it knows the leadout/leadin size. [I think Hannu refers to Hannu Savolainen from GNU/Linux Kernel code.] @return -1 if we can't get multisession info, 0 if there is one session only or the last session LBA is the same as the first audio track and 1 if the multi-session lba is higher than first audio track */ int FixupTOC(cdrom_drive_t *d, track_t i_tracks) { int j; /* First off, make sure the 'starting sector' is >=0 */ for( j=0; jdisc_toc[j].dwStartSector<0 ) { cdmessage(d,"\n\tTOC entry claims a negative start offset: massaging" ".\n"); d->disc_toc[j].dwStartSector=0; } if( jdisc_toc[j].dwStartSector> d->disc_toc[j+1].dwStartSector ) { cdmessage(d,"\n\tTOC entry claims an overly large start offset: massaging" ".\n"); d->disc_toc[j].dwStartSector=0; } } /* Make sure the listed 'starting sectors' are actually increasing. Flag things that are blatant/stupid/wrong */ { lsn_t last=d->disc_toc[0].dwStartSector; for ( j=1; jdisc_toc[j].dwStartSectordisc_toc[j].dwStartSector=last; } last=d->disc_toc[j].dwStartSector; } } d->audio_last_sector = CDIO_INVALID_LSN; { lsn_t last_ses_lsn; if (cdio_get_last_session (d->p_cdio, &last_ses_lsn) < 0) return -1; /* A Red Book Disc must have only one session, otherwise this is a * CD Extra */ if (last_ses_lsn > d->disc_toc[0].dwStartSector) { /* CD Extra discs have two session, the first one ending after * the last audio track * Thus the need to fix the length of the the audio data portion to * not cross the lead-out of this session */ for (j = i_tracks-1; j > 1; j--) { if (cdio_get_track_format(d->p_cdio, j+1) != TRACK_FORMAT_AUDIO && cdio_get_track_format(d->p_cdio, j) == TRACK_FORMAT_AUDIO) { /* First session lead-out is 1:30 * Lead-ins are 1:00 * Every session's first track have a 0:02 pregap * * That makes a control data section of (90+60+2)*75 sectors in the * last audio track */ const int gap = ((90+60+2) * CDIO_CD_FRAMES_PER_SEC); if ((last_ses_lsn - gap >= d->disc_toc[j-1].dwStartSector) && (last_ses_lsn - gap < d->disc_toc[j].dwStartSector)) { d->audio_last_sector = last_ses_lsn - gap - 1; break; } } } return 1; } } return 0; } libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/common_interface.h000066400000000000000000000020641461637345700260700ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2008, 2009, 2010, 2011 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu */ #ifndef _CDDA_COMMON_INTERFACE_H_ #define _CDDA_COMMON_INTERFACE_H_ #if defined(HAVE_CONFIG_H) && !defined(__CDIO_CONFIG_H__) # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #include #include "low_interface.h" #if defined(HAVE_LSTAT) && !defined(HAVE_WIN32_CDROM) && !defined(HAVE_OS2_CDROM) /* Define this if the CD-ROM device is a file in the filesystem that can be lstat'd */ #define DEVICE_IN_FILESYSTEM 1 #else #undef DEVICE_IN_FILESYSTEM #endif /** Test for presence of a cdrom by pinging with the 'CDROMVOLREAD' ioctl() */ extern int ioctl_ping_cdrom(int fd); extern char *atapi_drive_info(int fd); /*! Here we fix up a couple of things that will never happen. yeah, right. rocky OMITTED FOR NOW: The multisession stuff is from Hannu's code; it assumes it knows the leadout/leadin size. */ extern int FixupTOC(cdrom_drive_t *d, track_t tracks); #endif /*_CDDA_COMMON_INTERFACE_H_*/ libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/drive_exceptions.c000066400000000000000000000070401461637345700261240ustar00rootroot00000000000000/* Copyright (C) 2004, 2008, 2011 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ #include "common_interface.h" #include "drive_exceptions.h" int dummy_exception (cdrom_drive_t *d,int Switch) { return(0); } #if HAVE_LINUX_MAJOR_H /* list of drives that affect autosensing in ATAPI specific portions of code (force drives to detect as ATAPI or SCSI, force ATAPI read command */ const exception_t atapi_list[]={ {"SAMSUNG SCR-830 REV 2.09 2.09 ", 1, 0, dummy_exception,scsi_read_mmc2,0}, {"Memorex CR-622", 1, 0, dummy_exception, NULL,0}, {"SONY CD-ROM CDU-561", 0, 0, dummy_exception, NULL,0}, {"Chinon CD-ROM CDS-525", 0, 0, dummy_exception, NULL,0}, {NULL,0,0,NULL,NULL,0}}; #endif /*HAVE_LINUX_MAJOR_H*/ /* list of drives that affect MMC default settings */ #ifdef NEED_MMC_LIST static exception_t mmc_list[]={ {"SAMSUNG SCR-830 REV 2.09 2.09 ", 1, 0, dummy_exception,scsi_read_mmc2,0}, {"Memorex CR-622", 1, 0, dummy_exception, NULL,0}, {"SONY CD-ROM CDU-561", 0, 0, dummy_exception, NULL,0}, {"Chinon CD-ROM CDS-525", 0, 0, dummy_exception, NULL,0}, {"KENWOOD CD-ROM UCR", -1, 0, NULL,scsi_read_D8, 0}, {NULL,0,0,NULL,NULL,0}}; #endif /*NEED_MMC_LIST*/ /* list of drives that affect SCSI default settings */ #ifdef NEED_SCSI_LIST static exception_t scsi_list[]={ {"TOSHIBA", -1,0x82,scsi_enable_cdda,scsi_read_28, 0}, {"IBM", -1,0x82,scsi_enable_cdda,scsi_read_28, 0}, {"DEC", -1,0x82,scsi_enable_cdda,scsi_read_28, 0}, {"IMS", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, {"KODAK", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, {"RICOH", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, {"HP", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, {"PHILIPS", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, {"PLASMON", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, {"GRUNDIG CDR100IPW", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, {"MITSUMI CD-R ", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, {"KENWOOD CD-ROM UCR", -1, 0, NULL,scsi_read_D8, 0}, {"YAMAHA", -1, 0,scsi_enable_cdda, NULL, 0}, {"PLEXTOR", -1, 0, NULL, NULL, 0}, {"SONY", -1, 0, NULL, NULL, 0}, {"NEC", -1, 0, NULL,scsi_read_D4_10,0}, /* the 7501 locks up if hit with the 10 byte version from the autoprobe first */ {"MATSHITA CD-R CW-7501", -1, 0, NULL,scsi_read_D4_12,-1}, {NULL,0,0,NULL,NULL,0}}; #endif /* NEED_SCSI_LIST*/ libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/drive_exceptions.h000066400000000000000000000035631461637345700261370ustar00rootroot00000000000000/* $Id: drive_exceptions.h,v 1.6 2008/06/13 19:26:23 flameeyes Exp $ Copyright (C) 2004, 2008 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ extern int scsi_enable_cdda(cdrom_drive_t *d, int); extern long scsi_read_mmc(cdrom_drive_t *d, void *,long,long); extern long scsi_read_D4_10(cdrom_drive_t *, void *,long,long); extern long scsi_read_D4_12(cdrom_drive_t *, void *,long,long); extern long scsi_read_D8(cdrom_drive_t *, void *,long,long); extern long scsi_read_28(cdrom_drive_t *, void *,long,long); extern long scsi_read_A8(cdrom_drive_t *, void *,long,long); typedef struct exception { const char *model; int atapi; /* If the ioctl doesn't work */ unsigned char density; int (*enable)(cdrom_drive_t *,int); long (*read)(cdrom_drive_t *,void *, long, long); int bigendianp; } exception_t; /* specific to general */ #ifdef FINISHED_DRIVE_EXCEPTIONS extern long scsi_read_mmc2(cdrom_drive_t *d, void *,long,long); #else #define scsi_read_mmc2 NULL #endif int dummy_exception (cdrom_drive_t *d,int Switch); #if HAVE_LINUX_MAJOR_H extern const exception_t atapi_list[]; #endif #ifdef NEED_MMC_LIST extern const exception_t mmc_list[]; #endif #ifdef NEED_SCSI_LIST extern const exception_t scsi_list[]; #endif libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/interface.c000066400000000000000000000115601461637345700245140ustar00rootroot00000000000000/* Copyright (C) 2005, 2008 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ /****************************************************************** * Top-level interface module for cdrom drive access. SCSI, ATAPI, etc * specific stuff are in other modules. Note that SCSI does use * specialized ioctls; these appear in common_interface.c where the * generic_scsi stuff is in scsi_interface.c. * ******************************************************************/ #include "common_interface.h" #include "low_interface.h" #include "utils.h" #include #include #include extern const char *cdio_cddap_version(void){ return LIBCDIO_PARANOIA_VERSION; } static void _clean_messages(cdrom_drive_t *d) { if(d){ if(d->messagebuf)free(d->messagebuf); if(d->errorbuf)free(d->errorbuf); d->messagebuf=NULL; d->errorbuf=NULL; } } /*! Closes d and releases all storage associated with it except the internal p_cdio pointer. @param d cdrom_drive_t object to be closed. @return 0 if passed a null pointer and 1 if not in which case some work was probably done. @see cdio_cddap_close */ bool cdio_cddap_close_no_free_cdio(cdrom_drive_t *d) { if(d){ if(d->opened) d->enable_cdda(d,0); _clean_messages(d); if (d->cdda_device_name) free(d->cdda_device_name); if (d->drive_model) free(d->drive_model); d->cdda_device_name = d->drive_model = NULL; free(d); return true; } return false; } /*! Closes d and releases all storage associated with it. Doubles as "cdrom_drive_free()". @param d cdrom_drive_t object to be closed. @return 0 if passed a null pointer and 1 if not in which case some work was probably done. @see cdio_cddap_close_no_free_cdio */ int cdio_cddap_close(cdrom_drive_t *d) { if (d) { CdIo_t *p_cdio = d->p_cdio; cdio_cddap_close_no_free_cdio(d); cdio_destroy (p_cdio); return 1; } return 0; } /* finish initializing the drive! */ int cdio_cddap_open(cdrom_drive_t *d) { int ret; if(d->opened)return(0); if ( (ret=cddap_init_drive(d)) ) return(ret); /* Check TOC, enable for CDDA */ /* Some drives happily return a TOC even if there is no disc... */ { int i; for(i=0; itracks; i++) if(d->disc_toc[i].dwStartSector<0 || d->disc_toc[i+1].dwStartSector==0){ d->opened=0; cderror(d,"009: CDROM reporting illegal table of contents\n"); return(-9); } } if((ret=d->enable_cdda(d,1))) return(ret); /* d->select_speed(d,d->maxspeed); most drives are full speed by default */ if ( -1 == d->bigendianp ) { d->bigendianp = data_bigendianp(d); } return(0); } int cdio_cddap_speed_set(cdrom_drive_t *d, int speed) { if(d->set_speed) if(!d->set_speed(d, speed))return 0; cderror(d,"405: Option not supported by drive\n"); return -405; } long cdio_cddap_read_timed(cdrom_drive_t *d, void *buffer, lsn_t beginsector, long sectors, int *ms) { if(ms)*ms= -1; if (d->opened) { if (sectors>0) { sectors=d->read_audio(d, buffer, beginsector, sectors); if (sectors > 0) { /* byteswap? */ if ( d->bigendianp == -1 ) /* not determined yet */ d->bigendianp = data_bigendianp(d); if ( buffer && d->b_swap_bytes && d->bigendianp != bigendianp() ) { int i; uint16_t *p=(uint16_t *)buffer; long els=sectors*CDIO_CD_FRAMESIZE_RAW/2; for(i=0;ilast_milliseconds; return(sectors); } cderror(d,"400: Device not open\n"); return(-400); } long cdio_cddap_read(cdrom_drive_t *d, void *buffer, lsn_t beginsector, long sectors){ return cdda_read_timed(d,buffer,beginsector,sectors,NULL); } void cdio_cddap_verbose_set(cdrom_drive_t *d,int err_action, int mes_action) { d->messagedest=mes_action; d->errordest=err_action; } extern char * cdio_cddap_messages(cdrom_drive_t *d) { char *ret=d->messagebuf; d->messagebuf=NULL; return(ret); } extern char * cdio_cddap_errors(cdrom_drive_t *d) { char *ret=d->errorbuf; d->errorbuf=NULL; return(ret); } extern void cdio_cddap_free_messages(char *psz_messages) { if (psz_messages != NULL) free(psz_messages); } libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/libcdio_cdda.sym000066400000000000000000000010661461637345700255220ustar00rootroot00000000000000cdio_cddap_find_a_cdrom cdio_cddap_free_messages cdio_cddap_identify cdio_cddap_identify_cdio cdio_cddap_version cdio_cddap_speed_set cdio_cddap_verbose_set cdio_cddap_messages cdio_cddap_errors cdio_cddap_close_no_free_cdio cdio_cddap_close cdio_cddap_open cdio_cddap_read cdio_cddap_read_timed cdio_cddap_track_firstsector cdio_cddap_track_lastsector cdio_cddap_tracks cdio_cddap_sector_gettrack cdio_cddap_track_channels cdio_cddap_track_audiop cdio_cddap_track_copyp cdio_cddap_track_preemp cdio_cddap_disc_firstsector cdio_cddap_disc_lastsector data_bigendianp libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/low_interface.h000066400000000000000000000020461461637345700254010ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2008 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu */ /** internal include file for cdda interface kit for Linux */ #ifndef _CDDA_LOW_INTERFACE_ #define _CDDA_LOW_INTERFACE_ #ifdef HAVE_STDIO_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_LINUX_VERSION_H #include #endif #include #include /* some include file locations have changed with newer kernels */ #ifndef CDROMAUDIOBUFSIZ #define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ #endif #ifdef HAVE_LINUX_CDROM_H #include #endif #ifdef HAVE_LINUX_MAJOR_H #include #endif #define MAX_RETRIES 8 #define MAX_BIG_BUFF_SIZE 65536 #define MIN_BIG_BUFF_SIZE 4096 #define SG_OFF sizeof(struct sg_header) extern int cddap_init_drive (cdrom_drive_t *d); #endif /*_CDDA_LOW_INTERFACE_*/ libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/scan_devices.c000066400000000000000000000214211461637345700251770ustar00rootroot00000000000000/* $Id: scan_devices.c,v 1.33 2008/06/16 19:45:44 flameeyes Exp $ Copyright (C) 2004, 2005, 2007, 2008, 2009 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ /****************************************************************** * * Autoscan for or verify presence of a CD-ROM device * ******************************************************************/ #include "common_interface.h" #include "low_interface.h" #include "utils.h" #include "cdio/mmc.h" #include "cdio/util.h" #include #include #ifdef HAVE_PWD_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifndef PATH_MAX #define PATH_MAX 4096 #endif static const char cdrom_devices[][32]={ "/dev/cdrom", "/dev/cdroms/cdrom?", "/dev/hd?", "/dev/sg?", "/dev/cdu31a", "/dev/cdu535", "/dev/sbpcd", "/dev/sbpcd?", "/dev/sonycd", "/dev/mcd", "/dev/sjcd", /* "/dev/aztcd", timeout is too long */ "/dev/cm206cd", "/dev/gscd", "/dev/optcd", ""}; static cdrom_drive_t * cdda_identify_device_cdio(CdIo_t *p_cdio, const char *psz_device, int messagedest, char **ppsz_messages); /* Functions here look for a cdrom drive; full init of a drive type happens in interface.c */ cdrom_drive_t * cdio_cddap_find_a_cdrom(int messagedest, char **ppsz_messages){ /* Brute force... */ int i=0; cdrom_drive_t *d; while(*cdrom_devices[i]!='\0'){ /* is it a name or a pattern? */ char *pos; if((pos=strchr(cdrom_devices[i],'?'))){ int j; /* try first eight of each device */ for(j=0;j<4;j++){ char *buffer=strdup(cdrom_devices[i]); /* number, then letter */ buffer[pos-(cdrom_devices[i])]=j+48; if((d=cdda_identify(buffer, messagedest, ppsz_messages))) return(d); idmessage(messagedest, ppsz_messages, "", NULL); buffer[pos-(cdrom_devices[i])]=j+97; if((d=cdda_identify(buffer, messagedest, ppsz_messages))) return(d); idmessage(messagedest, ppsz_messages, "", NULL); free(buffer); } }else{ /* Name. Go for it. */ if((d=cdda_identify(cdrom_devices[i], messagedest, ppsz_messages))) return(d); idmessage(messagedest, ppsz_messages, "", NULL); } i++; } { #if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) struct passwd *temp; temp=getpwuid(geteuid()); idmessage(messagedest, ppsz_messages, "\n\nNo cdrom drives accessible to %s found.\n", temp->pw_name); #else idmessage(messagedest, ppsz_messages, "\n\nNo cdrom drives accessible found.\n", NULL); #endif } return(NULL); } #ifdef DEVICE_IN_FILESYSTEM static char * test_resolve_symlink(const char *file, int messagedest, char **ppsz_messages) { char resolved[PATH_MAX]; struct stat st; if (lstat(file,&st)){ idperror(messagedest, ppsz_messages, "\t\tCould not stat %s",file); return(NULL); } if (cdio_realpath(file,resolved)) return(strdup(resolved)); idperror(messagedest, ppsz_messages, "\t\tCould not resolve symlink %s", file); return(NULL); } #endif /** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL if there was an error. @see cdio_cddap_identify_cdio */ cdrom_drive_t * cdio_cddap_identify(const char *psz_dev, int messagedest, char **ppsz_messages) { CdIo_t *p_cdio = NULL; if (psz_dev) idmessage(messagedest, ppsz_messages, "Checking %s for cdrom...", psz_dev); else idmessage(messagedest, ppsz_messages, "Checking for cdrom...", NULL); #ifdef DEVICE_IN_FILESYSTEM if (psz_dev) { char *psz_device = test_resolve_symlink(psz_dev, messagedest, ppsz_messages); if ( psz_device ) { cdrom_drive_t *d=NULL; p_cdio = cdio_open(psz_device, DRIVER_UNKNOWN); d = cdda_identify_device_cdio(p_cdio, psz_device, messagedest, ppsz_messages); free(psz_device); return d; } } #endif p_cdio = cdio_open(psz_dev, DRIVER_UNKNOWN); if (p_cdio) { if (!psz_dev) { psz_dev = cdio_get_arg(p_cdio, "source"); } return cdda_identify_device_cdio(p_cdio, psz_dev, messagedest, ppsz_messages); } return NULL; } /** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL if there was an error. In contrast to cdio_cddap_identify, we start out with an initialized p_cdio object. For example you may have used that for other purposes such as to get CDDB/CD-Text information. @see cdio_cddap_identify */ cdrom_drive_t * cdio_cddap_identify_cdio(CdIo_t *p_cdio, int messagedest, char **ppsz_messages) { if (!p_cdio) return NULL; { const char *psz_device = cdio_get_arg(p_cdio, "source"); idmessage(messagedest, ppsz_messages, "Checking %s for cdrom...", psz_device); return cdda_identify_device_cdio(p_cdio, psz_device, messagedest, ppsz_messages); } } static cdrom_drive_t * cdda_identify_device_cdio(CdIo_t *p_cdio, const char *psz_device, int messagedest, char **ppsz_messages) { cdrom_drive_t *d=NULL; int drive_type = 0; char *description=NULL; #ifdef HAVE_LINUX_MAJOR_H struct stat st; #endif if (!p_cdio) { idperror(messagedest, ppsz_messages, "\t\tUnable to open %s", psz_device); return NULL; } #ifdef HAVE_LINUX_MAJOR_H if ( 0 == stat(psz_device, &st) ) { if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { drive_type=(int)(st.st_rdev>>8); switch (drive_type) { case IDE0_MAJOR: case IDE1_MAJOR: case IDE2_MAJOR: case IDE3_MAJOR: /* Yay, ATAPI... */ description=strdup("ATAPI compatible "); break; case CDU31A_CDROM_MAJOR: /* major indicates this is a cdrom; no ping necessary. */ description=strdup("Sony CDU31A or compatible"); break; case CDU535_CDROM_MAJOR: /* major indicates this is a cdrom; no ping necessary. */ description=strdup("Sony CDU535 or compatible"); break; case MATSUSHITA_CDROM_MAJOR: case MATSUSHITA_CDROM2_MAJOR: case MATSUSHITA_CDROM3_MAJOR: case MATSUSHITA_CDROM4_MAJOR: /* major indicates this is a cdrom; no ping necessary. */ description=strdup("non-ATAPI IDE-style Matsushita/Panasonic CR-5xx or compatible"); break; case SANYO_CDROM_MAJOR: description=strdup("Sanyo proprietary or compatible: NOT CDDA CAPABLE"); break; case MITSUMI_CDROM_MAJOR: case MITSUMI_X_CDROM_MAJOR: description=strdup("Mitsumi proprietary or compatible: NOT CDDA CAPABLE"); break; case OPTICS_CDROM_MAJOR: description=strdup("Optics Dolphin or compatible: NOT CDDA CAPABLE"); break; case AZTECH_CDROM_MAJOR: description=strdup("Aztech proprietary or compatible: NOT CDDA CAPABLE"); break; case GOLDSTAR_CDROM_MAJOR: description=strdup("Goldstar proprietary: NOT CDDA CAPABLE"); break; case CM206_CDROM_MAJOR: description=strdup("Philips/LMS CM206 proprietary: NOT CDDA CAPABLE"); break; case SCSI_CDROM_MAJOR: case SCSI_GENERIC_MAJOR: /* Nope nope nope */ description=strdup("SCSI CD-ROM"); break; default: /* What the hell is this? */ idmessage(messagedest, ppsz_messages, "\t\t%s is not a cooked ioctl CDROM.", psz_device); return(NULL); } } } #endif /*HAVE_LINUX_MAJOR_H*/ /* Minimum init */ d=calloc(1, sizeof(cdrom_drive_t)); d->p_cdio = p_cdio; d->cdda_device_name = strdup(psz_device); d->drive_type = drive_type; d->bigendianp = -1; /* We don't know yet... */ d->nsectors = -1; /* We don't know yet... */ d->messagedest = messagedest; d->b_swap_bytes = true; { cdio_hwinfo_t hw_info = { "UNKNOWN", "Unknown model", "????" }; if ( mmc_get_hwinfo( p_cdio, &hw_info ) ) { unsigned int i_len = strlen(hw_info.psz_vendor) + strlen(hw_info.psz_model) + strlen(hw_info.psz_revision) + 5; if (description) { i_len += strlen(description); d->drive_model=malloc( i_len ); snprintf( d->drive_model, i_len, "%s %s %s %s", hw_info.psz_vendor, hw_info.psz_model, hw_info.psz_revision, description ); } else { d->drive_model=malloc( i_len ); snprintf( d->drive_model, i_len, "%s %s %s", hw_info.psz_vendor, hw_info.psz_model, hw_info.psz_revision ); } idmessage(messagedest, ppsz_messages, "\t\tCDROM sensed: %s\n", d->drive_model); } } if (description) free(description); return(d); } libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/smallft.c000066400000000000000000000244001461637345700242130ustar00rootroot00000000000000/* Copyright (C) 2008 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ /****************************************************************** * FFT implementation from OggSquish, minus cosine transforms, * minus all but radix 2/4 case * * See OggSquish or NetLib for the version that can do other than just * power-of-two sized vectors. ******************************************************************/ #include #include #include "smallft.h" static void drfti1(int n, float *wa, int *ifac){ static int ntryh[4] = { 4,2,3,5 }; static float tpi = 6.28318530717958647692528676655900577; float arg,argh,argld,fi; int ntry=0,i,j=-1; int k1, l1, l2, ib; int ld, ii, ip, is, nq, nr; int ido, ipm, nfm1; int nl=n; int nf=0; L101: j++; if (j < 4) ntry=ntryh[j]; else ntry+=2; L104: nq=nl/ntry; nr=nl-ntry*nq; if (nr!=0) goto L101; nf++; ifac[nf+1]=ntry; nl=nq; if(ntry!=2)goto L107; if(nf==1)goto L107; for (i=1;i Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ /****************************************************************** * FFT implementation from OggSquish, minus cosine transforms. * Only convenience functions exposed ******************************************************************/ extern void fft_forward(int n, float *buf, float *trigcache, int *sp); extern void fft_backward(int n, float *buf, float *trigcache, int *sp); extern void fft_i(int n, float **trigcache, int **splitcache); libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/test_interface.c000066400000000000000000000133001461637345700255450ustar00rootroot00000000000000/* Copyright (C) 2004, 2008 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ /****************************************************************** * * Fake interface backend for testing paranoia layer * NOTE: THIS CODE HAVE BEEN FOLDED INTO THE MAINLINE CODE SO IT IS * NOT USED ANYMORE. (It's not clear that it had been used * for a while in the non-libcdio cdparaonoia either.) * ******************************************************************/ #ifdef CDDA_TEST #include "low_interface.h" #include "utils.h" /* Build which test model? */ #define CDDA_TEST_OK #undef CDDA_TEST_JITTER_SMALL #undef CDDA_TEST_JITTER_LARGE #undef CDDA_TEST_JITTER_MASSIVE #undef CDDA_TEST_FRAG_SMALL #undef CDDA_TEST_FRAG_LARGE #undef CDDA_TEST_FRAG_MASSIVE #undef CDDA_TEST_BOGUS_BYTES #undef CDDA_TEST_DROPDUPE_BYTES #undef CDDA_TEST_SCRATCH #undef CDDA_TEST_UNDERRUN #undef CDDA_TEST_ALLJITTER #undef CDDA_TEST_SOMEJITTER #undef CDDA_TEST_SEEKJITTER static int test_readtoc (cdrom_drive *d){ int tracks=0; long bytes; long sectors; /* only one track, as many sectors as the file */ bytes=lseek(d->cdda_fd,0,SEEK_END); lseek(d->cdda_fd,0,SEEK_SET); sectors=bytes/CDIO_CD_FRAMESIZE_RAW; d->disc_toc[0].bFlags = 0; d->disc_toc[0].bTrack = 1; d->disc_toc[0].dwStartSector = 37; d->disc_toc[1].bFlags = 0x4; d->disc_toc[1].bTrack = CDROM_LEADOUT; d->disc_toc[1].dwStartSector = sectors+37; tracks=2; d->cd_extra=0; return(--tracks); /* without lead-out */ } /* we emulate jitter, scratches, atomic jitter and bogus bytes on boundaries, etc */ static long test_read(cdrom_drive *d, void *p, long begin, long sectors) { #if defined(CDDA_TEST_SEEKJITTER) \ || defined(CDDA_TEST_ALLJITTER) \ || defined(CDDA_TEST_SOMEJITTER) int jitter_flag; #endif int los_flag; static int jitter=0; int bytes_so_far=0; long bytestotal; static FILE *fd=NULL; static long lastread=0; if(!fd)fd=fdopen(d->cdda_fd,"r"); if(beginlast_milliseconds=20; else d->last_milliseconds=sectors; #ifdef CDDA_TEST_UNDERRUN sectors-=1; #endif #ifdef CDDA_TEST_SEEKJITTER if(lastread!=begin)jitter_flag=1; #else #ifdef CDDA_TEST_ALLJITTER jitter_flag=1; #else #ifdef CDDA_TEST_SOMEJITTER jitter_flag=(drand48()>.9?1:0); los_flag=(drand48()>.9?1:0); #else los_flag=1; #endif #endif #endif lastread=begin+sectors; bytestotal=sectors*CDIO_CD_FRAMESIZE_RAW; begin*=CDIO_CD_FRAMESIZE_RAW; while(bytes_so_far.8) this_jitter=32; else this_jitter=0; #endif #endif #endif #endif #endif #endif #endif #endif if(begin+jitter+bytes_so_far<0)jitter=0; seeki=begin+bytes_so_far+jitter; if(fseek(fd,seeki,SEEK_SET)<0){ return(0); } if(!inner_buf){ char *temp = malloc(this_bytes); rbytes=fread(temp,1,this_bytes,fd); free(temp); }else rbytes=fread(inner_buf,1,this_bytes,fd); bytes_so_far+=rbytes; if(rbytes==0)break; #ifdef CDDA_TEST_SEEKJITTER jitter_flag=0; los_flag=0; #else #ifdef CDDA_TEST_ALLJITTER jitter_flag=1; los_flag=0; #else #ifdef CDDA_TEST_SOMEJITTER jitter_flag=(drand48()>.9?1:0); los_flag=(drand48()>.9?1:0); #else los_flag=1; #endif #endif #endif } #ifdef CDDA_TEST_SCRATCH { long location=300*CDIO_CD_FRAMESIZE_RAW+(drand48()*56)+512; if(begin<=location && begin+bytestotal>location){ if(p)memset(p+location-begin,(int)(drand48()*256),1100); } } #endif return(sectors); } /* set function pointers to use the ioctl routines */ int test_init_drive (cdrom_drive *d){ d->nsectors=13; d->enable_cdda = dummy_exception; d->read_audio = test_read; d->read_toc = test_readtoc; d->set_speed = dummy_exception; d->tracks=d->read_toc(d); if(d->tracks==-1) return(d->tracks); d->opened=1; srand48(0); return(0); } #endif libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/toc.c000066400000000000000000000152231461637345700233410ustar00rootroot00000000000000/* Copyright (C) 2005, 2008, 2013, 2019 Rocky Bernstein Copyright (C) 1998-2008 Monty xiphmont@mit.edu derived from code (C) 1994-1996 Heiko Eissfeldt 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 3 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, see . */ /****************************************************************** * Table of contents convenience functions ******************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #include "low_interface.h" #include "utils.h" #include /*! Return the lsn for the start of track i_track or CDIO_LEADOUT_TRACK */ lsn_t cdda_track_firstsector(cdrom_drive_t *d, track_t i_track) { if(!d->opened){ cderror(d,"400: Device not open\n"); return(-400); } else { const track_t i_first_track = cdio_get_first_track_num(d->p_cdio); const track_t i_last_track = cdio_get_last_track_num(d->p_cdio) + 1; /* include leadout */ if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = i_last_track; if (i_track == 0) { if (d->disc_toc[0].dwStartSector == 0) { /* first track starts at lba 0 -> no pre-gap */ cderror(d,"402: No initial pregap\n"); return(-402); } else { return 0; /* pre-gap of first track always starts at lba 0 */ } } else if (i_track < i_first_track || i_track > i_last_track) { char buf[100]; snprintf(buf, sizeof(buf), "401: Invalid track number %02d\n", i_track); cderror(d, buf); return(-401); } return(d->disc_toc[i_track-i_first_track].dwStartSector); } } /*! Get first lsn of the first audio track. -ERROR_CODE is returned on error. */ lsn_t cdda_disc_firstsector(cdrom_drive_t *d) { int i; int first_track = cdio_get_first_track_num(d->p_cdio); if(!d->opened){ cderror(d,"400: Device not open\n"); return(-400); } /* look for an audio track */ for (i = first_track - 1; i < first_track - 1 + d->tracks; i++) if( cdda_track_audiop(d, i+1)==1 ) { if (i == first_track - 1) /* disc starts at lba 0 if first track is an audio track */ return 0; else return cdda_track_firstsector(d, i+1); } cderror(d,"403: No audio tracks on disc\n"); return(-403); } /*! Get last lsn of the track. The lsn is generally one less than the start of the next track. -ERROR_CODE is returned on error. */ lsn_t cdda_track_lastsector(cdrom_drive_t *d, track_t i_track) { if(!d->opened){ cderror(d,"400: Device not open\n"); return(-400); } else { const track_t i_first_track = cdio_get_first_track_num(d->p_cdio); const track_t i_last_track = cdio_get_last_track_num(d->p_cdio); if (i_track == 0) { if (d->disc_toc[0].dwStartSector == 0) { /* first track starts at lba 0 -> no pre-gap */ cderror(d,"402: No initial pregap\n"); return(-402); } else { return d->disc_toc[0].dwStartSector-1; } } else if (i_track < i_first_track || i_track > i_last_track) { char buf[100]; snprintf(buf, sizeof(buf), "401: Invalid track number %02d\n", i_track); cderror(d, buf); return(-401); } /* CD Extra have their first session ending at the last audio track */ if (d->cd_extra > 0 && i_track-i_first_track+2 <= d->tracks) { if (d->audio_last_sector >= d->disc_toc[i_track-i_first_track].dwStartSector && d->audio_last_sector < d->disc_toc[i_track-i_first_track+1].dwStartSector) { return d->audio_last_sector; } } /* Index safe because we always have the leadout at * disc_toc[tracks] */ return(d->disc_toc[i_track-i_first_track+1].dwStartSector-1); } } /*! Get last lsn of the last audio track. The last lssn generally one less than the start of the next track after the audio track. -ERROR_CODE is returned on error. */ lsn_t cdda_disc_lastsector(cdrom_drive_t *d) { if (!d->opened) { cderror(d,"400: Device not open\n"); return -400; } else { /* look for an audio track */ const track_t i_first_track = cdio_get_first_track_num(d->p_cdio); track_t i = cdio_get_last_track_num(d->p_cdio); for ( ; i >= i_first_track; i-- ) if ( cdda_track_audiop(d,i) ) return (cdda_track_lastsector(d,i)); } cderror(d,"403: No audio tracks on disc\n"); return -403; } /*! Return the number of tracks on the CD or CDIO_INVALID_TRACK (255) if error. */ track_t cdda_tracks(cdrom_drive_t *d) { if (!d->opened){ cderror(d,"400: Device not open\n"); return CDIO_INVALID_TRACK; } return(d->tracks); } /*! Return the track containing the given LSN. If the LSN is before the first track (in the pregap), 0 is returned. If there was an error or the LSN after the LEADOUT (beyond the end of the CD), then CDIO_INVALID_TRACK is returned. */ int cdio_cddap_sector_gettrack(cdrom_drive_t *d, lsn_t lsn) { if (!d->opened) { cderror(d,"400: Device not open\n"); return CDIO_INVALID_TRACK; } else { if (lsn < d->disc_toc[0].dwStartSector) return 0; /* We're in the pre-gap of first track */ return cdio_get_track(d->p_cdio, lsn); } } /*! Return the number of channels in track: 2 or 4; -2 if not implemented or -1 for error. Not meaningful if track is not an audio track. */ extern int cdio_cddap_track_channels(cdrom_drive_t *d, track_t i_track) { return(cdio_get_track_channels(d->p_cdio, i_track)); } /*! Return 1 is track is an audio track, 0 otherwise. */ extern int cdio_cddap_track_audiop(cdrom_drive_t *d, track_t i_track) { track_format_t track_format = cdio_get_track_format(d->p_cdio, i_track); return TRACK_FORMAT_AUDIO == track_format ? 1 : 0; } /*! Return 1 is track is an audio track, 0 otherwise. */ extern int cdio_cddap_track_copyp(cdrom_drive_t *d, track_t i_track) { track_flag_t track_flag = cdio_get_track_copy_permit(d->p_cdio, i_track); return CDIO_TRACK_FLAG_TRUE == track_flag ? 1 : 0; } /*! Return 1 is audio track has linear preemphasis set, 0 otherwise. Only makes sense for audio tracks. */ extern int cdio_cddap_track_preemp(cdrom_drive_t *d, track_t i_track) { track_flag_t track_flag = cdio_get_track_preemphasis(d->p_cdio, i_track); return CDIO_TRACK_FLAG_TRUE == track_flag ? 1 : 0; } libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/utils.c000066400000000000000000000114111461637345700237070ustar00rootroot00000000000000/* Copyright (C) 2004, 2008, 2010-2011, 2017 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #ifdef HAVE_SYS_TIME_H # include #endif #include "common_interface.h" #include "utils.h" void cderror(cdrom_drive_t *d,const char *s) { ssize_t bytes_ret __attribute__((unused)); if(s && d){ switch(d->errordest){ case CDDA_MESSAGE_PRINTIT: bytes_ret = write(STDERR_FILENO, s, strlen(s)); if (strlen(s) != bytes_ret) break; case CDDA_MESSAGE_LOGIT: d->errorbuf=catstring(d->errorbuf,s); break; case CDDA_MESSAGE_FORGETIT: default: break; } } } void cdmessage(cdrom_drive_t *d, const char *s) { ssize_t bytes_ret __attribute__((unused)); if(s && d){ switch(d->messagedest){ case CDDA_MESSAGE_PRINTIT: bytes_ret = write(STDERR_FILENO, s, strlen(s)); break; case CDDA_MESSAGE_LOGIT: d->messagebuf=catstring(d->messagebuf,s); break; case CDDA_MESSAGE_FORGETIT: default: break; } } } void idperror(int messagedest,char **messages,const char *f, const char *s) { char *buffer; int malloced=0; if(!f) buffer=(char *)s; else if(!s) buffer=(char *)f; else{ buffer=malloc(strlen(f)+strlen(s)+9); sprintf(buffer,f,s); malloced=1; } if(buffer){ ssize_t bytes_ret __attribute__((unused)); switch(messagedest){ case CDDA_MESSAGE_PRINTIT: bytes_ret = write(STDERR_FILENO,buffer,strlen(buffer)); if(errno){ bytes_ret = write(STDERR_FILENO,": ",2); bytes_ret = write(STDERR_FILENO,strerror(errno),strlen(strerror(errno))); bytes_ret = write(STDERR_FILENO,"\n",1); } break; case CDDA_MESSAGE_LOGIT: if(messages){ *messages=catstring(*messages,buffer); if(errno){ *messages=catstring(*messages,": "); *messages=catstring(*messages,strerror(errno)); *messages=catstring(*messages,"\n"); } } break; case CDDA_MESSAGE_FORGETIT: default: break; } } if(malloced)free(buffer); } void idmessage(int messagedest,char **messages,const char *f, const char *s) { char *buffer; int malloced=0; ssize_t bytes_ret __attribute__((unused)); if(!f) buffer=(char *)s; else if(!s) buffer=(char *)f; else{ const unsigned int i_buffer=strlen(f)+strlen(s)+2; buffer=malloc(i_buffer); sprintf(buffer,f,s); strncat(buffer,"\n",1); malloced=1; } if(buffer) { switch(messagedest){ case CDDA_MESSAGE_PRINTIT: bytes_ret = write(STDERR_FILENO,buffer,strlen(buffer)); if(!malloced) bytes_ret = write(STDERR_FILENO,"\n",1); break; case CDDA_MESSAGE_LOGIT: if(messages){ *messages=catstring(*messages,buffer); if(!malloced)*messages=catstring(*messages,"\n"); } break; case CDDA_MESSAGE_FORGETIT: default: break; } } if(malloced)free(buffer); } char * catstring(char *buff, const char *s) { if (s) { const unsigned int add_len = strlen(s) + 1; if(buff) { buff = realloc(buff, strlen(buff) + add_len); } else { buff=calloc(add_len, 1); } strncat(buff, s, add_len - 1); } return(buff); } int gettime(struct timespec *ts) { int ret = -1; if (!ts) return ret; #if defined(HAVE_CLOCK_GETTIME) /* Use clock_gettime if available, preferably using the monotonic clock. */ static clockid_t clock = (clockid_t)-1; if ((int)clock == -1) clock = (clock_gettime(CLOCK_MONOTONIC, ts) < 0 ? CLOCK_REALTIME : CLOCK_MONOTONIC); ret = clock_gettime(clock, ts); #elif defined(WIN32) /* clock() returns wall time (not CPU time) on Windows, so we can use it here. */ clock_t time = clock(); if ((int)time != -1) { ts->tv_sec = time/CLOCKS_PER_SEC; ts->tv_nsec = time%CLOCKS_PER_SEC*(1000000000/CLOCKS_PER_SEC); ret = 0; } #else /* In other cases use gettimeofday. */ struct timeval tv; ret = gettimeofday(&tv, NULL); if (ret == 0) { ts->tv_sec = tv.tv_sec; ts->tv_nsec = tv.tv_usec*1000; } #endif return ret; } libcdio-paranoia-release-10.2-2.0.2/lib/cdda_interface/utils.h000066400000000000000000000037201461637345700237200ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2008 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ #include #include #include /* I wonder how many alignment issues this is gonna trip in the future... it shouldn't trip any... I guess we'll find out :) */ static inline int bigendianp(void) { int test=1; char *hack=(char *)(&test); if(hack[0])return(0); return(1); } extern char *catstring(char *buff, const char *s); extern int gettime(struct timespec *); /*#if BYTE_ORDER == LITTLE_ENDIAN*/ #ifndef WORDS_BIGENDIAN static inline int16_t be16_to_cpu(int16_t x){ return(UINT16_SWAP_LE_BE_C(x)); } static inline int16_t le16_to_cpu(int16_t x){ return(x); } #else static inline int16_t be16_to_cpu(int16_t x){ return(x); } static inline int16_t le16_to_cpu(int16_t x){ return(UINT16_SWAP_LE_BE_C(x)); } #endif static inline int16_t cpu_to_be16(int16_t x){ return(be16_to_cpu(x)); } static inline int16_t cpu_to_le16(int16_t x){ return(le16_to_cpu(x)); } void cderror(cdrom_drive_t *d, const char *s); void cdmessage(cdrom_drive_t *d,const char *s); void idperror(int messagedest, char **messages, const char *f, const char *s); void idmessage(int messagedest, char **messages, const char *f, const char *s); libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/000077500000000000000000000000001461637345700212645ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/.gitignore000066400000000000000000000001421461637345700232510ustar00rootroot00000000000000/*.lo /*.o /*~ /.deps /.libs /Makefile /Makefile.in /libcdio_paranoia.la /libcdio_paranoia.la.ver libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/Makefile.am000066400000000000000000000161661461637345700233320ustar00rootroot00000000000000# Copyright (C) 2004, 2006, 2008, 2011, 2017 Rocky Bernstein # # 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 3 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, see . ######################################################## # Things to make the libcdio_paranoia library ######################################################## # # From libtool documentation amended with guidance from N. Boullis: # # 1. Start with version information of `0:0:0' for each libtool library. # # 2. It is probably not a good idea to update the version information # several times between public releases, but rather once per public # release. (This seems to be more an aesthetic consideration than # a hard technical one.) # # 3. If the library source code has changed at all since the last # update, then increment REVISION (`C:R:A' becomes `C:R+1:A'). # # 4. If any interfaces have been added, removed, or changed since the # last update, increment CURRENT, and set REVISION to 0. # # 5. If any interfaces have been added since the last public release, # then increment AGE. # # 6. If any interfaces have been removed or changed since the last # public release, then set AGE to 0. A changed interface means an # incompatibility with previous versions. EXTRA_DIST = libcdio_paranoia.sym libcdio_paranoia_la_CURRENT = 2 libcdio_paranoia_la_REVISION = 0 libcdio_paranoia_la_AGE = 0 noinst_HEADERS = gap.h isort.h overlap.h p_block.h libcdio_paranoia_sources = gap.c isort.c overlap.c overlap.h \ p_block.c paranoia.c lib_LTLIBRARIES = libcdio_paranoia.la libcdio_paranoia_la_SOURCES = $(libcdio_paranoia_sources) libcdio_paranoia_la_ldflags = -version-info $(libcdio_paranoia_la_CURRENT):$(libcdio_paranoia_la_REVISION):$(libcdio_paranoia_la_AGE) @LT_NO_UNDEFINED@ AM_CPPFLAGS = $(LIBCDIO_PARANOIA_CFLAGS) $(LIBCDIO_CFLAGS) FLAGS=@LIBCDIO_PARANOIA_CFLAGS@ @TYPESIZES@ @CFLAGS@ -I.. -I../.. OPT=$(FLAGS) DEBUG=$(FLAGS) ## SUFFIXES = .t ## TFILES = isort.t gap.t p_block.t paranoia.t ##test: $(TFILES) ##.c.t: ## $(CC) -g -DTEST $(DEBUG) -o $@ $< $(LIBS) ## $@ ##debug: ## $(MAKE) libcdio_paranoia.a CFLAGS="$(DEBUG)" LIBS = $(LIBCDIO_LIBS) $(LIBCDIO_CDDA_LIBS) ######################################################## # Things to version the symbols in the libraries ######################################################## # An explanation of the versioning problem from Nicolas Boullis and # the versioned symbol solution he uses below... # # Currently, libvcdinfo uses the cdio_open function from libcdio. # Let's imagine a program foobar that uses both the vcdinfo_open # function from libvcdinfo and the cdio_open function from libcdio. # Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME # libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both # libvcdinfo.so.0 and libcdio.so.0. Everything looks fine. # # Now, for some reason, you decide to change the cdio_open function. # That's your right, but you have to bump the CURRENT version and (if I # understand it correctly, athough this is not that clear in libtool's # documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is # sane since the interface changes incompatibly. # Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and # foobar still require libcdio.so.0. Everything is still fine. # Now, after some minor changes, the author of foobar recompiles foobar. # Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar # now segfaults... # What is happening? When you run foobar, if brings both libvcdinfo.so.0 # and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you # have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the # global namespace. Hence, you have to incompatible versions of the # cdio_open function in the name space. When foobar calls cdio_open, it # may choose the wrong function, and segfaults... # With versioned symbols, the cdio_open function from libcdio.so.0 may be # known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open # function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of # libcdio would still be brought in by the most recent foobar, but foobar # (and libvcdinfo) know which versioned function to use and then use the # good one. # This is some simple versioning where every symbol is versioned with # something that looks like the SONAME of the library. More complex (and # better) versioning is possible; it is for example what is used by glibc. # But good complex versioning is something that requires much more # work... # The below is a impliments symbol versioning. First of all, I # compute MAJOR as CURENT - AGE; that is what is used within libtool # (at least on GNU/Linux systems) for the number in the SONAME. The # nm command gives the list of symbols known in each of the object # files that will be part of the shared library. And the sed command # extracts from this list those symbols that will be shared. (This sed # command comes from libtool.) libcdio_paranoia_la_MAJOR = $(shell expr $(libcdio_paranoia_la_CURRENT) - $(libcdio_paranoia_la_AGE)) if VERSION_SCRIPT if BUILD_VERSIONED_LIBS if HAVE_LD_VERSION_SCRIPT libcdio_paranoia_la_LDFLAGS = $(libcdio_paranoia_la_ldflags) -Wl,--version-script=libcdio_paranoia.la.ver else !HAVE_LD_VERSION_SCRIPT libcdio_paranoia_la_LDFLAGS = $(libcdio_paranoia_la_ldflags) endif # HAVE_LD_VERSION_SCRIPT libcdio_paranoia_la_DEPENDENCIES = libcdio_paranoia.la.ver libcdio_paranoia.la.ver: $(libcdio_paranoia_la_OBJECTS) $(srcdir)/libcdio_paranoia.sym echo 'CDIO_PARANOIA_$(libcdio_paranoia_la_MAJOR) { ' > $@ objs=`for obj in $(libcdio_paranoia_la_OBJECTS); do sed -ne "s/^pic_object='\(.*\)'$$/\1/p" $$obj; done`; \ if test -n "$$objs" ; then \ ${NM} $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_paranoia.sym; then if test $$first = true; then echo " global:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \ ${NM} $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio_paranoia.sym; then :; else if test $$first = true; then echo " local:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \ fi echo '};' >> $@ else libcdio_paranoia_la_LDFLAGS = $(libcdio_paranoia_la_ldflags) endif !BUILD_VERSIONED_LIBS else !VERSION_SCRIPT libcdio_paranoia_la_LDFLAGS = $(libcdio_paranoia_la_ldflags) endif !VERSION_SCRIPT MOSTLYCLEANFILES = libcdio_paranoia.la.ver libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/gap.c000066400000000000000000000426051461637345700222060ustar00rootroot00000000000000/* Copyright (C) 2004, 2008, 2011 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ /*** * Gap analysis support code for paranoia * ***/ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #include "p_block.h" #include #include "gap.h" #include /**** Gap analysis code ***************************************************/ /* =========================================================================== * i_paranoia_overlap_r (internal) * * This function seeks backward through two vectors (starting at the given * offsets) to determine how many consecutive samples agree. It returns * the number of matching samples, which may be 0. * * Unlike its sibling, i_paranoia_overlap_f, this function doesn't need to * be given the size of the vectors (all vectors stop at offset 0). * * This function is used by i_analyze_rift_r() below to find where a * leading rift ends. */ long int i_paranoia_overlap_r(int16_t *buffA,int16_t *buffB, long offsetA, long offsetB) { long beginA=offsetA; long beginB=offsetB; /* Start at the given offsets and work our way backwards until we hit * the beginning of one of the vectors. */ for( ; beginA>=0 && beginB>=0; beginA--,beginB-- ) if (buffA[beginA] != buffB[beginB]) break; return(offsetA-beginA); } /* =========================================================================== * i_paranoia_overlap_f (internal) * * This function seeks forward through two vectors (starting at the given * offsets) to determine how many consecutive samples agree. It returns * the number of matching samples, which may be 0. * * Unlike its sibling, i_paranoia_overlap_r, this function needs to given * the size of the vectors. * * This function is used by i_analyze_rift_f() below to find where a * trailing rift ends. */ long int i_paranoia_overlap_f(int16_t *buffA,int16_t *buffB, long offsetA, long offsetB, long sizeA,long sizeB) { long endA=offsetA; long endB=offsetB; /* Start at the given offsets and work our way forward until we hit * the end of one of the vectors. */ for(;endA or <- */ /* =========================================================================== * i_analyze_rift_f (internal) * * This function examines a trailing rift to see how far forward the rift goes * and to determine what kind of rift it is. This function is called by * i_stage2_each() when a trailing rift is detected. (aoffset,boffset) are * the offsets into (A,B) of the first mismatching sample. * * This function returns: * matchA > 0 if there are (matchA) samples missing from A * matchA < 0 if there are (-matchA) duplicate samples (stuttering) in A * matchB > 0 if there are (matchB) samples missing from B * matchB < 0 if there are (-matchB) duplicate samples in B * matchC != 0 if there are (matchC) samples of garbage, after which * both A and B are in sync again */ void i_analyze_rift_f(int16_t *A,int16_t *B, long sizeA, long sizeB, long aoffset, long boffset, long *matchA,long *matchB,long *matchC) { long apast=sizeA-aoffset; long bpast=sizeB-boffset; long i; *matchA=0, *matchB=0, *matchC=0; /* Look forward to see where we regain agreement between vectors * A and B (of at least MIN_WORDS_RIFT samples). We look for one of * the following possible matches: * * edge * v * (1) (... A matching run)|(aoffset matches ...) * (... B matching run)| (rift) |(boffset+i matches ...) * * (2) (... A matching run)| (rift) |(aoffset+i matches ...) * (... B matching run)|(boffset matches ...) * * (3) (... A matching run)| (rift) |(aoffset+i matches ...) * (... B matching run)| (rift) |(boffset+i matches ...) * * Anything that doesn't match one of these three is too corrupt to * for us to recover from. E.g.: * * (... A matching run)| (rift) |(eventual match ...) * (... B matching run)| (big rift) |(eventual match ...) * * We won't find the eventual match, since we wouldn't be sure how * to fix the rift. */ for(i=1;;i++){ /* Search for whatever case we hit first, so as to end up with the * smallest rift. */ /* Don't search for (1) past the end of B */ if (i=MIN_WORDS_RIFT){ *matchA=i; break; } /* Don't search for (2) or (3) past the end of A */ if (i=MIN_WORDS_RIFT){ *matchB=i; break; } /* Don't search for (3) past the end of B */ if (i=MIN_WORDS_RIFT){ *matchC=i; break; } }else /* Stop searching when we've reached the end of both vectors. * In theory we could stop when there aren't MIN_WORDS_RIFT samples * left in both vectors, but this case should happen fairly rarely. */ if(i>=bpast)break; /* Try the search again with a larger tentative rift. */ } if(*matchA==0 && *matchB==0 && *matchC==0)return; if(*matchC)return; /* For case (1) or (2), we need to determine whether the rift contains * samples dropped by the other vector (that should be inserted), or * whether the rift contains a stutter (that should be dropped). To * distinguish, we check the contents of the rift against the good samples * just before the rift. If the contents match, then the rift contains * a stutter. * * A stutter in the second vector: * (...good samples... 1234)|(567 ...newly matched run...) * (...good samples... 1234)| (1234) | (567 ...newly matched run) * * Samples missing from the first vector: * (...good samples... 1234)|(901 ...newly matched run...) * (...good samples... 1234)| (5678) |(901 ...newly matched run...) * * Of course, there's no theoretical guarantee that a non-stutter * truly represents missing samples, but given that we're dealing with * verified fragments in stage 2, we can have some confidence that this * is the case. */ if(*matchA){ /* For case (1), we need to determine whether A dropped samples at the * rift or whether B stuttered. * * If the rift doesn't match the good samples in A (and hence in B), * it's not a stutter, and the rift should be inserted into A. */ if(i_stutter_or_gap(A,B,aoffset-*matchA,boffset,*matchA)) return; /* It is a stutter, so we need to signal that we need to remove * (matchA) bytes from B. */ *matchB = -*matchA; *matchA=0; return; }else{ /* Case (2) is the inverse of case (1) above. */ if(i_stutter_or_gap(B,A,boffset-*matchB,aoffset,*matchB)) return; *matchA = -*matchB; *matchB=0; return; } } /* riftv must be first even val of rift moving back */ /* =========================================================================== * i_analyze_rift_r (internal) * * This function examines a leading rift to see how far back the rift goes * and to determine what kind of rift it is. This function is called by * i_stage2_each() when a leading rift is detected. (aoffset,boffset) are * the offsets into (A,B) of the first mismatching sample. * * This function returns: * matchA > 0 if there are (matchA) samples missing from A * matchA < 0 if there are (-matchA) duplicate samples (stuttering) in A * matchB > 0 if there are (matchB) samples missing from B * matchB < 0 if there are (-matchB) duplicate samples in B * matchC != 0 if there are (matchC) samples of garbage, after which * both A and B are in sync again */ void i_analyze_rift_r(int16_t *A,int16_t *B, long sizeA, long sizeB, long aoffset, long boffset, long *matchA,long *matchB,long *matchC) { long apast=aoffset+1; long bpast=boffset+1; long i; *matchA=0, *matchB=0, *matchC=0; /* Look backward to see where we regain agreement between vectors * A and B (of at least MIN_WORDS_RIFT samples). We look for one of * the following possible matches: * * edge * v * (1) (... aoffset matches)|(A matching run ...) * (... boffset-i matches)| (rift) |(B matching run ...) * * (2) (... aoffset-i matches)| (rift) |(A matching run ...) * (... boffset matches)|(B matching run ...) * * (3) (... aoffset-i matches)| (rift) |(A matching run ...) * (... boffset-i matches)| (rift) |(B matching run ...) * * Anything that doesn't match one of these three is too corrupt to * for us to recover from. E.g.: * * (... eventual match)| (rift) |(A matching run ...) * (... eventual match) | (big rift) |(B matching run ...) * * We won't find the eventual match, since we wouldn't be sure how * to fix the rift. */ for(i=1;;i++){ /* Search for whatever case we hit first, so as to end up with the * smallest rift. */ /* Don't search for (1) past the beginning of B */ if (i=MIN_WORDS_RIFT){ *matchA=i; break; } /* Don't search for (2) or (3) past the beginning of A */ if (i=MIN_WORDS_RIFT){ *matchB=i; break; } /* Don't search for (3) past the beginning of B */ if (i=MIN_WORDS_RIFT){ *matchC=i; break; } }else /* Stop searching when we've reached the end of both vectors. * In theory we could stop when there aren't MIN_WORDS_RIFT samples * left in both vectors, but this case should happen fairly rarely. */ if(i>=bpast)break; /* Try the search again with a larger tentative rift. */ } if(*matchA==0 && *matchB==0 && *matchC==0)return; if(*matchC)return; /* For case (1) or (2), we need to determine whether the rift contains * samples dropped by the other vector (that should be inserted), or * whether the rift contains a stutter (that should be dropped). To * distinguish, we check the contents of the rift against the good samples * just after the rift. If the contents match, then the rift contains * a stutter. * * A stutter in the second vector: * (...newly matched run... 234)|(5678 ...good samples...) * (...newly matched run... 234)| (5678) |(5678 ...good samples...) * * Samples missing from the first vector: * (...newly matched run... 890)|(5678 ...good samples...) * (...newly matched run... 890)| (1234) |(5678 ...good samples...) * * Of course, there's no theoretical guarantee that a non-stutter * truly represents missing samples, but given that we're dealing with * verified fragments in stage 2, we can have some confidence that this * is the case. */ if(*matchA){ /* For case (1), we need to determine whether A dropped samples at the * rift or whether B stuttered. * * If the rift doesn't match the good samples in A (and hence in B), * it's not a stutter, and the rift should be inserted into A. * * ???BUG??? It's possible for aoffset+1+*matchA to be > sizeA, in * which case the comparison in i_stutter_or_gap() will extend beyond * the bounds of A. Thankfully, this isn't writing data and thus * trampling memory, but it's still a memory access error that should * be fixed. * * This bug is not fixed yet. */ if(i_stutter_or_gap(A,B,aoffset+1,boffset-*matchA+1,*matchA)) return; /* It is a stutter, so we need to signal that we need to remove * (matchA) bytes from B. */ *matchB = -*matchA; *matchA=0; return; }else{ /* Case (2) is the inverse of case (1) above. */ if(i_stutter_or_gap(B,A,boffset+1,aoffset-*matchB+1,*matchB)) return; *matchA = -*matchB; *matchB=0; return; } } /* =========================================================================== * analyze_rift_silence_f (internal) * * This function examines the fragment and root from the rift onward to * see if they have a rift's worth of silence (or if they end with silence). * It sets (*matchA) to -1 if A's rift is silence, (*matchB) to -1 if B's * rift is silence, and sets them to 0 otherwise. * * Note that, unlike every other function in cdparanoia, this function * considers any repeated value to be silence (which, in effect, it is). * All other functions only consider repeated zeroes to be silence. * * ??? Is this function name just a misnomer, as it's really looking for * repeated garbage? * * This function is called by i_stage2_each() if it runs into a trailing rift * that i_analyze_rift_f couldn't diagnose. This checks for another variant: * where one vector has silence and the other doesn't. We then assume * that the silence (and anything following it) is garbage. * * Note that while this function checks both A and B for silence, the caller * assumes that only one or the other has silence. */ void analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB, long aoffset, long boffset, long *matchA, long *matchB) { *matchA=-1; *matchB=-1; /* Search for MIN_WORDS_RIFT samples, or to the end of the vector, * whichever comes first. */ sizeA=min(sizeA,aoffset+MIN_WORDS_RIFT); sizeB=min(sizeB,boffset+MIN_WORDS_RIFT); aoffset++; boffset++; /* Check whether A has only "silence" within the search range. Note * that "silence" here is a single, repeated value (zero or not). */ while(aoffset Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ #ifndef _GAP_H_ #define _GAP_H_ extern long i_paranoia_overlap_r(int16_t *buffA,int16_t *buffB, long offsetA, long offsetB); extern long i_paranoia_overlap_f(int16_t *buffA,int16_t *buffB, long offsetA, long offsetB, long sizeA,long sizeB); extern int i_stutter_or_gap(int16_t *A, int16_t *B,long offA, long offB, long gap); extern void i_analyze_rift_f(int16_t *A,int16_t *B, long sizeA, long sizeB, long aoffset, long boffset, long *matchA,long *matchB,long *matchC); extern void i_analyze_rift_r(int16_t *A,int16_t *B, long sizeA, long sizeB, long aoffset, long boffset, long *matchA,long *matchB,long *matchC); extern void analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB, long aoffset, long boffset, long *matchA, long *matchB); #endif /*_GAP_H*/ libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/isort.c000066400000000000000000000213461461637345700225760ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2008, 2011 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ /* sorted vector abstraction for paranoia */ /* Old isort got a bit complex. This re-constrains complexity to give a go at speed through a more alpha-6-like mechanism. */ /* "Sort" is a bit of a misnomer in this implementation. It's actually * basically a hash table of sample values (with a linked-list collision * resolution), which lets you quickly determine where in a vector a * particular sample value occurs. * * Collisions aren't due to hash collisions, as the table has one bucket * for each possible sample value. Instead, the "collisions" represent * multiple occurrences of a given value. */ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "p_block.h" #include "isort.h" /* =========================================================================== * sort_alloc() * * Allocates and initializes a new, empty sort_info object, which can be * used to index up to (size) samples from a vector. */ sort_info_t * sort_alloc(long size) { sort_info_t *ret=calloc(1, sizeof(sort_info_t)); ret->vector=NULL; ret->sortbegin=-1; ret->size=-1; ret->maxsize=size; ret->head=calloc(65536,sizeof(sort_link_t *)); ret->bucketusage=calloc(1, 65536*sizeof(long)); ret->revindex=calloc(size,sizeof(sort_link_t)); ret->lastbucket=0; return(ret); } /* =========================================================================== * sort_unsortall() (internal) * * This function resets the index for further use with a different vector * or range, without the overhead of an unnecessary free/alloc. */ void sort_unsortall(sort_info_t *i) { /* If there were few enough different samples encountered (and hence few * enough buckets used), we can just zero out those buckets. If there * were many (2000 is picked somewhat arbitrarily), it's faster simply to * zero out all buckets with a memset() rather than walking the data * structure and zeroing them out one by one. */ if (i->lastbucket>2000) { /* a guess */ memset(i->head,0,65536*sizeof(sort_link_t *)); } else { long b; for (b=0; blastbucket; b++) i->head[i->bucketusage[b]]=NULL; } i->lastbucket=0; i->sortbegin=-1; /* Curiously, this function preserves the vector association created * by sort_setup(), but it is used only internally by sort_setup, so * preserving this association is unnecessary. */ } /* =========================================================================== * sort_free() * * Releases all memory consumed by a sort_info object. */ void sort_free(sort_info_t *i) { free(i->revindex); free(i->head); free(i->bucketusage); free(i); } /* =========================================================================== * sort_sort() (internal) * * This function builds the index to allow for fast searching for sample * values within a portion (sortlo - sorthi) of the object's associated * vector. It is called internally and only when needed. */ static void sort_sort(sort_info_t *i,long sortlo,long sorthi) { long j; /* We walk backward through the range to index because we insert new * samples at the head of each bucket's list. At the end, they'll be * sorted from first to last occurrence. */ for (j=sorthi-1; j>=sortlo; j--) { /* i->vector[j] = the signed 16-bit sample to index. * hv = pointer to the head of the sorted list of occurences * of this sample * l = the node to associate with this sample * * We add 32768 to convert the signed 16-bit integer to an unsigned * range from 0 to 65535. * * Note that l is located within i->revindex at a position * corresponding to the sample's position in the vector. This allows * ipos() to determine the sample position from a returned sort_link. */ sort_link_t **hv = i->head+i->vector[j]+32768; sort_link_t *l = i->revindex+j; /* If this is the first time we've encountered this sample, add its * bucket to the list of buckets used. This list is used only for * resetting the index quickly. */ if(*hv==NULL){ i->bucketusage[i->lastbucket] = i->vector[j]+32768; i->lastbucket++; } /* Point the new node at the old head, then assign the new node as * the new head. */ l->next=*hv; *hv=l; } /* Mark the index as initialized. */ i->sortbegin=0; } /* =========================================================================== * sort_setup() * * This function initializes a previously allocated sort_info_t. The * sort_info_t is associated with a vector of samples of length * (size), whose position begins at (*abspos) within the CD's stream * of samples. Only the range of samples between (sortlo, sorthi) * will eventually be indexed for fast searching. (sortlo, sorthi) * are absolute sample positions. * * ???: Why is abspos a pointer? Why not just store a copy? * * Note: size *must* be <= the size given to the preceding sort_alloc(), * but no error checking is done here. */ void sort_setup(sort_info_t *i, int16_t *vector, long int *abspos, long int size, long int sortlo, long int sorthi) { /* Reset the index if it has already been built. */ if (i->sortbegin!=-1) sort_unsortall(i); i->vector=vector; i->size=size; i->abspos=abspos; /* Convert the absolute (sortlo, sorthi) to offsets within the vector. * Note that the index will not be built until sort_getmatch() is called. * Here we're simply hanging on to the range to index until then. */ i->lo = min(size, max(sortlo - *abspos, 0)); i->hi = max(0, min(sorthi - *abspos, size)); } /* =========================================================================== * sort_getmatch() * * This function returns a sort_link_t pointer which refers to the * first sample equal to (value) in the vector. It only searches for * hits within (overlap) samples of (post), where (post) is an offset * within the vector. The caller can determine the position of the * matched sample using ipos(sort_info *, sort_link *). * * This function returns NULL if no matches were found. */ sort_link_t * sort_getmatch(sort_info_t *i, long post, long overlap, int value) { sort_link_t *ret; /* If the vector hasn't been indexed yet, index it now. */ if (i->sortbegin==-1) sort_sort(i,i->lo,i->hi); /* Now we reuse lo and hi */ /* We'll only return samples within (overlap) samples of (post). * Clamp the boundaries to search to the boundaries of the array, * convert the signed sample to an unsigned offset, and store the * state so that future calls to sort_nextmatch do the right thing. * * Reusing lo and hi this way is awful. */ post=max(0,min(i->size,post)); i->val=value+32768; i->lo=max(0,post-overlap); /* absolute position */ i->hi=min(i->size,post+overlap); /* absolute position */ /* Walk through the linked list of samples with this value, until * we find the first one within the bounds specified. If there * aren't any, return NULL. */ ret=i->head[i->val]; while (ret) { /* ipos() calculates the offset (in terms of the original vector) * of this hit. */ if (ipos(i,ret)lo) { ret=ret->next; } else { if (ipos(i,ret)>=i->hi) ret=NULL; break; } } /*i->head[i->val]=ret;*/ return(ret); } /* =========================================================================== * sort_nextmatch() * * This function returns a sort_link_t pointer which refers to the next sample * matching the criteria previously passed to sort_getmatch(). See * sort_getmatch() for details. * * This function returns NULL if no further matches were found. */ sort_link_t * sort_nextmatch(sort_info_t *i, sort_link_t *prev) { sort_link_t *ret=prev->next; /* If there aren't any more hits, or we've passed the boundary requested * of sort_getmatch(), we're done. */ if (!ret || ipos(i,ret)>=i->hi) return(NULL); return(ret); } libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/isort.h000066400000000000000000000130061461637345700225750ustar00rootroot00000000000000/* $Id: isort.h,v 1.6 2008/04/17 17:39:48 karl Exp $ Copyright (C) 2004, 2005, 2008 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ #ifndef _ISORT_H_ #define _ISORT_H_ typedef struct sort_link{ struct sort_link *next; } sort_link_t; typedef struct sort_info { int16_t *vector; /* vector (storage doesn't belong to us) */ long *abspos; /* pointer for side effects */ long size; /* vector size */ long maxsize; /* maximum vector size */ long sortbegin; /* range of contiguous sorted area */ long lo,hi; /* current post, overlap range */ int val; /* ...and val */ /* sort structs */ sort_link_t **head; /* sort buckets (65536) */ long *bucketusage; /* of used buckets (65536) */ long lastbucket; sort_link_t *revindex; } sort_info_t; /*! ======================================================================== * sort_alloc() * * Allocates and initializes a new, empty sort_info object, which can * be used to index up to (size) samples from a vector. */ extern sort_info_t *sort_alloc(long int size); /*! ======================================================================== * sort_unsortall() (internal) * * This function resets the index for further use with a different * vector or range, without the overhead of an unnecessary free/alloc. */ extern void sort_unsortall(sort_info_t *i); /*! ======================================================================== * sort_setup() * * This function initializes a previously allocated sort_info_t. The * sort_info_t is associated with a vector of samples of length * (size), whose position begins at (*abspos) within the CD's stream * of samples. Only the range of samples between (sortlo, sorthi) * will eventually be indexed for fast searching. (sortlo, sorthi) * are absolute sample positions. * * ???: Why is abspos a pointer? Why not just store a copy? * * Note: size *must* be <= the size given to the preceding sort_alloc(), * but no error checking is done here. */ extern void sort_setup(sort_info_t *i, int16_t *vector, long int *abspos, long int size, long int sortlo, long int sorthi); /* ========================================================================= * sort_free() * * Releases all memory consumed by a sort_info object. */ extern void sort_free(sort_info_t *i); /*! ======================================================================== * sort_getmatch() * * This function returns a sort_link_t pointer which refers to the * first sample equal to (value) in the vector. It only searches for * hits within (overlap) samples of (post), where (post) is an offset * within the vector. The caller can determine the position of the * matched sample using ipos(sort_info *, sort_link *). * * This function returns NULL if no matches were found. */ extern sort_link_t *sort_getmatch(sort_info_t *i, long post, long overlap, int value); /*! ======================================================================== * sort_nextmatch() * * This function returns a sort_link_t pointer which refers to the * next sample matching the criteria previously passed to * sort_getmatch(). See sort_getmatch() for details. * * This function returns NULL if no further matches were found. */ extern sort_link_t *sort_nextmatch(sort_info_t *i, sort_link_t *prev); /* =========================================================================== * is() * * This macro returns the size of the vector indexed by the given sort_info_t. */ #define is(i) (i->size) /* =========================================================================== * ib() * * This macro returns the absolute position of the first sample in the vector * indexed by the given sort_info_t. */ #define ib(i) (*i->abspos) /* =========================================================================== * ie() * * This macro returns the absolute position of the sample after the last * sample in the vector indexed by the given sort_info_t. */ #define ie(i) (i->size+*i->abspos) /* =========================================================================== * iv() * * This macro returns the vector indexed by the given sort_info_t. */ #define iv(i) (i->vector) /* =========================================================================== * ipos() * * This macro returns the relative position (offset) within the indexed vector * at which the given match was found. * * It uses a little-known and frightening aspect of C pointer arithmetic: * subtracting a pointer is not an arithmetic subtraction, but rather the * additive inverse. In other words, since * q = p + n returns a pointer to the nth object in p, * q - p = p + n - p, and * q - p = n, not the difference of the two addresses. */ #define ipos(i,l) (l-i->revindex) #endif /* _ISORT_H_ */ libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/libcdio_paranoia.sym000066400000000000000000000003671461637345700253030ustar00rootroot00000000000000cdio_paranoia_init cdio_paranoia_free cdio_paranoia_modeset cdio_paranoia_seek cdio_paranoia_read cdio_paranoia_read_limited cdio_paranoia_overlapset cdio_paranoia_set_range cdio_paranoia_version cdio_paranoia_cachemodel_size paranoia_cb_mode2str libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/overlap.c000066400000000000000000000161341461637345700231050ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2008, 2011, 2017 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ /*** * * Statistic code and cache management for overlap settings * ***/ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #ifdef HAVE_STDLIB_H #include #endif #include #ifdef HAVE_STRING_H #include #endif #include #include "p_block.h" #include "overlap.h" #include "isort.h" /**** Internal cache management *****************************************/ void paranoia_resetcache(cdrom_paranoia_t *p) { c_block_t *c=c_first(p); v_fragment_t *v; while(c){ free_c_block(c); c=c_first(p); } v=v_first(p); while(v){ free_v_fragment(v); v=v_first(p); } } void paranoia_resetall(cdrom_paranoia_t *p) { p->root.returnedlimit=0; p->dyndrift=0; p->root.lastsector=0; if(p->root.vector){ i_cblock_destructor(p->root.vector); p->root.vector=NULL; } paranoia_resetcache(p); } void i_paranoia_trim(cdrom_paranoia_t *p, long int beginword, long int endword) { root_block *root=&(p->root); if(root->vector!=NULL){ long target=beginword-MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; long rbegin=cb(root->vector); long rend=ce(root->vector); if(rbegin>beginword) goto rootfree; if(rbegin+MAX_SECTOR_OVERLAP*CD_FRAMEWORDSrend) goto rootfree; { long int offset=target-rbegin; c_removef(root->vector,offset); } } { c_block_t *c=c_first(p); while(c){ c_block_t *next=c_next(c); if(ce(c)vector); root->vector=NULL; root->returnedlimit=-1; root->lastsector=0; } /**** Statistical and heuristic[al? :-] management ************************/ /* =========================================================================== * offset_adjust_settings (internal) * * This function is called by offset_add_value() every time 10 samples have * been accumulated. This function updates the internal statistics for * paranoia (dynoverlap, dyndrift) that compensate for jitter and drift. * * (dynoverlap) influences how far stage 1 and stage 2 search for matching * runs. In low-jitter conditions, it will be very small (or even 0), * narrowing our search. In high-jitter conditions, it will be much larger, * widening our search at the cost of speed. * * ???: To be studied further. */ void offset_adjust_settings(cdrom_paranoia_t *p, void(*callback)(long int, paranoia_cb_mode_t)) { if(p->stage2.offpoints>=10){ /* drift: look at the average offset value. If it's over one sector, frob it. We just want a little hysteresis [sp?]*/ long av=(p->stage2.offpoints?p->stage2.offaccum/p->stage2.offpoints:0); if(labs(av)>p->dynoverlap/4){ av=(av/MIN_SECTOR_EPSILON)*MIN_SECTOR_EPSILON; if(callback)(*callback)(ce(p->root.vector),PARANOIA_CB_DRIFT); p->dyndrift+=av; /* Adjust all the values in the cache otherwise we get a (potentially unstable) feedback loop */ { c_block_t *c=c_first(p); v_fragment_t *v=v_first(p); while(v && v->one){ /* safeguard beginning bounds case with a hammer */ if(fb(v)one)one=NULL; }else{ fb(v)-=av; } v=v_next(v); } while(c){ long adj=min(av,cb(c)); c_set(c,cb(c)-adj); c=c_next(c); } } p->stage2.offaccum=0; p->stage2.offmin=0; p->stage2.offmax=0; p->stage2.offpoints=0; p->stage2.newpoints=0; p->stage2.offdiff=0; } } if(p->stage1.offpoints>=10){ /* dynoverlap: we arbitrarily set it to 4x the running difference value, unless min/max are more */ p->dynoverlap=(p->stage1.offpoints?p->stage1.offdiff/ p->stage1.offpoints*3:CD_FRAMEWORDS); if(p->dynoverlap<-p->stage1.offmin*1.5) p->dynoverlap=-p->stage1.offmin*1.5; if(p->dynoverlapstage1.offmax*1.5) p->dynoverlap=p->stage1.offmax*1.5; if(p->dynoverlapdynoverlap=MIN_SECTOR_EPSILON; if(p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS) p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; if(callback)(*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP); if(p->stage1.offpoints>600){ /* bit of a bug; this routine is called too often due to the overlap mesh alg we use in stage 1 */ p->stage1.offpoints/=1.2; p->stage1.offaccum/=1.2; p->stage1.offdiff/=1.2; } p->stage1.offmin=0; p->stage1.offmax=0; p->stage1.newpoints=0; } } /* =========================================================================== * offset_add_value (internal) * * This function adds the given jitter detected (value) to the statistics * for the given stage (o). It is called whenever jitter has been identified * by stage 1 or 2. After every 10 samples, we update the overall jitter- * compensation settings (e.g. dynoverlap). This allows us to narrow our * search for matching runs (in both stages) in low-jitter conditions * and also widen our search appropriately when there is jitter. * * * "???BUG???: * Note that there is a bug in the way that this is called by try_sort_sync(). * Silence looks like zero jitter, and dynoverlap may be incorrectly reduced * when there's lots of silence but also jitter." * * Strictly speaking, this is only sort-of true. The silence will * incorrectly somewhat reduce dynoverlap. However, it will increase * again once past the silence (even if reduced to zero, it will be * increased by the block read loop if we're not getting matches). * In reality, silence usually passes rapidly. Anyway, long streaks * of silence benefit performance-wise from having dynoverlap decrease * momentarily. There is no correctness bug. --Monty * */ void offset_add_value(cdrom_paranoia_t *p,offsets *o,long value, void(*callback)(long int, paranoia_cb_mode_t)) { if(o->offpoints!=-1){ /* Track the average magnitude of jitter (in either direction) */ o->offdiff += labs(value); o->offpoints++; o->newpoints++; /* Track the net value of the jitter (to track drift) */ o->offaccum+=value; /* Track the largest jitter we've encountered in each direction */ if(valueoffmin)o->offmin=value; if(value>o->offmax)o->offmax=value; /* After 10 samples, update dynoverlap, etc. */ if(o->newpoints>=10)offset_adjust_settings(p,callback); } } libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/overlap.h000066400000000000000000000023731461637345700231120ustar00rootroot00000000000000/* Copyright (C) 2004, 2008 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ #ifndef _OVERLAP_H_ #define _OVERLAP_H_ extern void offset_add_value(cdrom_paranoia_t *p,offsets *o,long value, void(*callback)(long int, paranoia_cb_mode_t)); extern void offset_clear_settings(offsets *o); extern void offset_adjust_settings(cdrom_paranoia_t *p, void(*callback)(long, paranoia_cb_mode_t)); extern void i_paranoia_trim(cdrom_paranoia_t *p,long beginword,long endword); extern void paranoia_resetall(cdrom_paranoia_t *p); extern void paranoia_resetcache(cdrom_paranoia_t *p); #endif /*_OVERLAP_H_*/ libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/p_block.c000066400000000000000000000215451461637345700230500ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2007, 2008 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) 1998 Monty xiphmont@mit.edu */ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #ifdef HAVE_STDLIB_H #include #endif #include #ifdef HAVE_STRING_H #include #endif #include #include "p_block.h" #include #include linked_list_t *new_list(void *(*newp)(void),void (*freep)(void *)) { linked_list_t *ret=calloc(1,sizeof(linked_list_t)); ret->new_poly=newp; ret->free_poly=freep; return(ret); } linked_element *add_elem(linked_list_t *l,void *elem) { linked_element *ret=calloc(1,sizeof(linked_element)); ret->stamp=l->current++; ret->ptr=elem; ret->list=l; if(l->head) l->head->prev=ret; else l->tail=ret; ret->next=l->head; ret->prev=NULL; l->head=ret; l->active++; return(ret); } linked_element * new_elem(linked_list_t *p_list) { void *p_new=p_list->new_poly(); return(add_elem(p_list,p_new)); } void free_elem(linked_element *e,int free_ptr) { linked_list_t *l=e->list; if(free_ptr)l->free_poly(e->ptr); if(e==l->head) l->head=e->next; if(e==l->tail) l->tail=e->prev; if(e->prev) e->prev->next=e->next; if(e->next) e->next->prev=e->prev; l->active--; free(e); } void free_list(linked_list_t *list,int free_ptr) { while(list->head) free_elem(list->head,free_ptr); free(list); } void *get_elem(linked_element *e) { return(e->ptr); } linked_list_t *copy_list(linked_list_t *list) { linked_list_t *new=new_list(list->new_poly,list->free_poly); linked_element *i=list->tail; while(i){ add_elem(new,i->ptr); i=i->prev; } return(new); } /**** C_block stuff ******************************************************/ static c_block_t * i_cblock_constructor(cdrom_paranoia_t *p) { c_block_t *ret=calloc(1,sizeof(c_block_t)); return(ret); } void i_cblock_destructor(c_block_t *c) { if(c){ if(c->vector)free(c->vector); if(c->flags)free(c->flags); c->e=NULL; free(c); } } c_block_t * new_c_block(cdrom_paranoia_t *p) { linked_element *e=new_elem(p->cache); c_block_t *c=e->ptr; c->e=e; c->p=p; return(c); } void free_c_block(c_block_t *c) { /* also rid ourselves of v_fragments that reference this block */ v_fragment_t *v=v_first(c->p); while(v){ v_fragment_t *next=v_next(v); if(v->one==c)free_v_fragment(v); v=next; } free_elem(c->e,1); } static v_fragment_t * i_vfragment_constructor(void) { v_fragment_t *ret=calloc(1,sizeof(v_fragment_t)); return(ret); } static void i_v_fragment_destructor(v_fragment_t *v) { free(v); } v_fragment_t * new_v_fragment(cdrom_paranoia_t *p, c_block_t *one, long int begin, long int end, int last) { linked_element *e=new_elem(p->fragments); v_fragment_t *b=e->ptr; b->e=e; b->p=p; b->one=one; b->begin=begin; b->vector=one->vector+begin-one->begin; b->size=end-begin; b->lastsector=last; #if TRACE_PARANOIA fprintf(stderr, "- Verified [%ld-%ld] (0x%04X...0x%04X)%s\n", begin, end, b->vector[0]&0xFFFF, b->vector[b->size-1]&0xFFFF, last ? " *" : ""); #endif return(b); } void free_v_fragment(v_fragment_t *v) { free_elem(v->e,1); } c_block_t * c_first(cdrom_paranoia_t *p) { if(p->cache->head) return(p->cache->head->ptr); return(NULL); } c_block_t * c_last(cdrom_paranoia_t *p) { if(p->cache->tail) return(p->cache->tail->ptr); return(NULL); } c_block_t * c_next(c_block_t *c) { if(c->e->next) return(c->e->next->ptr); return(NULL); } c_block_t * c_prev(c_block_t *c) { if(c->e->prev) return(c->e->prev->ptr); return(NULL); } v_fragment_t * v_first(cdrom_paranoia_t *p) { if(p->fragments->head){ return(p->fragments->head->ptr); } return(NULL); } v_fragment_t * v_last(cdrom_paranoia_t *p) { if(p->fragments->tail) return(p->fragments->tail->ptr); return(NULL); } v_fragment_t * v_next(v_fragment_t *v) { if(v->e->next) return(v->e->next->ptr); return(NULL); } v_fragment_t * v_prev(v_fragment_t *v) { if(v->e->prev) return(v->e->prev->ptr); return(NULL); } void recover_cache(cdrom_paranoia_t *p) { linked_list_t *l=p->cache; /* Are we at/over our allowed cache size? */ while(l->active>p->cache_limit) /* cull from the tail of the list */ free_c_block(c_last(p)); } int16_t * v_buffer(v_fragment_t *v) { if(!v->one)return(NULL); if(!cv(v->one))return(NULL); return(v->vector); } /* alloc a c_block not on a cache list */ c_block_t * c_alloc(int16_t *vector, long begin, long size) { c_block_t *c=calloc(1,sizeof(c_block_t)); c->vector=vector; c->begin=begin; c->size=size; return(c); } void c_set(c_block_t *v,long begin){ v->begin=begin; } /* pos here is vector position from zero */ void c_insert(c_block_t *v,long pos,int16_t *b,long size) { int vs=cs(v); if(pos<0 || pos>vs)return; if(v->vector) { v->vector = realloc(v->vector,sizeof(int16_t)*(size+vs)); } else { v->vector = calloc(1, sizeof(int16_t)*size); } if(posvector+pos+size,v->vector+pos, (vs-pos)*sizeof(int16_t)); memcpy(v->vector+pos,b,size*sizeof(int16_t)); v->size+=size; } void c_remove(c_block_t *v, long cutpos, long cutsize) { int vs=cs(v); if(cutpos<0 || cutpos>vs)return; if(cutpos+cutsize>vs)cutsize=vs-cutpos; if(cutsize<0)cutsize=vs-cutpos; if(cutsize<1)return; memmove(v->vector+cutpos,v->vector+cutpos+cutsize, (vs-cutpos-cutsize)*sizeof(int16_t)); v->size-=cutsize; } void c_overwrite(c_block_t *v,long pos,int16_t *b,long size) { int vs=cs(v); if(pos<0)return; if(pos+size>vs)size=vs-pos; memcpy(v->vector+pos,b,size*sizeof(int16_t)); } void c_append(c_block_t *v, int16_t *vector, long size) { int vs=cs(v); /* update the vector */ if(v->vector) v->vector=realloc(v->vector,sizeof(int16_t)*(size+vs)); else { v->vector=calloc(1, sizeof(int16_t)*size); } memcpy(v->vector+vs,vector,sizeof(int16_t)*size); v->size+=size; } void c_removef(c_block_t *v, long cut) { c_remove(v,0,cut); v->begin+=cut; } /**** Initialization *************************************************/ /*! Get the beginning and ending sector bounds given cursor position. There are a couple of subtle differences between this and the cdda_firsttrack_sector and cdda_lasttrack_sector. If the cursor is an a sector later than cdda_firsttrack_sector, that sectur will be used. As for the difference between cdda_lasttrack_sector, if the CD is mixed and there is a data track after the cursor but before the last audio track, the end of the audio sector before that is used. */ void i_paranoia_firstlast(cdrom_paranoia_t *p) { track_t i, j; cdrom_drive_t *d=p->d; const track_t i_first_track = cdio_get_first_track_num(d->p_cdio); const track_t i_last_track = cdio_get_last_track_num(d->p_cdio); p->current_lastsector = p->current_firstsector = -1; i = cdda_sector_gettrack(d, p->cursor); if ( CDIO_INVALID_TRACK != i ) { if ( 0 == i ) i = cdio_get_first_track_num(d->p_cdio); j = i; /* In the below loops, We assume the cursor already is on an audio sector. Not sure if this is correct if p->cursor is in the pregap before the first track. */ for ( ; i < i_last_track; i++) if( !cdda_track_audiop(d,i) ) { p->current_lastsector=cdda_track_lastsector(d,i-1); break; } i = j; for ( ; i >= i_first_track; i-- ) if( !cdda_track_audiop(d,i) ) { p->current_firstsector = cdda_track_firstsector(d,i+1); break; } } if (p->current_lastsector == -1) p->current_lastsector = cdda_disc_lastsector(d); if(p->current_firstsector == -1) p->current_firstsector = cdda_disc_firstsector(d); } cdrom_paranoia_t * paranoia_init(cdrom_drive_t *d) { cdrom_paranoia_t *p=calloc(1,sizeof(cdrom_paranoia_t)); p->cache=new_list((void *)&i_cblock_constructor, (void *)&i_cblock_destructor); p->fragments=new_list((void *)&i_vfragment_constructor, (void *)&i_v_fragment_destructor); p->cdcache_begin= 9999999; p->cdcache_end= 9999999; p->cdcache_size=CACHEMODEL_SECTORS; p->sortcache=sort_alloc(p->cdcache_size*CD_FRAMEWORDS); p->d=d; p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; p->cache_limit=JIGGLE_MODULO; p->enable=(paranoia_cb_mode_t)PARANOIA_MODE_FULL; p->cursor=cdda_disc_firstsector(d); /* One last one... in case data and audio tracks are mixed... */ i_paranoia_firstlast(p); return(p); } void paranoia_set_range(cdrom_paranoia_t *p, long start, long end) { p->cursor = start; p->current_firstsector = start; p->current_lastsector = end; } /* sectors < 0 indicates a query. Returns the number of sectors before the call */ int paranoia_cachemodel_size(cdrom_paranoia_t *p,int sectors){ int ret = p->cdcache_size; if(sectors>=0) p->cdcache_size=sectors; return ret; } libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/p_block.h000066400000000000000000000133101461637345700230440ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2008 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) by Monty (xiphmont@mit.edu) 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 3 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, see . */ #ifndef _P_BLOCK_H_ #define _P_BLOCK_H_ #include #include #define MIN_WORDS_OVERLAP 64 /* 16 bit words */ #define MIN_WORDS_SEARCH 64 /* 16 bit words */ #define MIN_WORDS_RIFT 16 /* 16 bit words */ #define MAX_SECTOR_OVERLAP 32 /* sectors */ #define MIN_SECTOR_EPSILON 128 /* words */ #define MIN_SECTOR_BACKUP 16 /* sectors */ #define JIGGLE_MODULO 15 /* sectors */ #define MIN_SILENCE_BOUNDARY 1024 /* 16 bit words */ #define CACHEMODEL_SECTORS 1200 #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)<(y)?(y):(x)) #include "isort.h" typedef struct { /* linked list */ struct linked_element *head; struct linked_element *tail; void *(*new_poly)(); void (*free_poly)(void *poly); long current; long active; } linked_list_t; typedef struct linked_element{ void *ptr; struct linked_element *prev; struct linked_element *next; linked_list_t *list; int stamp; } linked_element; extern linked_list_t *new_list(void *(*new_fn)(void),void (*free)(void *)); extern linked_element *new_elem(linked_list_t *list); extern linked_element *add_elem(linked_list_t *list,void *elem); extern void free_list(linked_list_t *list,int free_ptr); /* unlink or free */ extern void free_elem(linked_element *e,int free_ptr); /* unlink or free */ extern void *get_elem(linked_element *e); /* This is a shallow copy; it doesn't copy contained structures */ extern linked_list_t *copy_list(linked_list_t *p_list); typedef struct c_block { /* The buffer */ int16_t *vector; long begin; long size; /* auxiliary support structures */ unsigned char *flags; /* 1 known boundaries in read data 2 known blanked data 4 matched sample 8 reserved 16 reserved 32 reserved 64 reserved 128 reserved */ /* end of session cases */ long lastsector; cdrom_paranoia_t *p; struct linked_element *e; } c_block_t; extern void free_c_block(c_block_t *c); extern void i_cblock_destructor(c_block_t *c); extern c_block_t *new_c_block(cdrom_paranoia_t *p); typedef struct v_fragment_s { c_block_t *one; long begin; long size; int16_t *vector; /* end of session cases */ long lastsector; /* linked list */ cdrom_paranoia_t *p; struct linked_element *e; } v_fragment_t; extern void free_v_fragment(v_fragment_t *c); extern v_fragment_t *new_v_fragment(cdrom_paranoia_t *p, c_block_t *one, long int begin, long int end, int lastsector); extern int16_t *v_buffer(v_fragment_t *v); extern c_block_t *c_first(cdrom_paranoia_t *p); extern c_block_t *c_last(cdrom_paranoia_t *p); extern c_block_t *c_next(c_block_t *c); extern c_block_t *c_prev(c_block_t *c); extern v_fragment_t *v_first(cdrom_paranoia_t *p); extern v_fragment_t *v_last(cdrom_paranoia_t *p); extern v_fragment_t *v_next(v_fragment_t *v); extern v_fragment_t *v_prev(v_fragment_t *v); typedef struct root_block{ long returnedlimit; long lastsector; cdrom_paranoia_t *p; c_block_t *vector; /* doesn't use any sorting */ int silenceflag; long silencebegin; } root_block; typedef struct offsets{ long offpoints; long newpoints; long offaccum; long offdiff; long offmin; long offmax; } offsets; struct cdrom_paranoia_s { cdrom_drive_t *d; root_block root; /* verified/reconstructed cached data */ linked_list_t *cache; /* our data as read from the cdrom */ long int cache_limit; linked_list_t *fragments; /* fragments of blocks that have been 'verified' */ sort_info_t *sortcache; /* cache tracking */ int cdcache_size; int cdcache_begin; int cdcache_end; int jitter; paranoia_cb_mode_t enable; long int cursor; long int current_lastsector; long int current_firstsector; /* statistics for drift/overlap */ struct offsets stage1; struct offsets stage2; long dynoverlap; long dyndrift; /* statistics for verification */ }; extern c_block_t *c_alloc(int16_t *vector,long begin,long size); extern void c_set(c_block_t *v,long begin); extern void c_insert(c_block_t *v,long pos,int16_t *b,long size); extern void c_remove(c_block_t *v,long cutpos,long cutsize); extern void c_overwrite(c_block_t *v,long pos,int16_t *b,long size); extern void c_append(c_block_t *v, int16_t *vector, long size); extern void c_removef(c_block_t *v, long cut); #define ce(v) (v->begin+v->size) #define cb(v) (v->begin) #define cs(v) (v->size) /* pos here is vector position from zero */ extern void recover_cache(cdrom_paranoia_t *p); extern void i_paranoia_firstlast(cdrom_paranoia_t *p); #define cv(c) (c->vector) #define fe(f) (f->begin+f->size) #define fb(f) (f->begin) #define fs(f) (f->size) #define fv(f) (v_buffer(f)) #ifndef DO_NOT_WANT_PARANOIA_COMPATIBILITY /** For compatibility with good ol' paranoia */ #define linked_list linked_list_t #endif /*DO_NOT_WANT_PARANOIA_COMPATIBILITY*/ #define CDP_COMPILE #endif /*_P_BLOCK_H_*/ libcdio-paranoia-release-10.2-2.0.2/lib/paranoia/paranoia.c000066400000000000000000003216011461637345700232250ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2006, 2008, 2011, 2017 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) 1998 Monty xiphmont@mit.edu 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 3 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, see . */ /*** * Toplevel file for the paranoia abstraction over the cdda lib * ***/ /* immediate todo:: */ /* Allow disabling of root fixups? */ /* Dupe bytes are creeping into cases that require greater overlap than a single fragment can provide. We need to check against a larger area* (+/-32 sectors of root?) to better eliminate dupes. Of course this leads to other problems... Is it actually a practically solvable problem? */ /* Bimodal overlap distributions break us. */ /* scratch detection/tolerance not implemented yet */ /*************************************************************** Da new shtick: verification now a two-step assymetric process. A single 'verified/reconstructed' data segment cache, and then the multiple fragment cache verify a newly read block against previous blocks; do it only this once. We maintain a list of 'verified sections' from these matches. We then glom these verified areas into a new data buffer. Defragmentation fixups are allowed here alone. We also now track where read boundaries actually happened; do not verify across matching boundaries. **************************************************************/ /*************************************************************** Silence. "It's BAAAAAAaaack." audio is now treated as great continents of values floating on a mantle of molten silence. Silence is not handled by basic verification at all; we simply anchor sections of nonzero audio to a position and fill in everything else as silence. We also note the audio that interfaces with silence; an edge must be 'wet'. **************************************************************/ /* =========================================================================== * Let's translate the above vivid metaphor into something a mere mortal * can understand: * * Non-silent audio is "solid." Silent audio is "wet" and fluid. The reason * to treat silence as fluid is that if there's a long enough span of * silence, we can't reliably detect jitter or dropped samples within that * span (since all silence looks alike). Non-silent audio, on the other * hand, is distinctive and can be reliably reassembled. * * So we treat long spans of silence specially. We only consider an edge * of a non-silent region ("continent" or "island") to be "wet" if it borders * a long span of silence. Short spans of silence are merely damp and can * be reliably placed within a continent. * * We position ("anchor") the non-silent regions somewhat arbitrarily (since * they may be jittered and we have no way to verify their exact position), * and fill the intervening space with silence. * * See i_silence_match() for the gory details. * =========================================================================== */ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #ifdef HAVE_STDLIB_H #include #endif #include #include #include #ifdef HAVE_STRING_H #include #endif #include #include #include "../cdda_interface/smallft.h" #include #include "p_block.h" #include #include "overlap.h" #include "gap.h" #include "isort.h" #include #define MIN_SEEK_MS 6 const char *paranoia_cb_mode2str[] = { "read", "verify", "fixup edge", "fixup atom", "scratch", "repair", "skip", "drift", "backoff", "overlap", "fixup dropped", "fixup duplicated", "read error" }; /** The below variables are trickery to force the above enum symbol values to be recorded in debug symbol tables. They are used to allow one to refer to the enumeration value names in the typedefs above in a debugger and debugger expressions */ paranoia_mode_t debug_paranoia_mode; paranoia_cb_mode_t debug_paranoia_cb_mode; static inline long re(root_block *root) { if (!root)return(-1); if (!root->vector)return(-1); return(ce(root->vector)); } static inline long rb(root_block *root) { if (!root)return(-1); if (!root->vector)return(-1); return(cb(root->vector)); } static inline long rs(root_block *root) { if (!root)return(-1); if (!root->vector)return(-1); return(cs(root->vector)); } static inline int16_t * rv(root_block *root){ if (!root)return(NULL); if (!root->vector)return(NULL); return(cv(root->vector)); } #define rc(r) (r->vector) /** Flags indicating the status of a read samples. Imagine the below enumeration values are \#defines to be used in a bitmask rather than distinct values of an enum. The variable part of the declaration is trickery to force the enum symbol values to be recorded in debug symbol tables. They are used to allow one refer to the enumeration value names in a debugger and in debugger expressions. */ enum { FLAGS_EDGE =0x1, /**< first/last N words of frame */ FLAGS_UNREAD =0x2, /**< unread, hence missing and unmatchable */ FLAGS_VERIFIED=0x4 /**< block read and verified */ } paranoia_read_flags; /**** matching and analysis code *****************************************/ /* =========================================================================== * i_paranoia_overlap() (internal) * * This function is called when buffA[offsetA] == buffB[offsetB]. This * function searches backward and forward to see how many consecutive * samples also match. * * This function is called by do_const_sync() when we're not doing any * verification. Its more complicated sibling is i_paranoia_overlap2. * * This function returns the number of consecutive matching samples. * If (ret_begin) or (ret_end) are not NULL, it fills them with the * offsets of the first and last matching samples in A. */ static inline long i_paranoia_overlap(int16_t *buffA,int16_t *buffB, long offsetA, long offsetB, long sizeA,long sizeB, long *ret_begin, long *ret_end) { long beginA=offsetA,endA=offsetA; long beginB=offsetB,endB=offsetB; /* Scan backward to extend the matching run in that direction. */ for(; beginA>=0 && beginB>=0; beginA--,beginB--) if (buffA[beginA] != buffB[beginB]) break; beginA++; beginB++; /* Scan forward to extend the matching run in that direction. */ for(; endA=0 && beginB>=0; beginA--,beginB--) { if (buffA[beginA] != buffB[beginB]) break; /* don't allow matching across matching sector boundaries. The liklihood of the drive skipping identically in two different reads with the same sector read boundary is actually relatively very high compared to the liklihood of it skipping when one read is continuous across the boundary and other was discontinuous */ /* Stop if both samples were at the edges of a low-level read. * ???: What implications does this have? * ???: Why do we include the first sample for which this is true? */ if ((flagsA[beginA]&flagsB[beginB]&FLAGS_EDGE)) { beginA--; beginB--; break; } /* don't allow matching through known missing data */ if ((flagsA[beginA]&FLAGS_UNREAD) || (flagsB[beginB]&FLAGS_UNREAD)) break; } beginA++; beginB++; /* Scan forward to extend the matching run in that direction. */ for (; endAflags; long ret=0; /* If we're doing any verification whatsoever, we have flags in stage * 1, and will take them into account. Otherwise (e.g. in stage 2), * we just do the simple equality test for samples on both sides of * the initial match. */ if (flagB==NULL) ret=i_paranoia_overlap(cv(A), iv(B), posA, posB, cs(A), is(B), begin, end); else if ((flagB[posB]&FLAGS_UNREAD)==0) ret=i_paranoia_overlap2(cv(A), iv(B), flagA, flagB, posA, posB, cs(A), is(B), begin, end); /* Small matching runs could just be coincidental. We only consider this * a real match if it's long enough. */ if (ret > MIN_WORDS_SEARCH) { *offset=+(posA+cb(A))-(posB+ib(B)); /* Note that try_sort_sync()'s swaps A & B when it calls this function, * so while we adjust begin & end to be relative to A here, that means * it's relative to B in try_sort_sync(). */ *begin+=cb(A); *end+=cb(A); return(ret); } return(0); } /* =========================================================================== * try_sort_sync() (internal) * * Starting from the sample in B with the absolute position (post), look * for a matching run in A. This search will look in A for a first * matching sample within (p->dynoverlap) samples around (post). If it * finds one, it will then determine how many consecutive samples match * both A and B from that point, looking backwards and forwards. If * this search produces a matching run longer than MIN_WORDS_SEARCH, we * consider it a match. * * When used by stage 1, the "post" is planted with respect to the old * c_block being compare to the new c_block. In stage 2, the "post" is * planted with respect to the verified root. * * This function returns 1 if a match is found and 0 if not. When a match * is found, (begin) and (end) are set to the boundaries of the run, and * (offset) is set to the difference in position of the run in A and B. * (begin) and (end) are the absolute positions of the samples in * B. (offset) transforms A to B's frame of reference. I.e., an offset of * 2 would mean that A's absolute 3 is equivalent to B's 5. */ /* post is w.r.t. B. in stage one, we post from old. In stage 2 we post from root. Begin, end, offset count from B's frame of reference */ static inline long int try_sort_sync(cdrom_paranoia_t *p, sort_info_t *A, unsigned char *Aflags, c_block_t *B, long int post, long int *begin, long int *end, long *offset, void (*callback)(long int, paranoia_cb_mode_t)) { long int dynoverlap=p->dynoverlap; sort_link_t *ptr=NULL; unsigned char *Bflags=B->flags; /* block flag matches FLAGS_UNREAD (and hence unmatchable) */ if (Bflags==NULL || (Bflags[post-cb(B)]&FLAGS_UNREAD)==0){ /* always try absolute offset zero first! */ { long zeropos=post-ib(A); if (zeropos>=0 && zeroposstage1),*offset,callback); return(1); } } } } } else return(0); /* If the samples with the same absolute position didn't match, it's * either a bad sample, or the two c_blocks are jittered with respect * to each other. Now we search through A for samples that do have * the same value as B's post. The search looks from first to last * occurrence witin (dynoverlap) samples of (post). */ ptr=sort_getmatch(A,post-ib(A),dynoverlap,cv(B)[post-cb(B)]); while (ptr){ /* We've found a matching sample, so try to grow the matching run in * both directions. If we find a long enough run (longer than * MIN_WORDS_SEARCH), we've found a match. */ if (do_const_sync(B,A,Aflags, post-cb(B),ipos(A,ptr), begin,end,offset)){ /* ???BUG??? Jitter cannot be accurately detected when there are * large regions of silence. Silence all looks alike, so if * there is actually jitter but lots of silence, jitter (offset) * will be incorrectly identified as 0. When the incorrect zero * jitter is passed to offset_add_value, it eventually reduces * dynoverlap so much that it's impossible for stage 2 to merge * jittered fragments into the root (it doesn't search far enough). * * A potential solution (tested, but not committed) is to check * for silence in do_const_sync and simply not call * offset_add_value if the match is all silence. * * This bug is not fixed yet. */ /* ???: To be studied. */ offset_add_value(p,&(p->stage1),*offset,callback); return(1); } /* The matching sample was just a fluke -- there weren't enough adjacent * samples that matched to consider a matching run. So now we check * for the next occurrence of that value in A. */ ptr=sort_nextmatch(A,ptr); } /* We didn't find any matches. */ *begin=-1; *end=-1; *offset=-1; return(0); } /* =========================================================================== * STAGE 1 MATCHING * * ???: Insert high-level explanation here. * =========================================================================== */ /* Top level of the first stage matcher */ /* We match each analysis point of new to the preexisting blocks recursively. We can also optionally maintain a list of fragments of the preexisting block that didn't match anything, and match them back afterward. */ #define OVERLAP_ADJ (MIN_WORDS_OVERLAP/2-1) /* =========================================================================== * stage1_matched() (internal) * * This function is called whenever stage 1 verification finds two identical * runs of samples from different reads. The runs must be more than * MIN_WORDS_SEARCH samples long. They may be jittered (i.e. their absolute * positions on the CD may not match due to inaccurate seeking) with respect * to each other, but they have been verified to have no dropped samples * within them. * * This function provides feedback via the callback mechanism and marks the * runs as verified. The details of the marking are somehwat subtle and * are described near the relevant code. * * Subsequent portions of the stage 1 code will build a verified fragment * from this run. The verified fragment will eventually be merged * into the verified root (and its absolute position determined) in * stage 2. */ static inline void stage1_matched(c_block_t *old, c_block_t *new, long matchbegin,long matchend, long matchoffset, void (*callback)(long int, paranoia_cb_mode_t)) { long i; long oldadjbegin=matchbegin-cb(old); long oldadjend=matchend-cb(old); long newadjbegin=matchbegin-matchoffset-cb(new); long newadjend=matchend-matchoffset-cb(new); /* Provide feedback via the callback about the samples we've just * verified. * * "???: How can matchbegin ever be < cb(old)?" * Sorry, old bulletproofing habit. I often use <= to mean "not >" * --Monty * * "???: Why do edge samples get logged only when there's jitter * between the matched runs (matchoffset != 0)?" * FIXUP_EDGE is actually logging a jitter event, not a rift-- * a rift is FIXUP_ATOM --Monty */ if ( matchbegin-matchoffset<=cb(new) || matchbegin<=cb(old) || (new->flags[newadjbegin]&FLAGS_EDGE) || (old->flags[oldadjbegin]&FLAGS_EDGE) ) { if ( matchoffset && callback ) (*callback)(matchbegin,PARANOIA_CB_FIXUP_EDGE); } else if (callback) (*callback)(matchbegin,PARANOIA_CB_FIXUP_ATOM); if ( matchend-matchoffset>=ce(new) || (new->flags[newadjend]&FLAGS_EDGE) || matchend>=ce(old) || (old->flags[oldadjend]&FLAGS_EDGE) ) { if ( matchoffset && callback ) (*callback)(matchend,PARANOIA_CB_FIXUP_EDGE); } else if (callback) (*callback)(matchend, PARANOIA_CB_FIXUP_ATOM); #if TRACE_PARANOIA & 1 fprintf(stderr, "- Matched [%ld-%ld] against [%ld-%ld]\n", newadjbegin+cb(new), newadjend+cb(new), oldadjbegin+cb(old), oldadjend+cb(old)); #endif /* Mark verified samples as "verified," but trim the verified region * by OVERLAP_ADJ samples on each side. There are several significant * implications of this trimming: * * 1) Why we trim at all: We have to trim to distinguish between two * adjacent verified runs and one long verified run. We encounter this * situation when samples have been dropped: * * matched portion of read 1 ....)(.... matched portion of read 1 * read 2 adjacent run .....)(..... read 2 adjacent run * || * dropped samples in read 2 * * So at this point, the fact that we have two adjacent runs means * that we have not yet verified that the two runs really are adjacent. * (In fact, just the opposite: there are two runs because they were * matched by separate runs, indicating that some samples didn't match * across the length of read 2.) * * If we verify that they are actually adjacent (e.g. if the two runs * are simply a result of matching runs from different reads, not from * dropped samples), we will indeed mark them as one long merged run. * * 2) Why we trim by this amount: We want to ensure that when we * verify the relationship between these two runs, we do so with * an overlapping fragment at least OVERLAP samples long. Following * from the above example: * * (..... matched portion of read 3 .....) * read 2 adjacent run .....)(..... read 2 adjacent run * * Assuming there were no dropped samples between the adjacent runs, * the matching portion of read 3 will need to be at least OVERLAP * samples long to mark the two runs as one long verified run. * If there were dropped samples, read 3 wouldn't match across the * two runs, proving our caution worthwhile. * * 3) Why we partially discard the work we've done: We don't. * When subsequently creating verified fragments from this run, * we compensate for this trimming. Thus the verified fragment will * contain the full length of verified samples. Only the c_blocks * will reflect this trimming. * * ???: The comment below indicates that the sort cache is updated in * some way, but this does not appear to be the case. */ /* Mark the verification flags. Don't mark the first or last OVERLAP/2 elements so that overlapping fragments have to overlap by OVERLAP to actually merge. We also remove elements from the sort such that later sorts do not have to sift through already matched data */ newadjbegin+=OVERLAP_ADJ; newadjend-=OVERLAP_ADJ; for(i=newadjbegin;iflags[i]|=FLAGS_VERIFIED; /* mark verified */ oldadjbegin+=OVERLAP_ADJ; oldadjend-=OVERLAP_ADJ; for(i=oldadjbegin;iflags[i]|=FLAGS_VERIFIED; /* mark verified */ } /* =========================================================================== * i_iterate_stage1 (internal) * * This function is called by i_stage1() to compare newly read samples with * previously read samples, searching for contiguous runs of identical * samples. Matching runs indicate that at least two reads of the CD * returned identical data, with no dropped samples in that run. * The runs may be jittered (i.e. their absolute positions on the CD may * not be accurate due to inaccurate seeking) at this point. Their * positions will be determined in stage 2. * * This function compares the new c_block (which has been indexed in * p->sortcache) to a previous c_block. It is called for each previous * c_block. It searches for runs of identical samples longer than * MIN_WORDS_SEARCH. Samples in matched runs are marked as verified. * * Subsequent stage 1 code builds verified fragments from the runs of * verified samples. These fragments are merged into the verified root * in stage 2. * * This function returns the number of distinct runs verified in the new * c_block when compared against this old c_block. */ static long int i_iterate_stage1(cdrom_paranoia_t *p, c_block_t *old, c_block_t *new, void(*callback)(long int, paranoia_cb_mode_t)) { long matchbegin = -1; long matchend = -1; long matchoffset; /* "???: Why do we limit our search only to the samples with overlapping * absolute positions? It could be because it eliminates some further * bounds checking." * Short answer is yes --Monty * * "Why do we "no longer try to spread the ... search" as mentioned * below?" * The search is normally much faster without the spread, * even in heavy jitter. Dynoverlap tends to be a bigger deal in * stage 2. --Monty */ /* we no longer try to spread the stage one search area by dynoverlap */ long searchend = min(ce(old), ce(new)); long searchbegin = max(cb(old), cb(new)); long searchsize = searchend-searchbegin; sort_info_t *i = p->sortcache; long ret = 0; long int j; long tried = 0; long matched = 0; if (searchsize<=0) return(0); /* match return values are in terms of the new vector, not old */ /* "???: Why 23?" Odd, prime number --Monty */ for (j=searchbegin; jflags[j-cb(new)] & (FLAGS_VERIFIED|FLAGS_UNREAD)) == 0) { tried++; /* Starting from the sample in the old c_block with the absolute * position j, look for a matching run in the new c_block. This * search will look a certain distance around j, and if successful * will extend the matching run as far backward and forward as * it can. * * The search will only return 1 if it finds a matching run long * enough to be deemed significant. */ if (try_sort_sync(p, i, new->flags, old, j, &matchbegin, &matchend, &matchoffset, callback) == 1) { matched+=matchend-matchbegin; /* purely cosmetic: if we're matching zeros, don't use the callback because they will appear to be all skewed */ { long j = matchbegin-cb(old); long end = matchend-cb(old); for (; j j) j = matchend-1; } } } /* end for */ #ifdef NOISY fprintf(stderr,"iterate_stage1: search area=%ld[%ld-%ld] tried=%ld matched=%ld spans=%ld\n", searchsize,searchbegin,searchend,tried,matched,ret); #endif return(ret); } /* =========================================================================== * i_stage1() (internal) * * Compare newly read samples against previously read samples, searching * for contiguous runs of identical samples. Matching runs indicate that * at least two reads of the CD returned identical data, with no dropped * samples in that run. The runs may be jittered (i.e. their absolute * positions on the CD may not be accurate due to inaccurate seeking) at * this point. Their positions will be determined in stage 2. * * This function compares a new c_block against all other c_blocks in memory, * searching for sufficiently long runs of identical samples. Since each * c_block represents a separate call to read_c_block, this ensures that * multiple reads have returned identical data. (Additionally, read_c_block * varies the reads so that multiple reads are unlikely to produce identical * errors, so any matches between reads are considered verified. See * i_read_c_block for more details.) * * Each time we find such a run (longer than MIN_WORDS_SEARCH), we mark * the samples as "verified" in both c_blocks. Runs of verified samples in * the new c_block are promoted into verified fragments, which will later * be merged into the verified root in stage 2. * * In reality, not all the verified samples are marked as "verified." * See stage1_matched() for an explanation. * * This function returns the number of verified fragments created by the * stage 1 matching. */ static long int i_stage1(cdrom_paranoia_t *p, c_block_t *p_new, void (*callback)(long int, paranoia_cb_mode_t)) { long size=cs(p_new); c_block_t *ptr=c_last(p); int ret=0; long int begin=0; long int end; #if TRACE_PARANOIA & 1 long int block_count = 0; fprintf(stderr, "Verifying block %ld:[%ld-%ld] against previously read blocks...\n", p->cache->active, cb(p_new), ce(p_new)); #endif /* We're going to be comparing the new c_block against the other * c_blocks in memory. Initialize the "sort cache" index to allow * for fast searching through the new c_block. (The index will * actually be built the first time we search.) */ if (ptr) sort_setup( p->sortcache, cv(p_new), &cb(p_new), cs(p_new), cb(p_new), ce(p_new) ); /* Iterate from oldest to newest c_block, comparing the new c_block * to each, looking for a sufficiently long run of identical samples * (longer than MIN_WORDS_SEARCH), which will be marked as "verified" * in both c_blocks. * * Since the new c_block is already in the list (at the head), don't * compare it against itself. */ while ( ptr && ptr != p_new ) { #if TRACE_PARANOIA & 1 block_count++; fprintf(stderr, "- Verifying against block %ld:[%ld-%ld] dynoverlap=%ld\n", block_count, cb(ptr), ce(ptr), p->dynoverlap); #endif if (callback) (*callback)(cb(p_new), PARANOIA_CB_VERIFY); i_iterate_stage1(p,ptr,p_new,callback); ptr=c_prev(ptr); } /* parse the verified areas of p_new into v_fragments */ /* Find each run of contiguous verified samples in the new c_block * and create a verified fragment from each run. */ begin=0; while (beginflags[begin]&FLAGS_VERIFIED) break; for (end=begin; end < size; end++) if ((p_new->flags[end]&FLAGS_VERIFIED)==0) break; if (begin>=size) break; ret++; /* We create a new verified fragment from the contiguous run * of verified samples. * * We expand the "verified" range by OVERLAP_ADJ on each side * to compensate for trimming done to the verified range by * stage1_matched(). The samples were actually verified, and * hence belong in the verified fragment. See stage1_matched() * for an explanation of the trimming. */ new_v_fragment(p,p_new,cb(p_new)+max(0,begin-OVERLAP_ADJ), cb(p_new)+min(size,end+OVERLAP_ADJ), (end+OVERLAP_ADJ>=size && p_new->lastsector)); begin=end; } /* Return the number of distinct verified fragments we found with * stage 1 matching. */ return(ret); } /* =========================================================================== * STAGE 2 MATCHING * * ???: Insert high-level explanation here. * =========================================================================== */ typedef struct sync_result { long offset; long begin; long end; } sync_result_t; /* Reconcile v_fragments to root buffer. Free if matched, fragment/fixup root if necessary. Do *not* match using zero posts */ /* =========================================================================== * i_iterate_stage2 (internal) * * This function searches for a sufficiently long run of identical samples * between the passed verified fragment and the verified root. The search * is similar to that performed by i_iterate_stage1. Of course, what we do * as a result of a match is different. * * Our search is slightly different in that we refuse to match silence to * silence. All silence looks alike, and it would result in too many false * positives here, so we handle silence separately. * * Also, because we're trying to determine whether this fragment as a whole * overlaps with the root at all, we narrow our search (since it should match * immediately or not at all). This is in contrast to stage 1, where we * search the entire vector looking for all possible matches. * * This function returns 0 if no match was found (including failure to find * one due to silence), or 1 if we found a match. * * When a match is found, the sync_result_t is set to the boundaries of * matching run (begin/end, in terms of the root) and how far out of sync * the fragment is from the canonical root (offset). Note that this offset * is opposite in sign from the notion of offset used by try_sort_sync() * and stage 1 generally. */ static long int i_iterate_stage2(cdrom_paranoia_t *p, v_fragment_t *v, sync_result_t *r, void(*callback)(long int, paranoia_cb_mode_t)) { root_block *root=&(p->root); long matchbegin=-1,matchend=-1,offset; long fbv,fev; #if TRACE_PARANOIA & 2 fprintf(stderr, "- Comparing fragment [%ld-%ld] to root [%ld-%ld]...", fb(v), fe(v), rb(root), re(root)); #endif #ifdef NOISY fprintf(stderr,"Stage 2 search: fbv=%ld fev=%ld\n",fb(v),fe(v)); #endif /* Quickly check whether there could possibly be any overlap between * the verified fragment and the root. Our search will allow up to * (p->dynoverlap) jitter between the two, so we expand the fragment * search area by p->dynoverlap on both sides and see if that expanded * area overlaps with the root. * * We could just as easily expand root's boundaries by p->dynoverlap * instead and achieve the same result. */ if (min(fe(v) + p->dynoverlap,re(root)) - max(fb(v) - p->dynoverlap,rb(root)) <= 0) return(0); if (callback) (*callback)(fb(v), PARANOIA_CB_VERIFY); /* We're going to try to match the fragment to the root while allowing * for p->dynoverlap jitter, so we'll actually be looking at samples * in the fragment whose position claims to be up to p->dynoverlap * outside the boundaries of the root. But, of course, don't extend * past the edges of the fragment. */ fbv = max(fb(v), rb(root)-p->dynoverlap); /* Skip past leading zeroes in the fragment, and bail if there's nothing * but silence. We handle silence later separately. */ while (fbvdynoverlap outside the boundaries * of the root, but don't extend past the edges of the fragment. * * However, we also limit the search to no more than 256 samples. * Unlike stage 1, we're not trying to find all possible matches within * two runs -- rather, we're trying to see if the fragment as a whole * overlaps with the root. If we can't find a match within 256 samples, * there's probably no match to be found (because this fragment doesn't * overlap with the root). * * "??? Is this why? Why 256?" 256 is simply a 'large enough number'. --Monty */ fev = min(min(fbv+256, re(root)+p->dynoverlap), fe(v)); { /* Because we'll allow for up to (p->dynoverlap) jitter between the * fragment and the root, we expand the search area (fbv to fev) by * p->dynoverlap on both sides. But, because we're iterating through * root, we need to constrain the search area not to extend beyond * the root's boundaries. */ long searchend=min(fev+p->dynoverlap,re(root)); long searchbegin=max(fbv-p->dynoverlap,rb(root)); sort_info_t *i=p->sortcache; long j; long min_matchbegin = -1; long min_matchend = -1; long min_offset = LONG_MAX; /* Initialize the "sort cache" index to allow for fast searching * through the verified fragment between (fbv,fev). (The index will * actually be built the first time we search.) */ sort_setup(i, fv(v), &fb(v), fs(v), fbv, fev); /* ??? Why 23? */ for(j=searchbegin; j= 0) { /* We will never find a smaller offset by continuing */ break; } } } } /* If we found a matching run, we return the results of our match. * * Note that we flip the sign of (offset) because try_sort_sync() * returns it in terms of the fragment (i.e. what we add * to the fragment's position to yield the corresponding position * in the root), but here we consider the root to be canonical, * and so our returned "offset" reflects how the fragment is offset * from the root. * * E.g.: If the fragment's sample 10 corresponds to root's 12, * try_sort_sync() would return 2. But since root is canonical, * we say that the fragment is off by -2. */ if(min_offset != LONG_MAX) { r->begin=min_matchbegin; r->end=min_matchend; r->offset=-min_offset; if(min_offset)if(callback)(*callback)(r->begin,PARANOIA_CB_FIXUP_EDGE); return(1); } } return(0); } /* =========================================================================== * i_silence_test() (internal) * * If the entire root is silent, or there's enough trailing silence * to be significant (MIN_SILENCE_BOUNDARY samples), mark the beginning * of the silence and "light" the silence flag. This flag will remain lit * until i_silence_match() appends some non-silent samples to the root. * * We do this because if there's a long enough span of silence, we can't * reliably detect jitter or dropped samples within that span. See * i_silence_match() for details on how we recover from this situation. */ static void i_silence_test(root_block *root) { int16_t *vec=rv(root); long end=re(root)-rb(root)-1; long j; /* Look backward from the end of the root to find the first non-silent * sample. */ for(j=end-1;j>=0;j--) if (vec[j]!=0) break; /* If the entire root is silent, or there's enough trailing silence * to be significant, mark the beginning of the silence and "light" * the silence flag. */ if (j<0 || end-j>MIN_SILENCE_BOUNDARY) { /* ???BUG???: * * The original code appears to have a bug, as it points to the * last non-zero sample, and silence matching appears to treat * silencebegin as the first silent sample. As a result, in certain * situations, the last non-zero sample can get clobbered. * * This bug has been tentatively fixed, since it allows more regression * tests to pass. The original code was: * if (j<0)j=0; */ j++; root->silenceflag=1; root->silencebegin=rb(root)+j; /* ???: To be studied. */ if (root->silencebeginreturnedlimit) root->silencebegin=root->returnedlimit; } } /* =========================================================================== * i_silence_match() (internal) * * This function is merges verified fragments into the verified root in cases * where there is a problematic amount of silence (MIN_SILENCE_BOUNDARY * samples) at the end of the root. * * We need a special approach because if there's a long enough span of * silence, we can't reliably detect jitter or dropped samples within that * span (since all silence looks alike). * * Only fragments that begin with MIN_SILENCE_BOUNDARY samples are eligible * to be merged in this case. Fragments that are too far beyond the edge * of the root to possibly overlap are also disregarded. * * Our first approach is to assume that such fragments have no jitter (since * we can't establish otherwise) and merge them. However, if it's clear * that there must be jitter (i.e. because non-silent samples overlap when * we assume no jitter), we assume the fragment has the minimum possible * jitter and then merge it. * * This function extends silence fairly aggressively, so it must be called * with fragments in ascending order (beginning position) in case there are * small non-silent regions within the silence. */ static long int i_silence_match(root_block *root, v_fragment_t *v, void(*callback)(long int, paranoia_cb_mode_t)) { cdrom_paranoia_t *p=v->p; int16_t *vec=fv(v); long end=fs(v),begin; long j; #if TRACE_PARANOIA & 2 fprintf(stderr, "- Silence matching fragment [%ld-%ld] to root [%ld-%ld]" " silencebegin=%ld\n", fb(v), fe(v), rb(root), re(root), root->silencebegin); #endif /* See how much leading silence this fragment has. If there are fewer than * MIN_SILENCE_BOUNDARY leading silent samples, we don't do this special * silence matching. * * This fragment could actually belong here, but we can't be sure unless * it has enough silence on its leading edge. This fragment will likely * stick around until we do successfully extend the root, at which point * it will be merged using the usual method. */ if (enddynoverlap samples of the end of root). */ if (fb(v)>=re(root) && fb(v)-p->dynoverlapsilencebegin); end = min(j,re(root)); /* If there is an overlap, we assume that both the root and the fragment * are jitter-free (since there's no way for us to tell otherwise). */ if (beginre(root)){ long int voff = begin-fb(v); /* Truncate the overlapping silence from the end of the root. */ c_remove(rc(root),begin-rb(root),-1); /* Append the fragment to the root, starting from the point of overlap. */ c_append(rc(root),vec+voff,fs(v)-voff); #if TRACE_PARANOIA & 2 fprintf(stderr, "* Adding [%ld-%ld] to root (no jitter)\n", begin, re(root)); #endif } /* Record the fact that we merged this fragment assuming zero jitter. */ offset_add_value(p,&p->stage2,0,callback); } else { /* We weren't able to merge the fragment assuming zero jitter. * * Check whether the fragment's leading silence ends before the root's * trailing silence begins. If it does, we assume that the root is * jittered forward. */ if (jre(root)) { /* Truncate the trailing silence from the root. */ c_remove(rc(root),root->silencebegin-rb(root),-1); /* Append the non-silent tail of the fragment to the root. */ c_append(rc(root),vec+voff,fs(v)-voff); #if TRACE_PARANOIA & 2 fprintf(stderr, "* Adding [%ld-%ld] to root (jitter=%ld)\n", root->silencebegin, re(root), end-begin); #endif } /* Record the fact that we merged this fragment assuming (end-begin) * jitter. */ offset_add_value(p,&p->stage2,end-begin,callback); } else /* We only get here if the fragment is past the end of the root, * which means it must be farther than (dynoverlap) away, due to our * root extension above. */ /* We weren't able to merge this fragment into the root after all. */ return(0); } /* We only get here if we merged the fragment into the root. Update * the root's silence flag. * * Note that this is the only place silenceflag is reset. In other words, * once i_silence_test() lights the silence flag, it can only be reset * by i_silence_match(). */ root->silenceflag = 0; /* Now see if the new, extended root ends in silence. */ i_silence_test(root); /* Since we merged the fragment, we can free it now. But first we propagate * its lastsector flag. */ if (v->lastsector) root->lastsector=1; free_v_fragment(v); return(1); } /* =========================================================================== * i_stage2_each (internal) * * This function (which is entirely too long) attempts to merge the passed * verified fragment into the verified root. * * First this function looks for a run of identical samples between * the root and the fragment. If it finds a long enough run, it then * checks for "rifts" (see below) and fixes the root and/or fragment as * necessary. Finally, if the fragment will extend the tail of the root, * we merge the fragment and extend the root. * * Most of the ugliness in this function has to do with handling "rifts", * which are points of disagreement between the root and the verified * fragment. This can happen when a drive consistently drops a few samples * or stutters and repeats a few samples. It has to be consistent enough * to result in a verified fragment (i.e. it happens twice), but inconsistent * enough (e.g. due to the jiggled reads) not to happen every time. * * This function returns 1 if the fragment was successfully merged into the * root, and 0 if not. */ static long int i_stage2_each(root_block *root, v_fragment_t *v, void(*callback)(long int, paranoia_cb_mode_t)) { /* If this fragment has already been merged & freed, abort. */ if (!v || !v->one) return(0); cdrom_paranoia_t *p=v->p; /* "??? Why do we round down to an even dynoverlap?" Dynoverlap is in samples, not stereo frames --Monty */ long dynoverlap=p->dynoverlap/2*2; /* If there's no verified root yet, abort. */ if (!rv(root)){ return(0); } else { sync_result_t r; /* Search for a sufficiently long run of identical samples between * the verified fragment and the verified root. There's a little * bit of subtlety in the search when silence is involved. */ if (i_iterate_stage2(p,v,&r,callback)){ /* Convert the results of the search to be relative to the root. */ long int begin=r.begin-rb(root); long int end=r.end-rb(root); /* Convert offset into a value that will transform a relative * position in the root to the corresponding relative position in * the fragment. I.e., if offset = -2, then the sample at relative * position 2 in the root is at relative position 0 in the fragment. * * While a bit opaque, this does reduce the number of calculations * below. */ long int offset=r.begin+r.offset-fb(v)-begin; long int temp; c_block_t *l=NULL; /* we have a match! We don't rematch off rift, we chase the match all the way to both extremes doing rift analysis. */ #if TRACE_PARANOIA & 2 fprintf(stderr, "matched [%ld-%ld], offset=%ld\n", r.begin, r.end, r.offset); int traced = 0; #endif #ifdef NOISY fprintf(stderr,"Stage 2 match\n"); #endif /* Now that we've found a sufficiently long run of identical samples * between the fragment and the root, we need to check for rifts. * * A "rift", as mentioned above, is a disagreement between the * fragment and the root. When there's a rift, the matching run * found by i_iterate_stage2() will obviously stop where the root * and the fragment disagree. * * So we detect rifts by checking whether the matching run extends * to the ends of the fragment and root. If the run does extend to * the ends of the fragment and root, then all overlapping samples * agreed, and there's no rift. If, however, the matching run * stops with samples left over in both the root and the fragment, * that means the root and fragment disagreed at that point. * Leftover samples at the beginning of the match indicate a * leading rift, and leftover samples at the end of the match indicate * a trailing rift. * * Once we detect a rift, we attempt to fix it, depending on the * nature of the disagreement. See i_analyze_rift_[rf] for details * on how we determine what kind of rift it is. See below for * how we attempt to fix the rifts. */ /* First, check for a leading rift, fix it if possible, and then * extend the match forward until either we hit the limit of the * overlapping samples, or until we encounter another leading rift. * Keep doing this until we hit the beginning of the overlap. * * Note that while we do fix up leading rifts, we don't extend * the root backward (earlier samples) -- only forward (later * samples). */ /* If the beginning of the match didn't reach the beginning of * either the fragment or the root, we have a leading rift to be * examined. * * Remember that (begin) is the offset into the root, and (begin+offset) * is the equivalent offset into the fragment. If neither one is at * zero, then they both have samples before the match, and hence a * rift. */ while ((begin+offset>0 && begin>0)){ long matchA=0,matchB=0,matchC=0; /* (begin) is the offset into the root of the first matching sample, * (beginL) is the offset into the fragment of the first matching * sample. These samples are at the edge of the rift. */ long beginL=begin+offset; #if TRACE_PARANOIA & 2 if ((traced & 1) == 0) { fprintf(stderr, "- Analyzing leading rift...\n"); traced |= 1; } #endif /* The first time we encounter a leading rift, allocate a * scratch copy of the verified fragment which we'll use if * we need to fix up the fragment before merging it into * the root. */ if (l==NULL){ int16_t *buff=malloc(fs(v)*sizeof(int16_t)); l=c_alloc(buff,fb(v),fs(v)); memcpy(buff,fv(v),fs(v)*sizeof(int16_t)); } /* Starting at the first mismatching sample, see how far back the * rift goes, and determine what kind of rift it is. Note that * we're searching through the fixed up copy of the fragment. * * matchA > 0 if there are samples missing from the root * matchA < 0 if there are duplicate samples (stuttering) in the root * matchB > 0 if there are samples missing from the fragment * matchB < 0 if there are duplicate samples in the fragment * matchC != 0 if there's a section of garbage, after which * the fragment and root agree and are in sync */ i_analyze_rift_r(rv(root),cv(l), rs(root),cs(l), begin-1,beginL-1, &matchA,&matchB,&matchC); #ifdef NOISY fprintf(stderr,"matching rootR: matchA:%ld matchB:%ld matchC:%ld\n", matchA,matchB,matchC); #endif /* "??? The root.returnedlimit checks below are presently a mystery." */ /* Those are for the case where our backtracking wants to take us to back before bytes we've already returned to the application. In short, it's a "we're screwed" check. --Monty */ if (matchA){ /* There's a problem with the root */ if (matchA>0){ /* There were (matchA) samples dropped from the root. We'll add * them back from the fixed up fragment. */ if (callback) (*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED); if (rb(root)+beginroot.returnedlimit) break; else{ /* At the edge of the rift in the root, insert the missing * samples from the fixed up fragment. They're the (matchA) * samples immediately preceding the edge of the rift in the * fragment. */ c_insert(rc(root),begin,cv(l)+beginL-matchA, matchA); /* We just inserted (matchA) samples into the root, so update * our begin/end offsets accordingly. Also adjust the * (offset) to compensate (since we use it to find samples in * the fragment, and the fragment hasn't changed). */ offset-=matchA; begin+=matchA; end+=matchA; } } else { /* There were (-matchA) duplicate samples (stuttering) in the * root. We'll drop them. */ if (callback) (*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED); if (rb(root)+begin+matchAroot.returnedlimit) break; else{ /* Remove the (-matchA) samples immediately preceding the * edge of the rift in the root. */ c_remove(rc(root),begin+matchA,-matchA); /* We just removed (-matchA) samples from the root, so update * our begin/end offsets accordingly. Also adjust the offset * to compensate. Remember that matchA < 0, so we're actually * subtracting from begin/end. */ offset-=matchA; begin+=matchA; end+=matchA; } } } else if (matchB){ /* There's a problem with the fragment */ if (matchB>0){ /* There were (matchB) samples dropped from the fragment. We'll * add them back from the root. */ if (callback) (*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED); /* At the edge of the rift in the fragment, insert the missing * samples from the root. They're the (matchB) samples * immediately preceding the edge of the rift in the root. * Note that we're fixing up the scratch copy of the fragment. */ c_insert(l,beginL,rv(root)+begin-matchB, matchB); /* We just inserted (matchB) samples into the fixed up fragment, * so update (offset), since we use it to find samples in the * fragment based on the root's unchanged offsets. */ offset+=matchB; } else { /* There were (-matchB) duplicate samples (stuttering) in the * fixed up fragment. We'll drop them. */ if (callback) (*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED); /* Remove the (-matchB) samples immediately preceding the edge * of the rift in the fixed up fragment. */ c_remove(l,beginL+matchB,-matchB); /* We just removed (-matchB) samples from the fixed up fragment, * so update (offset), since we use it to find samples in the * fragment based on the root's unchanged offsets. */ offset+=matchB; } } else if (matchC){ /* There are (matchC) samples that simply disagree between the * fragment and the root. On the other side of the mismatch, the * fragment and root agree again. We can't classify the mismatch * as either a stutter or dropped samples, and we have no way of * telling whether the fragment or the root is right. * * "The original comment indicated that we set "disagree" * flags in the root, but it seems to be historical." The * disagree flags were from a time when we did interpolation * over samples we simply couldn't get to agree. Yes, * historical functionality that didn;t work well. --Monty */ if (rb(root)+begin-matchCroot.returnedlimit) break; /* Overwrite the mismatching (matchC) samples in root with the * samples from the fixed up fragment. * * "??? Do we think the fragment is more likely correct, is this * just arbitrary, or is there some other reason for overwriting * the root?" * We think these samples are more likely to be correct --Monty */ c_overwrite(rc(root),begin-matchC, cv(l)+beginL-matchC,matchC); } else { /* We may have had a mismatch because we ran into leading silence. * * "??? To be studied: why would this cause a mismatch? * Neither i_analyze_rift_r nor i_iterate_stage2() nor * i_paranoia_overlap() appear to take silence into * consideration in this regard. It could be due to our * skipping of silence when searching for a match." Jitter * and or skipping in sections of silence could end up with * two sets of verified vectors that agree completely except * for the length of the silence. Silence is a huge bugaboo * in general because there's no entropy within it to base * verification on. --Monty * * Since we don't extend the root in that direction, we don't * do anything, just move on to trailing rifts. */ /* If the rift was too complex to fix (see i_analyze_rift_r), * we just stop and leave the leading edge where it is. */ /*RRR(*callback)(post,PARANOIA_CB_XXX);*/ break; } /* Recalculate the offset of the edge of the rift in the fixed * up fragment, in case it changed. * * "??? Why is this done here rather than in the (matchB) case above, * which should be the only time beginL will change." * Because there's no reason not to? --Monty */ beginL=begin+offset; /* Now that we've fixed up the root or fragment as necessary, see * how far we can extend the matching run. This function is * overkill, as it tries to extend the matching run in both * directions (and rematches what we already matched), but it works. */ i_paranoia_overlap(rv(root),cv(l), begin,beginL, rs(root),cs(l), &begin,&end); } /* end while (leading rift) */ /* Second, check for a trailing rift, fix it if possible, and then * extend the match forward until either we hit the limit of the * overlapping samples, or until we encounter another trailing rift. * Keep doing this until we hit the end of the overlap. */ /* If the end of the match didn't reach the end of either the fragment * or the root, we have a trailing rift to be examined. * * Remember that (end) is the offset into the root, and (end+offset) * is the equivalent offset into the fragment. If neither one is * at the end of the vector, then they both have samples after the * match, and hence a rift. * * (temp) is the size of the (potentially fixed-up) fragment. If * there was a leading rift, (l) is the fixed up fragment, and * (offset) is now relative to it. */ temp=l ? cs(l) : fs(v); while (end+offset 0 if there are samples missing from the root * matchA < 0 if there are duplicate samples (stuttering) in the root * matchB > 0 if there are samples missing from the fragment * matchB < 0 if there are duplicate samples in the fragment * matchC != 0 if there's a section of garbage, after which * the fragment and root agree and are in sync */ i_analyze_rift_f(rv(root),cv(l), rs(root),cs(l), end,endL, &matchA,&matchB,&matchC); #ifdef NOISY fprintf(stderr,"matching rootF: matchA:%ld matchB:%ld matchC:%ld\n", matchA,matchB,matchC); #endif /* ??? The root.returnedlimit checks below are presently a mystery. */ if (matchA){ /* There's a problem with the root */ if (matchA>0){ /* There were (matchA) samples dropped from the root. We'll add * them back from the fixed up fragment. */ if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED); if (end+rb(root)root.returnedlimit) break; /* At the edge of the rift in the root, insert the missing * samples from the fixed up fragment. They're the (matchA) * samples immediately preceding the edge of the rift in the * fragment. */ c_insert(rc(root),end,cv(l)+endL,matchA); /* Although we just inserted samples into the root, we did so * after (begin) and (end), so we needn't update those offsets. */ } else { /* There were (-matchA) duplicate samples (stuttering) in the * root. We'll drop them. */ if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED); if (end+rb(root)root.returnedlimit) break; /* Remove the (-matchA) samples immediately following the edge * of the rift in the root. */ c_remove(rc(root),end,-matchA); /* Although we just removed samples from the root, we did so * after (begin) and (end), so we needn't update those offsets. */ } } else if (matchB){ /* There's a problem with the fragment */ if (matchB>0){ /* There were (matchB) samples dropped from the fragment. We'll * add them back from the root. */ if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED); /* At the edge of the rift in the fragment, insert the missing * samples from the root. They're the (matchB) samples * immediately following the dge of the rift in the root. * Note that we're fixing up the scratch copy of the fragment. */ c_insert(l,endL,rv(root)+end,matchB); /* Although we just inserted samples into the fragment, we did so * after (begin) and (end), so (offset) hasn't changed either. */ } else { /* There were (-matchB) duplicate samples (stuttering) in the * fixed up fragment. We'll drop them. */ if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED); /* Remove the (-matchB) samples immediately following the edge * of the rift in the fixed up fragment. */ c_remove(l,endL,-matchB); /* Although we just removed samples from the fragment, we did so * after (begin) and (end), so (offset) hasn't changed either. */ } } else if (matchC){ /* There are (matchC) samples that simply disagree between the * fragment and the root. On the other side of the mismatch, the * fragment and root agree again. We can't classify the mismatch * as either a stutter or dropped samples, and we have no way of * telling whether the fragment or the root is right. * * The original comment indicated that we set "disagree" flags * in the root, but it seems to be historical. */ if (end+rb(root)root.returnedlimit) break; /* Overwrite the mismatching (matchC) samples in root with the * samples from the fixed up fragment. * * ??? Do we think the fragment is more likely correct, is this * just arbitrary, or is there some other reason for overwriting * the root? */ c_overwrite(rc(root),end,cv(l)+endL,matchC); } else { /* We may have had a mismatch because we ran into trailing silence. * * ??? To be studied: why would this cause a mismatch? Neither * i_analyze_rift_f nor i_iterate_stage2() nor i_paranoia_overlap() * appear to take silence into consideration in this regard. * It could be due to our skipping of silence when searching for * a match. */ /* At this point we have a trailing rift. We check whether * one of the vectors (fragment or root) has trailing silence. */ analyze_rift_silence_f(rv(root),cv(l), rs(root),cs(l), end,endL, &matchA,&matchB); if (matchA){ /* The contents of the root's trailing rift are silence. The * fragment's are not (otherwise there wouldn't be a rift). * We therefore assume that the root has garbage from this * point forward and truncate it. * * This will have the effect of eliminating the trailing * rift, causing the fragment's samples to be appended to * the root. * * ??? Does this have any negative side effects? Why is this * a good idea? */ /* ??? TODO: returnedlimit */ /* Can only do this if we haven't already returned data */ if (end+rb(root)>=p->root.returnedlimit){ c_remove(rc(root),end,-1); } } else if (matchB){ /* The contents of the fragment's trailing rift are silence. * The root's are not (otherwise there wouldn't be a rift). * We therefore assume that the fragment has garbage from this * point forward. * * We needn't actually truncate the fragment, because the root * has already been fixed up from this fragment as much as * possible, and the truncated fragment wouldn't extend the * root. Therefore, we can consider this (truncated) fragment * to be already merged into the root. So we dispose of it and * return a success. */ if (l)i_cblock_destructor(l); free_v_fragment(v); return(1); } else { /* If the rift was too complex to fix (see i_analyze_rift_f), * we just stop and leave the trailing edge where it is. */ /*RRR(*callback)(post,PARANOIA_CB_XXX);*/ } break; } /* Now that we've fixed up the root or fragment as necessary, see * how far we can extend the matching run. This function is * overkill, as it tries to extend the matching run in both * directions (and rematches what we already matched), but it works. */ i_paranoia_overlap(rv(root),cv(l), begin,beginL, rs(root),cs(l), NULL,&end); temp=cs(l); } /* end while (trailing rift) */ /* Third and finally, if the overlapping verified fragment extends * our range forward (later samples), we append ("glom") the new * samples to the end of the root. * * Note that while we did fix up leading rifts, we don't extend * the root backward (earlier samples) -- only forward (later * samples). * * This is generally fine, since the verified root is supposed to * slide from earlier samples to later samples across multiple calls * to paranoia_read(). * * "??? But, is this actually right? Because of this, we don't * extend the root to hold the earliest read sample, if we * happened to initialize the root with a later sample due to * jitter. There are probably some ugly side effects from * extending the root backward, in the general case, but it may * not be so dire if we're near sample 0. To be investigated." * In the begin case, any start position is arbitrary due to * inexact seeking. Later, we can't back-extend the root as the * samples preceeding the beginning have already been returned * to the application! --Monty */ { long sizeA=rs(root); long sizeB; long vecbegin; int16_t *vector; /* If there were any rifts, we'll use the fixed up fragment (l), * otherwise, we use the original fragment (v). */ if (l){ sizeB=cs(l); vector=cv(l); vecbegin=cb(l); } else { sizeB=fs(v); vector=fv(v); vecbegin=fb(v); } /* Convert the fragment-relative offset (sizeB) into an offset * relative to the root (A), and see if the offset is past the * end of the root (> sizeA). If it is, this fragment will extend * our root. * * "??? Why do we check for v->lastsector separately?" Because * of the case where root extends *too* far; if we never get a * read that accidentally extends that far again, we could * hang and loop forever. --Monty */ if (sizeB-offset>sizeA || v->lastsector){ if (v->lastsector){ root->lastsector=1; } /* "??? Why would end be < sizeA? Why do we truncate root?" Because it can happen (seeking is very very inexact) and end of disk tends to be very problematic in terms of stopping point. We also generally believe more recent information over previous information when they disagree and both are 'verified'. --Monty */ if (endstage2,offset+vecbegin-rb(root),callback); } } if (l)i_cblock_destructor(l); free_v_fragment(v); return(1); } else { /* !i_iterate_stage2(...) */ #if TRACE_PARANOIA & 2 fprintf(stderr, "no match"); #endif /* We were unable to merge this fragment into the root. * * Check whether the fragment should have overlapped with the root, * even taking possible jitter into account. (I.e., If the fragment * ends so far before the end of the root that even (dynoverlap) * samples of jitter couldn't push it beyond the end of the root, * it should have overlapped.) * * It is, however, possible that we failed to match using the normal * tests because we're dealing with silence, which we handle * separately. * * If the fragment should have overlapped, and we're not dealing * with the special silence case, we don't know what to make of * this fragment, and we just discard it. */ if (fe(v)+dynoverlapsilenceflag){ /* It *should* have matched. No good; free it. */ free_v_fragment(v); #if TRACE_PARANOIA & 2 fprintf(stderr, ", discarding fragment."); #endif } #if TRACE_PARANOIA & 2 fprintf(stderr, "\n"); #endif /* otherwise, we likely want this for an upcoming match */ /* we don't free the sort info (if it was collected) */ return(0); } } /* endif rv(root) */ } static int i_init_root(root_block *root, v_fragment_t *v,long int begin, void(*callback)(long int, paranoia_cb_mode_t)) { if (fb(v)<=begin && fe(v)>begin){ root->lastsector=v->lastsector; root->returnedlimit=begin; if (rv(root)){ i_cblock_destructor(rc(root)); rc(root)=NULL; } { int16_t *buff=malloc(fs(v)*sizeof(int16_t)); memcpy(buff,fv(v),fs(v)*sizeof(int16_t)); root->vector=c_alloc(buff,fb(v),fs(v)); } /* Check whether the new root has a long span of trailing silence. */ i_silence_test(root); #if TRACE_PARANOIA & 2 fprintf(stderr, "* Assigning fragment [%ld-%ld] to root, silencebegin=%ld\n", rb(root), re(root), root->silencebegin); #endif return(1); } else return(0); } static int vsort(const void *a,const void *b) { return((*(v_fragment_t **)a)->begin-(*(v_fragment_t **)b)->begin); } /* =========================================================================== * i_stage2 (internal) * * This function attempts to extend the verified root by merging verified * fragments into it. It keeps extending the tail end of the root until * it runs out of matching fragments. See i_stage2_each (and * i_iterate_stage2) for details of fragment matching and merging. * * This function is called by paranoia_read_limited when the verified root * doesn't contain sufficient data to satisfy the request for samples. * If this function fails to extend the verified root far enough (having * exhausted the currently available verified fragments), the caller * will then read the device again to try and establish more verified * fragments. * * We first try to merge all the fragments in ascending order using the * standard method (i_stage2_each()), and then we try to merge the * remaining fragments using silence matching (i_silence_match()) * if the root has a long span of trailing silence. See the initial * comments on silence and i_silence_match() for an explanation of this * distinction. * * This function returns the number of verified fragments successfully * merged into the verified root. */ static int i_stage2(cdrom_paranoia_t *p, long int beginword, long int endword, void (*callback)(long int, paranoia_cb_mode_t)) { int flag=1,ret=0; root_block *root=&(p->root); #ifdef NOISY fprintf(stderr,"Fragments:%ld\n",p->fragments->active); fflush(stderr); #endif /* even when the 'silence flag' is lit, we try to do non-silence matching in the event that there are still audio vectors with content to be sunk before the silence */ /* This flag is not the silence flag. Rather, it indicates whether * we succeeded in adding a verified fragment to the verified root. * In short, we keep adding fragments until we no longer find a * match. */ while (flag) { /* Convert the linked list of verified fragments into an array, * to be sorted in order of beginning sample position */ v_fragment_t *first=v_first(p); long active=p->fragments->active,count=0; v_fragment_t **list = calloc(active, sizeof(v_fragment_t *)); while (first){ v_fragment_t *next=v_next(first); list[count++]=first; first=next; } /* Reset the flag so that if we don't match any fragments, we * stop looping. Then, proceed only if there are any fragments * to match. */ flag=0; if (count){ /* Sort the array of verified fragments in order of beginning * sample position. */ qsort(list,active,sizeof(v_fragment_t *),&vsort); /* We don't check for the silence flag yet, because even if the * verified root ends in silence (and thus the silence flag is set), * there may be a non-silent region at the beginning of the verified * root, into which we can merge the verified fragments. */ /* Iterate through the verified fragments, starting at the fragment * with the lowest beginning sample position. */ for(count=0;countone){ /* If we don't have a verified root yet, just promote the first * fragment (with lowest beginning sample) to be the verified * root. * * "??? It seems that this could be fairly arbitrary if jitter * is an issue. If we've verified two fragments allegedly * beginning at "0" (which are actually slightly offset due to * jitter), the root might not begin at the earliest read * sample. Additionally, because subsequent fragments are * only merged at the tail end of the root, this situation * won't be fixed by merging the earlier samples. * * Practically, this ends up not being critical since most * drives insert some extra silent samples at the beginning * of the stream. Missing a few of them doesn't cause any * real lost data. But it is non-deterministic." * * On such a drive, the entire act of CDDA read is highly * nondeterministic. All redbook says is +/- 75 sectors. * If you insist on the earliest possible sample, you can * get into a situation where the first read was far earlier * than all the others and no other read ever repeats the * early positioning. --Monty */ if (rv(root)==NULL){ if (i_init_root(&(p->root),first,beginword,callback)){ free_v_fragment(first); /* Consider this a merged fragment, so set the flag * to keep looping. */ flag=1; ret++; } } else { /* Try to merge this fragment with the verified root, * extending the tail of the root. */ if (i_stage2_each(root,first,callback)){ /* If we successfully merged the fragment, set the flag * to keep looping. */ ret++; flag=1; } } } } /* If the verified root ends in a long span of silence, iterate * through the remaining unmerged fragments to see if they can be * merged using our special silence matching. */ if (!flag && p->root.silenceflag){ for(count=0;countone){ if (rv(root)!=NULL){ /* Try to merge the fragment into the root. This will only * succeed if the fragment overlaps and begins with sufficient * silence to be a presumed match. * * Note that the fragments must be passed to i_silence_match() * in ascending order, as they are here. */ if (i_silence_match(root,first,callback)){ /* If we successfully merged the fragment, set the flag * to keep looping. */ ret++; flag=1; } } } } /* end for */ } } /* end if(count) */ free(list); /* If we were able to extend the verified root at all during this pass * through the loop, loop again to see if we can merge any remaining * fragments with the extended root. */ #if TRACE_PARANOIA & 2 if (flag) fprintf(stderr, "- Root updated, comparing remaining fragments again.\n"); #endif } /* end while */ /* Return the number of fragments we successfully merged into the * verified root. */ return(ret); } static void i_end_case(cdrom_paranoia_t *p,long endword, void(*callback)(long int, paranoia_cb_mode_t)) { root_block *root=&p->root; /* have an 'end' flag; if we've just read in the last sector in a session, set the flag. If we verify to the end of a fragment which has the end flag set, we're done (set a done flag). Pad zeroes to the end of the read */ if (root->lastsector==0)return; if (endwordroot); c_block_t *graft=NULL; int vflag=0; int gend=0; long post; #ifdef NOISY fprintf(stderr,"\nskipping\n"); #endif if (rv(root)==NULL){ post=0; } else { post=re(root); } if (post==-1)post=0; if (callback)(*callback)(post,PARANOIA_CB_SKIP); #if TRACE_PARANOIA fprintf(stderr, "Skipping [%ld-", post); #endif /* We want to add a sector. Look for a c_block that spans, preferrably a verified area */ { c_block_t *c=c_first(p); while (c){ long cbegin=cb(c); long cend=ce(c); if (cbegin<=post && cend>post){ long vend=post; if (c->flags[post-cbegin]&FLAGS_VERIFIED){ /* verified area! */ while (vendflags[vend-cbegin]&FLAGS_VERIFIED))vend++; if (!vflag || vend>vflag){ graft=c; gend=vend; } vflag=1; } else { /* not a verified area */ if (!vflag){ while (vendflags[vend-cbegin]&FLAGS_VERIFIED)==0)vend++; if (graft==NULL || gend>vend){ /* smallest unverified area */ graft=c; gend=vend; } } } } c=c_next(c); } if (graft){ long cbegin=cb(graft); long cend=ce(graft); while (gendflags[gend-cbegin]&FLAGS_VERIFIED))gend++; gend=min(gend+OVERLAP_ADJ,cend); if (rv(root)==NULL){ int16_t *buff=malloc(cs(graft)); memcpy(buff,cv(graft),cs(graft)); rc(root)=c_alloc(buff,cb(graft),cs(graft)); } else { c_append(rc(root),cv(graft)+post-cbegin, gend-post); } #if TRACE_PARANOIA fprintf(stderr, "%d], filled with %s data from block [%ld-%ld]\n", gend, (graft->flags[post-cbegin]&FLAGS_VERIFIED) ? "verified" : "unverified", cbegin, cend); #endif root->returnedlimit=re(root); return; } } /* No? Fine. Great. Write in some zeroes :-P */ { void *temp=calloc(CDIO_CD_FRAMESIZE_RAW,sizeof(int16_t)); if (rv(root)==NULL){ rc(root)=c_alloc(temp,post,CDIO_CD_FRAMESIZE_RAW); } else { c_append(rc(root),temp,CDIO_CD_FRAMESIZE_RAW); free(temp); } #if TRACE_PARANOIA fprintf(stderr, "%ld], filled with zero\n", re(root)); #endif root->returnedlimit=re(root); } } /**** toplevel ****************************************/ void paranoia_free(cdrom_paranoia_t *p) { paranoia_resetall(p); sort_free(p->sortcache); free_list(p->cache, 1); free_list(p->fragments, 1); free(p); } /*! Set the kind of repair you want to on for reading. The modes are listed above @param p paranoia type @param mode_flags paranoia mode flags built from values in paranoia_mode_t, e.g. PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP */ void paranoia_modeset(cdrom_paranoia_t *p, int mode_flags) { p->enable=mode_flags; } /*! reposition reading offset. @param p paranoia type @param seek byte offset to seek to @param whence like corresponding parameter in libc's lseek, e.g. SEEK_SET or SEEK_END. */ lsn_t paranoia_seek(cdrom_paranoia_t *p, int32_t seek, int whence) { long sector; long ret; switch(whence){ case SEEK_SET: sector=seek; break; case SEEK_END: sector=cdda_disc_lastsector(p->d)+seek; break; default: sector=p->cursor+seek; break; } if (cdda_sector_gettrack(p->d,sector)==-1)return(-1); i_cblock_destructor(p->root.vector); p->root.vector=NULL; p->root.lastsector=0; p->root.returnedlimit=0; ret=p->cursor; p->cursor=sector; i_paranoia_firstlast(p); /* Evil hack to fix pregap patch for NEC drives! To be rooted out in a10 */ p->current_firstsector=sector; return(ret); } static void cdrom_cache_update(cdrom_paranoia_t *p, int lba, int sectors){ if(lba+sectors > p->cdcache_size){ int end = lba+sectors; lba=end-p->cdcache_size; sectors = end-lba; } if(lba < p->cdcache_begin){ /* a backseek flushes the cache */ p->cdcache_begin=lba; p->cdcache_end=lba+sectors; }else{ if(lba+sectors>p->cdcache_end) p->cdcache_end = lba+sectors; if(lba+sectors-p->cdcache_size > p->cdcache_begin){ if(lba+sectors-p->cdcache_size < p->cdcache_end){ p->cdcache_begin = lba+sectors-p->cdcache_size; }else{ p->cdcache_begin = lba; } } } } static void cdrom_cache_handler(cdrom_paranoia_t *p, int lba, void(*callback)(long, paranoia_cb_mode_t)){ int seekpos; int ms; if(lba>=p->cdcache_end)return; /* nothing to do */ if(lba<0)lba=0; if(lbacdcache_begin){ /* should always trigger a backseek so let's do that here and look for the timing */ seekpos=(lba==0 || lba-1d) ? lba : lba-1); /* keep reads linear when possible */ }else{ int pre = p->cdcache_begin-1; int post = lba+p->cdcache_size; seekpos = (pred) ? post : pre); } if(cdda_read_timed(p->d,NULL,seekpos,1,&ms)==1) if(seekposcdcache_begin && msd->p_cdio)==cdio_os_driver) if (callback) (*callback)(seekpos*CD_FRAMEWORDS,PARANOIA_CB_CACHEERR); cdrom_cache_update(p,seekpos,1); return; } /* =========================================================================== * read_c_block() (internal) * * This funtion reads many (p->readahead) sectors, encompassing at least * the requested words. * * It returns a c_block which encapsulates these sectors' data and sector * number. The sectors come come from multiple low-level read requests. * * This function reads many sectors in order to exhaust any caching on the * drive itself, as caching would simply return the same incorrect data * over and over. Paranoia depends on truly re-reading portions of the * disc to make sure the reads are accurate and correct any inaccuracies. * * Which precise sectors are read varies ("jiggles") between calls to * read_c_block, to prevent consistent errors across multiple reads * from being misinterpreted as correct data. * * The size of each low-level read is determined by the underlying driver * (p->d->nsectors), which allows the driver to specify how many sectors * can be read in a single request. Historically, the Linux kernel could * only read 8 sectors at a time, with likely dropped samples between each * read request. Other operating systems may have different limitations. * * This function is called by paranoia_read_limited(), which breaks the * c_block of read data into runs of samples that are likely to be * contiguous, verifies them and stores them in verified fragments, and * eventually merges the fragments into the verified root. * * This function returns the last c_block read or NULL on error. */ static c_block_t * i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword, void(*callback)(long, paranoia_cb_mode_t)) { /* why do it this way? We need to read lots of sectors to kludge around stupid read ahead buffers on cheap drives, as well as avoid expensive back-seeking. We also want to 'jiggle' the start address to try to break borderline drives more noticeably (and make broken drives with unaddressable sectors behave more often). */ long readat,firstread; long totaltoread=p->cdcache_size; long sectatonce=p->d->nsectors; long driftcomp=(float)p->dyndrift/CD_FRAMEWORDS+.5; c_block_t *new=NULL; root_block *root=&p->root; int16_t *buffer=NULL; unsigned char *flags=NULL; long sofar; long dynoverlap=(p->dynoverlap+CD_FRAMEWORDS-1)/CD_FRAMEWORDS; long anyflag=0; /* Calculate the first sector to read. This calculation takes * into account the need to jitter the starting point of the read * to reveal consistent errors as well as the low reliability of * the edge words of a read. * * ???: Document more clearly how dynoverlap and MIN_SECTOR_BACKUP * are calculated and used. */ /* What is the first sector to read? want some pre-buffer if we're not at the extreme beginning of the disc */ if (p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){ long target; if (rv(root)==NULL || rb(root)>beginword) target=p->cursor-dynoverlap; else target=re(root)/(CD_FRAMEWORDS)-dynoverlap; /* we want to jitter the read alignment boundary, as some drives, beginning from a specific point, will tend to lose bytes between sectors in the same place. Also, as our vectors are being made up of multiple reads, we want the overlap boundaries to move.... */ readat=(target&(~((long)JIGGLE_MODULO-1)))+p->jitter; if (readat>target)readat-=JIGGLE_MODULO; p->jitter--; if (p->jitter<0) p->jitter+=JIGGLE_MODULO; } else { readat=p->cursor; } readat+=driftcomp; /* Create a new, empty c_block and add it to the head of the * list of c_blocks in memory. It will be empty until the end of * this subroutine. */ if (p->enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)) { flags=calloc(totaltoread*CD_FRAMEWORDS, 1); new=new_c_block(p); recover_cache(p); } else { /* in the case of root it's just the buffer */ paranoia_resetall(p); new=new_c_block(p); } buffer=calloc(totaltoread*CDIO_CD_FRAMESIZE_RAW, 1); sofar=0; firstread=-1; /* we have a read span; flush the drive cache if needed */ cdrom_cache_handler(p, readat, callback); #if TRACE_PARANOIA fprintf(stderr, "Reading [%ld-%ld] from media\n", readat*CD_FRAMEWORDS, (readat+totaltoread)*CD_FRAMEWORDS); #endif /* Issue each of the low-level reads; the optimal read size is * approximately the cachemodel's cdrom cache size. The only reason * to read less would be memory considerations. * * p->readahead = total number of sectors to read * p->d->nsectors = number of sectors to read per request */ /* actual read loop */ while (sofarcurrent_firstsector){ secread-=p->current_firstsector-adjread; adjread=p->current_firstsector; } if (adjread+secread-1>p->current_lastsector) secread=p->current_lastsector-adjread+1; if (sofar+secread>totaltoread)secread=totaltoread-sofar; if (secread>0){ if (firstread<0) firstread = adjread; /* Issue the low-level read to the driver. */ thisread = cdda_read(p->d, buffer+sofar*CD_FRAMEWORDS, adjread, secread); #if TRACE_PARANOIA & 1 fprintf(stderr, "- Read [%ld-%ld] (0x%04X...0x%04X)%s", adjread*CD_FRAMEWORDS, (adjread+thisread)*CD_FRAMEWORDS, buffer[sofar*CD_FRAMEWORDS] & 0xFFFF, buffer[(sofar+thisread)*CD_FRAMEWORDS - 1] & 0xFFFF, thisread < secread ? "" : "\n"); #endif /* If the low-level read returned too few sectors, pad the result * with null data and mark it as invalid (FLAGS_UNREAD). We pad * because we're going to be appending further reads to the current * c_block. * * "???: Why not re-read? It might be to keep you from getting * hung up on a bad sector. Or it might be to avoid * interrupting the streaming as much as possible." * * There are drives on which you will never get a full read in * some positions. They always abort out early due to firmware * boundary cases. Reread will cause exactly the same thing to * happen again. NEC MultiSpeed 4x is one such drive. In these * cases, you take what part of the read you know is good, and * you get substantially better performance. --Monty */ if ( thisread < secread) { if(thisread<0){ #ifdef ENOMEDIUM if(errno==ENOMEDIUM){ /* the one error we bail on immediately */ if(new)free_c_block(new); if(buffer)free(buffer); if(flags)free(flags); return NULL; } #endif thisread=0; } #if TRACE_PARANOIA & 1 fprintf(stderr, " -- couldn't read [%ld-%ld]\n", (adjread+thisread)*CD_FRAMEWORDS, (adjread+secread)*CD_FRAMEWORDS); #endif /* Uhhh... right. Make something up. But don't make us seek backward! */ if (callback) (*callback)((adjread+thisread)*CD_FRAMEWORDS, PARANOIA_CB_READERR); memset(buffer+(sofar+thisread)*CD_FRAMEWORDS,0, CDIO_CD_FRAMESIZE_RAW*(secread-thisread)); if (flags) memset(flags+(sofar+thisread)*CD_FRAMEWORDS, FLAGS_UNREAD, CD_FRAMEWORDS*(secread-thisread)); } if (thisread!=0)anyflag=1; /* Because samples are likely to be dropped between read requests, * mark the samples near the the boundaries of the read requests * as suspicious (FLAGS_EDGE). This means that any span of samples * against which these adjacent read requests are compared must * overlap beyond the edges and into the more trustworthy data. * Such overlapping spans are accordingly at least MIN_WORDS_OVERLAP * words long (and naturally longer if any samples were dropped * between the read requests). * * (EEEEE...overlapping span...EEEEE) * (read 1 ...........EEEEE) (EEEEE...... read 2 ......EEEEE) ... * dropped samples --^ */ if (flags && sofar!=0){ /* Don't verify across overlaps that are too close to one another */ int i=0; for(i=-MIN_WORDS_OVERLAP/2;icurrent_lastsector) new->lastsector=-1; if (callback)(*callback)((adjread+secread-1)*CD_FRAMEWORDS,PARANOIA_CB_READ); cdrom_cache_update(p,adjread,secread); sofar+=secread; readat=adjread+secread; } else /* secread <= 0 */ if (readatcurrent_firstsector) readat+=sectatonce; /* due to being before the readable area */ else break; /* due to being past the readable area */ /* Keep issuing read requests until we've read enough sectors to * exhaust the drive's cache. */ } /* end while */ /* If we managed to read any sectors at all (anyflag), fill in the * previously allocated c_block with the read data. Otherwise, free * our buffers, dispose of the c_block, and return NULL. */ if (anyflag) { new->vector=buffer; new->begin=firstread*CD_FRAMEWORDS-p->dyndrift; new->size=sofar*CD_FRAMEWORDS; new->flags=flags; #if TRACE_PARANOIA fprintf(stderr, "- Read block %ld:[%ld-%ld] from media\n", p->cache->active, cb(new), ce(new)); #endif } else { if (new)free_c_block(new); free(buffer); free(flags); new=NULL; } return(new); } /** ========================================================================== * cdio_paranoia_read(), cdio_paranoia_read_limited() * * These functions "read" the next sector of audio data and returns * a pointer to a full sector of verified samples (2352 bytes). * * The returned buffer is *not* to be freed by the caller. It will * persist only until the next call to paranoia_read() for this p */ int16_t * cdio_paranoia_read(cdrom_paranoia_t *p, void(*callback)(long, paranoia_cb_mode_t)) { return paranoia_read_limited(p, callback, 20); } /* I added max_retry functionality this way in order to avoid breaking any old apps using the new libs. cdparanoia 9.8 will need the updated libs, but nothing else will require it. */ int16_t * cdio_paranoia_read_limited(cdrom_paranoia_t *p, void(*callback)(long int, paranoia_cb_mode_t), int max_retries) { long int beginword = p->cursor*(CD_FRAMEWORDS); long int endword = beginword+CD_FRAMEWORDS; long int retry_count= 0; long int lastend = -2; root_block *root = &p->root; if(p->d->opened==0){ errno=EBADF; return NULL; } if (beginword > p->root.returnedlimit) p->root.returnedlimit=beginword; lastend=re(root); /* Since paranoia reads and verifies chunks of data at a time * (which it needs to counteract dropped samples and inaccurate * seeking), the requested samples may already be in memory, * in the verified "root". * * The root is where paranoia stores samples that have been * verified and whose position has been accurately determined. */ /* First, is the sector we want already in the root? */ while (rv(root)==NULL || rb(root)>beginword || (re(root)enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)) || re(root)enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){ /* We need to make sure our memory consumption doesn't grow * to the size of the whole CD. But at the same time, we * need to hang onto some of the verified data (even perhaps * data that's already been returned by paranoia_read()) in * order to verify and accurately position future samples. * * Therefore, we free some of the verified data that we * no longer need. */ i_paranoia_trim(p,beginword,endword); recover_cache(p); if (rb(root)!=-1 && p->root.lastsector) i_end_case(p, endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), callback); else /* Merge as many verified fragments into the verified root * as we need to satisfy the pending request. We may * not have all the fragments we need, in which case we'll * read data from the CD further below. */ i_stage2(p, beginword, endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), callback); } else i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), callback); /* only trips if we're already done */ #if TRACE_PARANOIA fprintf(stderr, "- Root is now [%ld-%ld] silencebegin=%ld\n", rb(root), re(root), root->silencebegin); #endif /* If we were able to fill the verified root with data already * in memory, we don't need to read any more data from the drive. */ if (!(rb(root)==-1 || rb(root)>beginword || re(root)enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)){ /* If we need to verify these samples, send them to * stage 1 verification, which will add verified samples * to the set of verified fragments. Verified fragments * will be merged into the verified root during stage 2 * overlap analysis. */ if (p->enable&PARANOIA_MODE_VERIFY) i_stage1(p,new,callback); /* If we're only doing overlapping reads (no stage 1 * verification), consider each low-level read in the * c_block to be a verified fragment. We exclude the * edges from these fragments to enforce the requirement * that we overlap the reads by the minimum amount. * These fragments will be merged into the verified * root during stage 2 overlap analysis. */ else{ /* just make v_fragments from the boundary information. */ long begin=0,end=0; while (beginflags[begin]&FLAGS_EDGE))begin++; end=begin+1; while (endflags[end]&FLAGS_EDGE)==0)end++; { new_v_fragment(p,new,begin+cb(new), end+cb(new), (new->lastsector && cb(new)+end==ce(new))); } begin=end; } } } else { /* If we're not doing any overlapping reads or verification * of data, skip over the stage 1 and stage 2 verification and * promote this c_block directly to the current "verified" root. */ if (p->root.vector)i_cblock_destructor(p->root.vector); free_elem(new->e,0); p->root.vector=new; i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), callback); } }else{ #ifdef ENOMEDIUM /* Was the medium removed or the device closed out from under us? */ if(errno==ENOMEDIUM) return NULL; #endif } } /* Are we doing lots of retries? **************************************/ /* ???: To be studied */ /* Check unaddressable sectors first. There's no backoff here; jiggle and minimum backseek handle that for us */ if (rb(root)!=-1 && lastend+588dynoverlap==MAX_SECTOR_OVERLAP*CD_FRAMEWORDS || retry_count==max_retries){ if (!(p->enable&PARANOIA_MODE_NEVERSKIP)) verify_skip_case(p,callback); retry_count=0; } else { if (p->stage1.offpoints!=-1){ /* hack */ p->dynoverlap*=1.5; if (p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS) p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; if (callback) (*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP); } } } } /* Having read data from the drive and placed it into verified * fragments, we now loop back to try to extend the root with * the newly loaded data. Alternatively, if the root already * contains the needed data, we'll just fall through. */ } /* end while */ p->cursor++; /* Return a pointer into the verified root. Thus, the caller * must NOT free the returned pointer! */ return(rv(root)+(beginword-rb(root))); } /* a temporary hack */ void cdio_paranoia_overlapset(cdrom_paranoia_t *p, long int overlap) { p->dynoverlap=overlap*CD_FRAMEWORDS; p->stage1.offpoints=-1; } extern const char *cdio_paranoia_version(void){ return LIBCDIO_PARANOIA_VERSION; } libcdio-paranoia-release-10.2-2.0.2/libcdio_cdda.pc.in000066400000000000000000000004161461637345700222360ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libcdio_cdda Description: CD paranoia CD-DA library from libcdio Version: @PACKAGE_VERSION@ Requires: libcdio Libs: -L${libdir} -lcdio_cdda -lcdio @COS_LIB@ Cflags: -I${includedir} libcdio-paranoia-release-10.2-2.0.2/libcdio_paranoia.pc.in000066400000000000000000000004221461637345700231320ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libcdio_paranoia Description: CD paranoia library from libcdio Version: @PACKAGE_VERSION@ Requires: libcdio Libs: -L${libdir} -lcdio_paranoia -lcdio_cdda -lcdio Cflags: -I${includedir} libcdio-paranoia-release-10.2-2.0.2/m4/000077500000000000000000000000001461637345700172445ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/m4/.gitignore000066400000000000000000000000401461637345700212260ustar00rootroot00000000000000/*.m4 !ld-version-script.m4 /*~ libcdio-paranoia-release-10.2-2.0.2/m4/ld-version-script.m4000066400000000000000000000031741461637345700230770ustar00rootroot00000000000000# ld-version-script.m4 serial 4 dnl Copyright (C) 2008-2019 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Simon Josefsson # FIXME: The test below returns a false positive for mingw # cross-compiles, 'local:' statements does not reduce number of # exported symbols in a DLL. Use --disable-ld-version-script to work # around the problem. # gl_LD_VERSION_SCRIPT # -------------------- # Check if LD supports linker scripts, and define automake conditional # HAVE_LD_VERSION_SCRIPT if so. AC_DEFUN([gl_LD_VERSION_SCRIPT], [ AC_ARG_ENABLE([ld-version-script], [AS_HELP_STRING([--enable-ld-version-script], [enable linker version script (default is enabled when possible)])], [have_ld_version_script=$enableval], [AC_CACHE_CHECK([if LD -Wl,--version-script works], [gl_cv_sys_ld_version_script], [gl_cv_sys_ld_version_script=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map" echo foo >conftest.map AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [], [cat > conftest.map <&1 | ruby ../make-check-filter.rb # See Makefile.am pats = '(' + ["^ CC", "^ CXX", '^(re|g)?make\[', "^(re|g)?make ", "Making check in", '^[+]{2} WARN: ', '^m4/', # doesn't work always '^configure.ac', # doesn't work always '^ cd \.\.', # doesn't work always '^config.status', # doesn't work always "^ vcd_demo.right", '^-- ', '^-+$', '^##<<+$', '^##>>+$', '`.+\' is up to date.$', '^jittering by', '^\s*$', ].join('|') + ')' # puts pats skip_re = /#{pats}/ while gets() next if $_ =~ skip_re puts $_ end libcdio-paranoia-release-10.2-2.0.2/src/000077500000000000000000000000001461637345700175135ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/src/.gitignore000066400000000000000000000001451461637345700215030ustar00rootroot00000000000000/*.exe /*.o /.deps /.libs /Makefile /Makefile.in /cd-paranoia /*.orig /*~ /*.rej /usage.h /usage.txt libcdio-paranoia-release-10.2-2.0.2/src/Makefile.am000066400000000000000000000020731461637345700215510ustar00rootroot00000000000000# Copyright (C) 2004, 2005, 2006, 2007, 2008, # Rocky Bernstein # Copyright (C) 1998 Monty xiphmont@mit.edu # transform = s,cd-paranoia,@CDPARANOIA_NAME@, GETOPT_C = getopt1.c getopt.c EXTRA_DIST = usage.txt.in usage-copy.h pod2c.pl \ $(GETOPT_C) getopt_int.h getopt.h noinst_HEADERS = header.h report.h $(GETOPT_H) cd_paranoia_SOURCES = cd-paranoia.c \ buffering_write.c buffering_write.h \ cachetest.c cachetest.h \ header.c report.c utils.h version.h $(GETOPT_C) cd_paranoia_LDADD = $(LIBCDIO_LIBS) $(LIBCDIO_CDDA_LIBS) $(LIBCDIO_PARANOIA_LIBS) $(LTLIBICONV) cd_paranoia_DEPENDENCIES = $(LIBCDIO_DEPS) $(LIBCDIO_CDDA_LIBS) $(LIBCDIO_PARANOIA_LIBS) bin_PROGRAMS = cd-paranoia AM_CPPFLAGS = -I$(top_srcdir) $(LIBCDIO_PARANOIA_CFLAGS) $(LIBCDIO_CFLAGS) cd-paranoia.$(OBJEXT): usage.h #: create header file used in help text: the "usage" help. if HAVE_PERL usage.h: usage.txt $(srcdir)/pod2c.pl $(PERL) $(srcdir)/pod2c.pl usage.txt >usage.h else usage.h: usage-copy.h cp usage-copy.h $@ endif MOSTLYCLEANFILES = usage.h usage.txt libcdio-paranoia-release-10.2-2.0.2/src/buffering_write.c000066400000000000000000000041321461637345700230400ustar00rootroot00000000000000/* Copyright (C) 2004, 2008 Rocky Bernstein Copyright (C) 1998, 1999 Monty */ /* Eliminate teeny little writes. patch submitted by Rob Ross --Monty 19991008 */ #include #include #include #include #define OUTBUFSZ 32*1024 #include "utils.h" #include "buffering_write.h" /* GLOBALS FOR BUFFERING CALLS */ static int bw_fd = -1; static long bw_pos = 0; static char bw_outbuf[OUTBUFSZ]; static long int blocking_write(int outf, char *buffer, long num){ long int words=0,temp; while(words= 0 && bw_pos > 0) { if (blocking_write(bw_fd, bw_outbuf, bw_pos)) { perror("write (in buffering_write, flushing)"); } } bw_fd = fd; bw_pos = 0; } if (bw_pos + num > OUTBUFSZ) { /* fill our buffer first, then write, then modify buffer and num */ memcpy(&bw_outbuf[bw_pos], buffer, OUTBUFSZ - bw_pos); if (blocking_write(fd, bw_outbuf, OUTBUFSZ)) { perror("write (in buffering_write, full buffer)"); return(-1); } num -= (OUTBUFSZ - bw_pos); buffer += (OUTBUFSZ - bw_pos); bw_pos = 0; } /* save data */ if(buffer && num) memcpy(&bw_outbuf[bw_pos], buffer, num); bw_pos += num; return(0); } /** buffering_close() - writes out remaining buffered data before * closing file. * */ int buffering_close(int fd) { if (fd == bw_fd && bw_pos > 0) { /* write out remaining data and clean up */ if (blocking_write(fd, bw_outbuf, bw_pos)) { perror("write (in buffering_close)"); } bw_fd = -1; bw_pos = 0; } return(close(fd)); } libcdio-paranoia-release-10.2-2.0.2/src/buffering_write.h000066400000000000000000000007061461637345700230500ustar00rootroot00000000000000/* Copyright (C) 2004, 2008 Rocky Bernstein Copyright (C) 1998 Monty */ /** buffering_write() - buffers data to a specified size before writing. * * Restrictions: * - MUST CALL BUFFERING_CLOSE() WHEN FINISHED!!! * */ extern long buffering_write(int outf, char *buffer, long num); /** buffering_close() - writes out remaining buffered data before * closing file. * */ extern int buffering_close(int fd); libcdio-paranoia-release-10.2-2.0.2/src/cachetest.c000066400000000000000000000575121461637345700216340ustar00rootroot00000000000000/* Copyright (C) 2024 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) 2008 Monty 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 3 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, see . */ /* we can ask most drives what their various caches' sizes are, but no drive will tell if it caches redbook data. None should, many do, and there's no way in (eg) MMC/ATAPI to tell a cdrom drive not to cache when accessing audio. SCSI drives have a FUA facility, but it's not clear how many ignore it. MMC does specify some cache side effect as part of SET READ AHEAD, but it's not clear we can rely on them. For that reason, we need to empirically determine cache size and strategy used for reads. */ #include #include #include #include #include #include #include #include "cachetest.h" /* not strictly just seeks, but also recapture and read resume when reading/readahead is suspended and idling */ #define MIN_SEEK_MS 6 #define reportC(...) {if(progress){fprintf(progress, __VA_ARGS__);} \ if(log){fprintf(log, __VA_ARGS__);}} #define printC(...) {if(progress){fprintf(progress, __VA_ARGS__);}} #define logC(...) {if(log){fprintf(log, __VA_ARGS__);}} static int time_drive(cdrom_drive_t *d, FILE *progress, FILE *log, int lba, int len, int initial_seek){ int i,x; int latency=0; double sum=0; double sumsq=0; int sofar; logC("\n"); for(i=0,sofar=0;sofar9999)x=9999; if(x<0)x=0; logC("%d:%d:%d ",lba+sofar,ret,x); sofar+=ret; if(i || !initial_seek){ sum+=x; sumsq+= x*x /(float)ret; }else latency=x; } /* we count even the upper outliers because the drive is almost certainly reading ahead and that will work itself out as we keep reading to catch up. Besides-- the tests would rather see too slow a timing than too fast; the timing data is used as an optimization when sleeping. */ { double mean = sum/(float)(len-1); double stddev = sqrt( (sumsq/(float)(len-1) - mean*mean)); if(initial_seek){ printC("%4dms seek, %.2fms/sec read [%.1fx]",latency,mean,1000./75./mean); logC("\n\tInitial seek latency (%d sectors): %dms",len,latency); } logC("\n\tAverage read latency: %.2fms/sector (raw speed: %.1fx)",mean,1000./75./mean); logC("\n\tRead latency standard deviation: %.2fms/sector",stddev); return sum; } } static float retime_drive(cdrom_drive_t *d, FILE *progress, FILE *log, int lba, int readahead, float oldmean){ int sectors = 2000; int total; float newmean; if(sectors*oldmean > 5000) sectors=5000/oldmean; readahead*=10; readahead/=9; if(readahead>sectors)sectors=readahead; printC("\bo"); logC("\n\tRetiming drive... "); total = time_drive(d,NULL,log,lba,sectors,1); newmean = total/(float)sectors; logC("\n\tOld mean=%.2fms/sec, New mean=%.2fms/sec\n",oldmean,newmean); printC("\b"); if(newmean>oldmean)return newmean; return oldmean; } int analyze_cache(cdrom_drive_t *d, FILE *progress, FILE *log, int speed){ /* Some assumptions about timing: We can't perform cache determination timing based on looking at average transfer times; on slow setups, the speed of a drive reading sectors via PIO will not be reliably distinguishable from the same drive returning data from the cache via pio. We need something even more noticable and reliable: the seek time. It is unlikely we'd ever see a seek latency of under ~10ms given the synchronization requirements of a CD and the maximum possible rotational velocity. A cache hit would always be faster, even with PIO. Further complicating things, we have to watch the data collection carefully as we're not always going to be on an unloaded system, and we even have to guard against other apps accessing the drive (something that should never happen on purpose, but could happen by accident). As we know in our testing when seeks should never occur, a sudden seek-sized latency popping up in the middle of a collection is an indication that collection is possibly invalid. A second cause of 'spurious latency' would be media damage; if we're consistently hitting latency on the same sector during initial collection, may need to move past it. */ int ret=0; int i,j,x; int firstsector=-1; int lastsector=-1; int firsttest=-1; int lasttest=-1; int offset; int warn=0; int current=1000; int hi=15000; int cachesize=0; int readahead=0; int rollbehind=0; int cachegran=0; float mspersector=0; if(speed<=0)speed=-1; reportC("\n=================== Checking drive cache/timing behavior ===================\n"); d->error_retry=0; /* verify the lib and cache analysis match */ if(strcmp(LIBCDIO_PARANOIA_VERSION,paranoia_version())){ reportC("\nWARNING: cdparanoia application (and thus the cache tests) does not match the" "\ninstalled (or in use) libcdda_paranoia.so library. The final verdict of this" "\ntesting may or may not be accurate for the actual version of the paranoia" "library. Continuing anyway...\n\n"); } /* find the longest stretch of available audio data */ for(i=0;itracks;i++){ if(cdda_track_audiop(d,i+1)==1){ if(firsttest == -1) firsttest=cdda_track_firstsector(d,i+1); lasttest=cdda_track_lastsector(d,i+1); if(lasttest-firsttest > lastsector-firstsector){ firstsector=firsttest; lastsector=lasttest; } }else{ firsttest=-1; lasttest=-1; } } if(firstsector==-1){ reportC("\n\tNo audio on disc; Cannot determine timing behavior..."); return -1; } /* Dump some initial timing data to give a little context for human eyes. Take readings ten minutes apart (45000 sectors) and at end of disk. */ { int best=0; int bestcount=0; int iterating=0; offset = lastsector-firstsector-current-1; reportC("\nSeek/read timing:\n"); while(offset>=firstsector){ int m = offset/4500; int s = (offset-m*4500)/75; int f = offset-m*4500-s*75; int sofar; if(iterating){ reportC("\n"); }else{ printC("\r"); logC("\n"); } reportC("\t[%02d:%02d.%02d]: ",m,s,f); /* initial seek to put at at a small offset past end of upcoming reads */ if((ret=cdda_read(d,NULL,offset+current+1,1))<0){ /* media error! grr! retry elsewhere */ if(ret==-404)return -1; reportC("\n\tWARNING: media error during read; continuing at next offset..."); offset = (offset-firstsector+44999)/45000*45000+firstsector; offset-=45000; continue; } sofar=time_drive(d,progress, log, offset, current, 1); if(offset==firstsector)mspersector = sofar/(float)current; if(sofar==-404) return -1; else if(sofar<0){ reportC("\n\tWARNING: media error during read; continuing at next offset..."); offset = (offset-firstsector+44999)/45000*45000+firstsector; offset-=45000; continue; }else{ if(!iterating){ if(best==0 || sofar*1.01sofar && bestcount>4000) iterating=1; } } } if(iterating){ offset = (offset-firstsector+44999)/45000*45000+firstsector; offset-=45000; printC(" "); }else{ offset--; printC(" spinning up... "); } } } reportC("\n\nAnalyzing cache behavior...\n"); /* search on cache size; cache hits are fast, seeks are not, so a linear search through cache hits up to a miss are faster than a bisection */ { int under=1; int onex=0; current=0; offset = firstsector+10; while(current <= hi && under){ int i,j; under=0; current++; if(onex){ if(speed==-1){ logC("\tAttempting to reset read speed to full... "); }else{ logC("\tAttempting to reset read speed to %dx... ",speed); } if(cdda_speed_set(d,speed)){ logC("failed.\n"); }else{ logC("drive said OK\n"); } onex=0; } printC("\r"); reportC("\tFast search for approximate cache size... %d sectors ",current-1); logC("\n"); for(i=0;i<25 && !under;i++){ for(j=0;;j++){ int ret1=0,ret2=0; if(i>=15){ int sofar=0; if(i==15){ printC("\r"); reportC("\tSlow verify for approximate cache size... %d sectors",current-1); logC("\n"); logC("\tAttempting to reduce read speed to 1x... "); if(cdda_speed_set(d,1)){ logC("failed.\n"); }else{ logC("drive said OK\n"); } onex=1; } printC("."); logC("\t\t>>> "); while(sofar>> fast_read=%d:%d:%d ",offset+current-1,ret1,x); /* Some drives are 'easily distracted' when readahead is running ahead of the read cursor, causing accesses of the earliest sectors in the cache to show bursty latency. If there's no seek here after a borderline long read of the earliest sector in the cache, then the cache must not have been dumped yet. */ if (ret==1 && i && xlastsector){ reportC("\n\tToo many read errors while performing drive cache checks;" "\n\t aborting test.\n\n"); return(-1); } reportC("\n\tRead error while performing drive cache checks;" "\n\t choosing new offset and trying again.\n"); }else{ if(x==-1){ reportC("\n\tTiming error while performing drive cache checks; aborting test.\n"); return(-1); }else{ if(x paranoia_cachemodel_size(p,-1)){ reportC("\nWARNING: This drive appears to be caching more sectors of\n" " readahead than Paranoia can currently handle!\n"); warn=1; } paranoia_free(p); } if(speed==-1){ logC("\tAttempting to reset read speed to full... "); }else{ logC("\tAttempting to reset read speed to %d... ",speed); } if(cdda_speed_set(d,speed)){ logC("failed.\n"); }else{ logC("drive said OK\n"); } /* This is similar to the Fast search above, but just in case the cache is being tracked as multiple areas that are treated differently if non-contiguous.... */ { int seekoff = cachesize*3; int under=0; reportC("\tVerifying that cache is contiguous..."); for(i=0;i<20 && !under;i++){ printC("."); for(j=0;;j++){ int ret1,ret2; if(offset+seekoff>lastsector){ reportC("\n\tOut of readable space on CDROM while performing drive checks;" "\n\t aborting test.\n\n"); return(-1); } ret1 = cdda_read_timed(d,NULL,offset+seekoff,1,&x); logC("\t\t>>> %d:%d:%d ",offset+seekoff,ret1,x); ret2 = cdda_read_timed(d,NULL,offset,1,&x); logC("seek_read:%d:%d:%d\n",offset,ret2,x); if(ret1<=0 || ret2<=0){ offset+=cachesize+100; if(j==10){ reportC("\n\tToo many read errors while performing drive cache checks;" "\n\t aborting test.\n\n"); return(-1); } reportC("\n\tRead error while performing drive cache checks;" "\n\t choosing new offset and trying again.\n"); }else{ if(x==-1){ reportC("\n\tTiming error while performing drive cache checks; aborting test.\n"); return(-1); }else{ if(x1 || under){ tests++; if(tests>8 && gran<64){ gran<<=3; tests=0; it=3; } if(gran && !under){ gran>>=3; tests=0; if(gran==1)it=10; } under=0; readahead=lower+gran; printC("\r"); logC("\n"); reportC("\tTesting background readahead past read cursor... %d",readahead); printC(" \b\b\b\b\b\b\b\b\b\b\b"); for (i=0;i>> ",i); while (sofarmax)usec=max; logC("sleep=%dus ",usec); usleep(usec); } /* seek to offset+cachesize+readahead */ ret = cdda_read_timed(d,NULL,offset+cachesize+readahead-1,1,&x); if(ret<=0)break; logC("seek=%d:%d:%d",offset+cachesize+readahead-1,ret,x); if(x>> "); printC("."); while(sofar0){ sofar--; ret = cdda_read_timed(d,NULL,offset+sofar,1,&x); if(ret<=0)break; logC("%d:%d:%d ",sofar,ret,x); if(x>=MIN_SEEK_MS){ if(rollbehind != sofar+1){ rollbehind=sofar+1; i=0; }else{ i++; } break; } if(sofar==0)rollbehind=0; } error: if(ret<=0){ offset+=cachesize; retry++; if(retry>10 || offset+cachesize>lastsector){ reportC("\n\tToo many read errors while performing drive cache checks;" "\n\t aborting test.\n\n"); return(-1); } reportC("\n\tRead error while performing drive cache checks;" "\n\t choosing new offset and trying again.\n"); continue; } } /* verify that the drive timing didn't suddenly change */ { float newms=retime_drive(d, progress, log, offset, readahead, mspersector); if(newms > mspersector*1.2){ mspersector=newms; printC("\r"); reportC("\tDrive timing changed during test; retrying..."); continue; } } break; } logC("\n"); printC("\r"); if(rollbehind==0){ reportC("\tCache tail cursor tied to read cursor \n"); }else{ reportC("\tCache tail rollbehind: %d sector(s) \n",rollbehind); } reportC("\tTesting granularity of cache tail"); while(1){ cachegran=cachesize+1; for(i=0;i<10 && cachegran;){ int sofar=0,ret=0,retry=0; logC("\n\t\t>>> "); printC("."); while(sofar=MIN_SEEK_MS){ if(cachegran == sofar+1){ i++; }else{ cachegran=sofar+1; i=0; } break; } if(sofar==0)cachegran=0; } error2: if(ret<=0){ offset+=cachesize; retry++; if(retry>10 || offset+cachesize>lastsector){ reportC("\n\tToo many read errors while performing drive cache checks;" "\n\t aborting test.\n\n"); return(-1); } reportC("\n\tRead error while performing drive cache checks;" "\n\t choosing new offset and trying again.\n"); continue; } } /* verify that the drive timing didn't suddenly change */ { float newms=retime_drive(d, progress, log, offset, readahead, mspersector); if(newms > mspersector*1.2){ mspersector=newms; printC("\r"); reportC("\tDrive timing changed during test; retrying..."); continue; } } break; } cachegran -= rollbehind; logC("\n"); printC("\r"); reportC("\tCache tail granularity: %d sector(s) \n",cachegran); /* Verify that a read that begins before the cached readahead dumps the entire readahead cache */ /* This is tricky because we can't simply read a one sector back seek, then rely on timing/seeking of subsequent sectors; the drive may well not seek ahead if reading linearly would be faster (and it often will be), and simply reading ahead after the seek and watching timing will be inaccurate because the drive may roll some readahead into the initial seek/read before returning the first block. */ /* we will need to use the timing of reading from media in one form or another and thus need to guard against slow bus transfer times [eg, no DMA] swamping the actual read time from media. */ /* sample cache access for five realtime seconds. */ { float cachems; float readms; int readsize = cachesize-rollbehind-8; int retry=0; if(readsize>cachesize-1)readsize=cachesize-1; if(readsize<7){ reportC("\tCache size (considering rollbehind) too small to test cache speed.\n"); }else{ reportC("\tTesting cache transfer speed..."); /* cache timing isn't dependent on rotational speed, so get a good read and then just hammer the cache; we will only need to do it once */ /* we need to time the cache using the most conservative possible read pattern; many drives will flush cache on *any* nonlinear access, but not if the read starts from the same point. The original cache size verification algo knows this, and we need to do it the same way here (this the '0' for 'initial_seek' on time_drve */ while(1){ int ret=time_drive(d, NULL, log, offset, readsize, 0); if(ret==-404) return -1; if(ret>0)break; retry++; if(retry==10){ reportC("\n\tToo many read errors while performing drive cache checks;" "\n\t aborting test.\n\n"); return(-1); } reportC("\n\tRead error while performing drive cache checks;" "\n\t choosing new offset and trying again.\n"); } { int elapsed=0; int sectors=0; int spinner=0; while(elapsed<5000){ sectors += readsize; elapsed += time_drive(d, NULL, log, offset, readsize, 0); spinner = elapsed*5/1000%4; printC("\b%c",(spinner==0?'o':(spinner==1?'O':(spinner==2?'o':'.')))); } printC("\r"); logC("\n"); cachems = elapsed/(float)sectors; reportC("\t Cache read speed: %.2fms/sector [%dx]\n", cachems,(int)(1000./75./cachems)); } if(cachems*3>mspersector){ reportC("\tCache access insufficiently faster than media access to\n" "\t\tperform cache backseek tests\n\n"); }else{ /* now do the read/backseek combo */ reportC("\tTesting that backseek flushes cache..."); { int total=0; int elapsed=0; int sectors=0; int spinner=0; int retry=0; while(elapsed<5000 && total<25){ /* don't kill the drive */ int ret; while(1){ /* need to force seek/flush, but don't kill the drive */ int seekpos = offset+cachesize+20000; if(seekpos>lastsector-150)seekpos=lastsector-150; ret=cdda_read(d, NULL, seekpos, 1); if(ret>0) ret=time_drive(d, NULL, log, offset+1, readsize, 1); if(ret>=0) ret=time_drive(d, NULL, log, offset, readsize, 1); if(ret<=0){ retry++; if(retry==10){ reportC("\n\tToo many read errors while performing drive cache checks;" "\n\t aborting test.\n\n"); return(-1); } reportC("\n\tRead error while performing drive cache checks; retrying..."); }else break; } sectors += (readsize-1); elapsed += ret; total++; spinner = elapsed*5/1000%4; printC("\b%c",(spinner==0?'o':(spinner==1?'O':(spinner==2?'o':'.')))); } printC("\r"); logC("\n"); readms = elapsed/(float)sectors; reportC("\t Access speed after backseek: %.2fms/sector [%dx]\n", readms,(int)(1000./75./readms)); if(readms*2. < mspersector || cachems*2. > readms){ reportC("\tWARNING: Read timing after backseek faster than expected!\n" "\t It's possible/likely that this drive is not\n" "\t flushing the readahead cache on backward seeks!\n\n"); warn=1; }else{ reportC("\tBackseek flushes the cache as expected\n"); } } } } } return warn; } libcdio-paranoia-release-10.2-2.0.2/src/cachetest.h000066400000000000000000000003741461637345700216330ustar00rootroot00000000000000/* Copyright (C) 2014 Robert Kausch Copyright (C) 2008 Monty */ /** analyze_cache() - analyze drive cache management. */ extern int analyze_cache(cdrom_drive_t *d, FILE *progress, FILE *log, int speed); libcdio-paranoia-release-10.2-2.0.2/src/cd-paranoia.c000066400000000000000000001323431461637345700220430ustar00rootroot00000000000000/* Copyright (C) 2004-2012, 2014-2015, 2017 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) 1998 Monty 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 3 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, see . See ChangeLog for recent changes. */ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDARG_H # include #endif #ifdef HAVE_LIMITS_H #include #endif #ifndef PATH_MAX # ifdef MAXPATHLEN # define PATH_MAX MAXPATHLEN # else # define PATH_MAX 4096 # endif #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_FCNTL_H #include #endif #include "getopt.h" #ifdef HAVE_ERRNO_H #include #endif #ifndef ENOMEDIUM #define ENOMEDIUM -1 #endif #include #include #ifdef HAVE_SYS_STAT_H # include #endif #if !defined(HAVE_GETTIMEOFDAY) /* MinGW uses sys/time.h and sys/timeb.h to roll its own gettimeofday() */ # if defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_TIMEB_H) # include # include static void gettimeofday(struct timeval* tv, void* timezone); # endif #endif /* !defined(HAVE_GETTIMEOFDAY) */ #include #include #include #include #include #include #include "utils.h" #include "report.h" #include "version.h" #include "header.h" #include "buffering_write.h" #include "cachetest.h" #ifndef O_BINARY #define O_BINARY 0 #endif /* I wonder how many alignment issues this is gonna trip in the future... it shouldn't trip any... I guess we'll find out :) */ static int bigendianp(void) { int test=1; char *hack=(char *)(&test); if(hack[0])return(0); return(1); } static long parse_offset(cdrom_drive_t *d, char *offset, int begin) { track_t i_track= CDIO_INVALID_TRACK; long hours = -1; long minutes = -1; long seconds = -1; long sectors = -1; char *time = NULL; char *temp = NULL; long ret; if (!offset) return -1; /* separate track from time offset */ temp=strchr(offset,']'); if(temp){ *temp='\0'; temp=strchr(offset,'['); if(temp==NULL){ report("Error parsing span argument"); exit(1); } *temp='\0'; time=temp+1; } /* parse track */ { int chars=strspn(offset,"0123456789"); if(chars>0){ offset[chars]='\0'; i_track=atoi(offset); if (i_track >= cdio_get_first_track_num(d->p_cdio) + d->tracks) { /*take track i_first_track-1 as pre-gap of 1st track*/ report("Track #%d does not exist.",i_track); exit(1); } } } while(time){ long val,chars; char *sec=strrchr(time,'.'); if(!sec)sec=strrchr(time,':'); if(!sec)sec=time-1; chars=strspn(sec+1,"0123456789"); if(chars) val=atoi(sec+1); else val=0; switch(*sec){ case '.': if(sectors!=-1){ report("Error parsing span argument"); exit(1); } sectors=val; break; default: if(seconds==-1) seconds=val; else if(minutes==-1) minutes=val; else if(hours==-1) hours=val; else{ report("Error parsing span argument"); exit(1); } break; } if (sec<=time) break; *sec='\0'; } if (i_track == CDIO_INVALID_TRACK) { if (seconds==-1 && sectors==-1) return -1; if (begin==-1) { ret=cdda_disc_firstsector(d); } else ret = begin; } else { if ( seconds==-1 && sectors==-1 ) { if (begin==-1){ /* first half of a span */ return(cdda_track_firstsector(d, i_track)); }else{ return(cdda_track_lastsector(d, i_track)); } } else { /* relative offset into a track */ ret=cdda_track_firstsector(d, i_track); } } /* OK, we had some sort of offset into a track */ if (sectors != -1) ret += sectors; if (seconds != -1) ret += seconds*CDIO_CD_FRAMES_PER_SEC; if (minutes != -1) ret += minutes*CDIO_CD_FRAMES_PER_MIN; if (hours != -1) ret += hours *60*CDIO_CD_FRAMES_PER_MIN; /* We don't want to outside of the track; if it's relative, that's OK... */ if( i_track != CDIO_INVALID_TRACK ){ if (cdda_sector_gettrack(d,ret) != i_track) { report("Time/sector offset goes beyond end of specified track."); exit(1); } } /* Don't pass up end of session */ if( ret>cdda_disc_lastsector(d) ) { report("Time/sector offset goes beyond end of disc."); exit(1); } return(ret); } static void display_toc(cdrom_drive_t *d) { long audiolen=0; track_t i; report("\nTable of contents (audio tracks only):\n" "track length begin copy pre ch\n" "==========================================================="); for( i=cdio_get_first_track_num(d->p_cdio); i<=cdio_get_last_track_num(d->p_cdio); i++) if ( cdda_track_audiop(d,i) > 0 ) { lsn_t sec=cdda_track_firstsector(d,i); lsn_t off=cdda_track_lastsector(d,i)-sec+1; report("%3d. %7ld [%02d:%02d.%02d] %7ld [%02d:%02d.%02d] %s %s %s", i, (long int) off, (int) (off/(CDIO_CD_FRAMES_PER_MIN)), (int) ((off/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN), (int) (off % CDIO_CD_FRAMES_PER_SEC), (long int) sec, (int) (sec/(CDIO_CD_FRAMES_PER_MIN)), (int) ((sec/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN), (int) (sec % CDIO_CD_FRAMES_PER_SEC), cdda_track_copyp(d,i)?" OK":" no", cdda_track_preemp(d,i)?" yes":" no", cdda_track_channels(d,i)==2?" 2":" 4"); audiolen+=off; } report("TOTAL %7ld [%02d:%02d.%02d] (audio only)", audiolen, (int) (audiolen/(CDIO_CD_FRAMES_PER_MIN)), (int) ((audiolen/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN), (int) (audiolen % CDIO_CD_FRAMES_PER_SEC)); report(" "); } #include "usage.h" static void usage(FILE *f) { fprintf( f, usage_help); } static long callbegin; static long callend; static long callscript=0; static int skipped_flag=0; static int abort_on_skip=0; static FILE *logfile = NULL; static int logfile_open=0; static int reportfile_open=0; #if TRACE_PARANOIA static void callback(long int inpos, paranoia_cb_mode_t function) { } #else static const char *callback_strings[16]={ "read", "verify", "jitter", "correction", "scratch", "scratch repair", "skip", "drift", "backoff", "overlap", "dropped", "duped", "transport error", "cache error", "wrote", "finished", }; static void callback(long int inpos, paranoia_cb_mode_t function) { /* (== PROGRESS == [--+!---x--------------> | 007218 01 ] == :-) . ==) */ int graph=30; char buffer[256]; static long c_sector=0, v_sector=0; static char dispcache[]=" "; static int last=0; static long lasttime=0; long int sector, osector=0; struct timeval thistime; static char heartbeat=' '; int position=0,aheadposition=0; static int overlap=0; static int printit=-1; static int slevel=0; static int slast=0; static int stimeout=0; static int cacheerr=0; const char *smilie="= :-)"; if (callscript) fprintf(stderr, "##: %d [%s] @ %ld\n", function, ((int) function >= 0 && (int) function < 16 ? callback_strings[function] : ""), inpos); else{ if(function==PARANOIA_CB_CACHEERR){ if(!cacheerr){ fprintf(stderr, "\rWARNING: The CDROM drive appears to be seeking impossibly quickly.\n" "This could be due to timer bugs, a drive that really is improbably fast,\n" "or, most likely, a bug in cdparanoia's cache modelling.\n\n" "Please consider using the -A option to perform an analysis run, then mail\n" "the cdparanoia.log file produced by the analysis to paranoia-dev@xiph.org\n" "to assist developers in correcting the problem.\n\n"); } cacheerr++; } } if(!quiet){ long test; osector=inpos; sector=inpos/CD_FRAMEWORDS; if(printit==-1){ if(isatty(STDERR_FILENO) || (logfile != NULL)){ printit=1; }else{ printit=0; } } if(printit==1){ /* else don't bother; it's probably being redirected */ position=((float)(sector-callbegin)/ (callend-callbegin))*graph; aheadposition=((float)(c_sector-callbegin)/ (callend-callbegin))*graph; if(function == PARANOIA_CB_WROTE){ v_sector=sector; return; } if (function == PARANOIA_CB_FINISHED) { last=8; heartbeat='*'; slevel=0; v_sector=sector; } else if(position=0) switch(function){ case PARANOIA_CB_VERIFY: if(stimeout>=30){ if(overlap>CD_FRAMEWORDS) slevel=2; else slevel=1; } break; case PARANOIA_CB_READ: if(sector>c_sector)c_sector=sector; break; case PARANOIA_CB_FIXUP_EDGE: if(stimeout>=5){ if(overlap>CD_FRAMEWORDS) slevel=2; else slevel=1; } if(dispcache[position]==' ') dispcache[position]='-'; break; case PARANOIA_CB_FIXUP_ATOM: if(slevel<3 || stimeout>5)slevel=3; if(dispcache[position]==' ' || dispcache[position]=='-') dispcache[position]='+'; break; case PARANOIA_CB_READERR: slevel=6; if(dispcache[position]!='V' && dispcache[position]!='C') dispcache[position]='e'; break; case PARANOIA_CB_CACHEERR: slevel=8; dispcache[position]='C'; break; case PARANOIA_CB_SKIP: slevel=8; if(dispcache[position]!='C') dispcache[position]='V'; break; case PARANOIA_CB_OVERLAP: overlap=osector; break; case PARANOIA_CB_SCRATCH: slevel=7; break; case PARANOIA_CB_DRIFT: if(slevel<4 || stimeout>5)slevel=4; break; case PARANOIA_CB_FIXUP_DROPPED: case PARANOIA_CB_FIXUP_DUPED: slevel=5; if(dispcache[position]==' ' || dispcache[position]=='-' || dispcache[position]=='+') dispcache[position]='!'; break; case PARANOIA_CB_REPAIR: case PARANOIA_CB_BACKOFF: break; case PARANOIA_CB_WROTE: case PARANOIA_CB_FINISHED: /* Handled above */ ; } switch(slevel){ case 0: /* finished, or no jitter */ if(skipped_flag) smilie=" 8-X"; else smilie=" :^D"; break; case 1: /* normal. no atom, low jitter */ smilie=" :-)"; break; case 2: /* normal, overlap > 1 */ smilie=" :-|"; break; case 4: /* drift */ smilie=" :-/"; break; case 3: /* unreported loss of streaming */ smilie=" :-P"; break; case 5: /* dropped/duped bytes */ smilie=" 8-|"; break; case 6: /* scsi error */ smilie=" :-0"; break; case 7: /* scratch */ smilie=" :-("; break; case 8: /* skip */ smilie=" ;-("; skipped_flag=1; break; } gettimeofday(&thistime,NULL); test=thistime.tv_sec*10+thistime.tv_usec/100000; if (lasttime!=test || function == PARANOIA_CB_FINISHED || slast!=slevel ) { if (lasttime!=test || function == PARANOIA_CB_FINISHED) { last++; lasttime=test; if(last>7)last=0; stimeout++; switch(last){ case 0: heartbeat=' '; break; case 1:case 7: heartbeat='.'; break; case 2:case 6: heartbeat='o'; break; case 3:case 5: heartbeat='0'; break; case 4: heartbeat='O'; break; } if(function == PARANOIA_CB_FINISHED) heartbeat='*'; } if(slast!=slevel){ stimeout=0; } slast=slevel; if (abort_on_skip && skipped_flag && function != PARANOIA_CB_FINISHED ) { sprintf(buffer, "\r (== PROGRESS == [%s| %06ld %02d ] ==%s %c ==) ", " ...aborting; please wait... ", v_sector,overlap/CD_FRAMEWORDS,smilie,heartbeat); }else{ if(v_sector==0) sprintf(buffer, "\r (== PROGRESS == [%s| ...... %02d ] ==%s %c ==) ", dispcache,overlap/CD_FRAMEWORDS,smilie,heartbeat); else sprintf(buffer, "\r (== PROGRESS == [%s| %06ld %02d ] ==%s %c ==) ", dispcache,v_sector,overlap/CD_FRAMEWORDS,smilie,heartbeat); if ( aheadposition>=0 && aheadpositiontv_sec=timebuffer.time; tv->tv_usec=1000*timebuffer.millitm; } #endif /* This is run automatically before leaving the program. Free allocated resources. */ static void cleanup (void) { if (p) paranoia_free(p); if (d) cdda_close(d); free_and_null(force_cdrom_device); free_and_null(span); if(logfile_open) { fclose(logfile); logfile = NULL; } if(reportfile_open) { fclose(reportfile); reportfile = NULL; } } /* Returns true if we have an integer argument. If so, pi_arg is set. If no argument or integer argument found, we give an error message and return false. */ static bool get_int_arg(char c, long int *pi_arg) { long int i_arg; char *p_end; if (!optarg) { /* This shouldn't happen, but we'll check anyway. */ fprintf(stderr, "An (integer) argument for option -%c was expected " " but not found. Option ignored\n", c); return false; } errno = 0; i_arg = strtol(optarg, &p_end, 10); if ( (LONG_MIN == i_arg || LONG_MAX == i_arg) && (0 != errno) ) { fprintf(stderr, "Value '%s' for option -%c out of range. Value %ld " "used instead.\n", optarg, c, i_arg); *pi_arg = i_arg; return false; } else if (*p_end) { fprintf(stderr, "Can't convert '%s' for option -%c completely into an integer. " "Option ignored.\n", optarg, c); return false; } else { *pi_arg = i_arg; return true; } } int main(int argc,char *argv[]) { int toc_bias = 0; int force_cdrom_endian = -1; int output_type = 1; /* 0=raw, 1=wav, 2=aifc */ int output_endian = 0; /* -1=host, 0=little, 1=big */ int query_only = 0; int batch = 0; int run_cache_test = 0; long int force_cdrom_overlap = -1; long int force_cdrom_sectors = -1; long int force_cdrom_speed = 0; long int force_overread = 0; long int sample_offset = 0; long int test_flags = 0; long int toc_offset = 0; long int max_retries = 20; char *logfile_name=NULL; char *reportfile_name=NULL; /* full paranoia, but allow skipping */ int paranoia_mode=PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP; int out; int c,long_option_index; atexit(cleanup); while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){ switch(c){ case 'a': output_type=2; output_endian=1; break; case 'B': batch=1; break; case 'c': force_cdrom_endian=0; break; case 'C': force_cdrom_endian=1; break; case 'e': callscript=1; fprintf(stderr, "Sending all callback output to stderr for wrapper script\n"); break; case 'f': output_type=3; output_endian=1; break; case 'F': paranoia_mode&=~(PARANOIA_MODE_FRAGMENT); break; case 'g': case 'k': case 'd': if (force_cdrom_device) { fprintf(stderr, "Multiple cdrom devices given. Previous device %s ignored\n", force_cdrom_device); free(force_cdrom_device); } force_cdrom_device=strdup(optarg); break; case 'h': usage(stdout); exit(0); case 'l': if(logfile_name)free(logfile_name); logfile_name=NULL; if(optarg) logfile_name=strdup(optarg); logfile_open=1; break; case 'L': if(reportfile_name)free(reportfile_name); reportfile_name=NULL; if(optarg) reportfile_name=strdup(optarg); reportfile_open=1; break; case 'm': { long int mmc_timeout_sec; if (get_int_arg(c, &mmc_timeout_sec)) { mmc_timeout_ms = 1000*mmc_timeout_sec; } } break; case 'n': get_int_arg(c, &force_cdrom_sectors); break; case 'o': get_int_arg(c, &force_cdrom_overlap); break; case 'O': get_int_arg(c, &sample_offset); break; case 'p': output_type=0; output_endian=-1; break; case 'r': output_type=0; output_endian=0; break; case 'q': verbose=CDDA_MESSAGE_FORGETIT; quiet=1; break; case 'Q': query_only=1; break; case 'R': output_type=0; output_endian=1; break; case 'S': get_int_arg(c, &force_cdrom_speed); break; case 't': get_int_arg(c, &toc_offset); break; case 'T': toc_bias=-1; break; case 'v': verbose=CDDA_MESSAGE_PRINTIT; quiet=0; break; case 'V': fprintf(stderr,PARANOIA_VERSION); fprintf(stderr,"\n"); exit(0); break; case 'w': output_type=1; output_endian=0; break; case 'W': paranoia_mode&=~PARANOIA_MODE_REPAIR; break; case 'x': get_int_arg(c, &test_flags); break; case 'X': /*paranoia_mode&=~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);*/ abort_on_skip=1; break; case 'Y': paranoia_mode|=PARANOIA_MODE_OVERLAP; /* cdda2wav style overlap check only */ paranoia_mode&=~PARANOIA_MODE_VERIFY; break; case 'Z': paranoia_mode=PARANOIA_MODE_DISABLE; break; case 'A': run_cache_test=1; query_only=1; reportfile_open=1; verbose=CDDA_MESSAGE_PRINTIT; break; case 'z': if (optarg) { get_int_arg(c, &max_retries); paranoia_mode&=~PARANOIA_MODE_NEVERSKIP; } else { paranoia_mode|=PARANOIA_MODE_NEVERSKIP; } break; case 'E': force_overread=1; break; default: usage(stderr); exit(1); } } if(logfile_open){ if(logfile_name==NULL) logfile_name=strdup("cdparanoia.log"); if(!strcmp(logfile_name,"-")){ logfile=stdout; logfile_open=0; }else{ logfile=fopen(logfile_name,"w"); if(logfile==NULL){ report("Cannot open log summary file %s: %s",logfile_name, strerror(errno)); exit(1); } } } if(reportfile_open){ if(reportfile_name==NULL) reportfile_name=strdup("cdparanoia.log"); if(!strcmp(reportfile_name,"-")){ reportfile=stdout; reportfile_open=0; }else{ if(logfile_name && !strcmp(reportfile_name,logfile_name)){ reportfile=logfile; reportfile_open=0; }else{ reportfile=fopen(reportfile_name,"w"); if(reportfile==NULL){ report("Cannot open debug log file %s: %s",reportfile_name, strerror(errno)); exit(1); } } } } if(logfile){ /* log command line and version */ int i; for (i = 0; i < argc; i++) fprintf(logfile,"%s ",argv[i]); fprintf(logfile,"\n"); if(reportfile!=logfile){ fprintf(logfile,VERSION); fprintf(logfile,"\n"); fprintf(logfile,"Using cdda library version: %s\n",cdda_version()); fprintf(logfile,"Using paranoia library version: %s\n",paranoia_version()); } fflush(logfile); } if(reportfile && reportfile!=logfile){ /* log command line */ int i; for (i = 0; i < argc; i++) fprintf(reportfile,"%s ",argv[i]); fprintf(reportfile,"\n"); fflush(reportfile); } if(optind>=argc && !query_only){ if(batch) span=NULL; else{ /* D'oh. No span. Fetch me a brain, Igor. */ usage(stderr); exit(1); } }else if (argv[optind]) span=strdup(argv[optind]); report(PARANOIA_VERSION); if(verbose){ report("Using cdda library version: %s",cdda_version()); report("Using paranoia library version: %s",paranoia_version()); } /* Query the cdrom/disc; we may need to override some settings */ if(force_cdrom_device) d=cdda_identify(force_cdrom_device,verbose,NULL); else { driver_id_t driver_id; char **ppsz_cd_drives = cdio_get_devices_with_cap_ret(NULL, CDIO_FS_AUDIO, false, &driver_id); if (ppsz_cd_drives && *ppsz_cd_drives) { d=cdda_identify(*ppsz_cd_drives,verbose, NULL); } else { report("\nUnable find or access a CD-ROM drive with an audio CD" " in it."); report("\nYou might try specifying the drive, especially if it has" " mixed-mode (and non-audio) format tracks"); exit(1); } cdio_free_device_list(ppsz_cd_drives); } if(!d){ if(!verbose) report("\nUnable to open cdrom drive; -v might give more information."); exit(1); } if(verbose) cdda_verbose_set(d,CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_PRINTIT); else cdda_verbose_set(d,CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_FORGETIT); /* possibly force hand on endianness of drive, sector request size */ if(force_cdrom_endian!=-1){ d->bigendianp=force_cdrom_endian; switch(force_cdrom_endian){ case 0: report("Forcing CDROM sense to little-endian; ignoring preset and autosense"); break; case 1: report("Forcing CDROM sense to big-endian; ignoring preset and autosense"); break; } } if (force_cdrom_sectors!=-1) { if(force_cdrom_sectors<0 || force_cdrom_sectors>100){ report("Default sector read size must be 1<= n <= 100\n"); cdda_close(d); d=NULL; exit(1); } report("Forcing default to read %ld sectors; " "ignoring preset and autosense",force_cdrom_sectors); d->nsectors=force_cdrom_sectors; } if (force_cdrom_overlap!=-1) { if (force_cdrom_overlap<0 || force_cdrom_overlap>CDIO_CD_FRAMES_PER_SEC) { report("Search overlap sectors must be 0<= n <=75\n"); cdda_close(d); d=NULL; if(logfile && logfile != stdout) fclose(logfile); exit(1); } report("Forcing search overlap to %ld sectors; " "ignoring autosense",force_cdrom_overlap); } switch( cdda_open(d) ) { case -2:case -3:case -4:case -5: report("\nUnable to open disc. Is there an audio CD in the drive?"); exit(1); case -6: report("\nCdparanoia could not find a way to read audio from this drive."); exit(1); case 0: break; default: report("\nUnable to open disc."); exit(1); } d->i_test_flags = test_flags; if (force_cdrom_speed == 0) force_cdrom_speed = -1; if (force_cdrom_speed != -1) { report("\nAttempting to set speed to %ldx... ", force_cdrom_speed); } else { if (verbose) report("\nAttempting to set cdrom to full speed... "); } if (cdda_speed_set(d, force_cdrom_speed)) { if (verbose || force_cdrom_speed != -1) report("\tCDROM speed set FAILED. Continuing anyway..."); } else { if (verbose) report("\tdrive returned OK."); } if(run_cache_test){ int warn=analyze_cache(d, stderr, reportfile, force_cdrom_speed); if(warn==0){ reportC("\nDrive tests OK with Paranoia.\n\n"); return 0; } if(warn==1) reportC("\nWARNING! PARANOIA MAY NOT BE TRUSTWORTHY WITH THIS DRIVE!\n" "\nThe Paranoia library may not model this CDROM drive's cache" "\ncorrectly according to this analysis run. Analysis is not" "\nalways accurate (it can be fooled by machine load or random" "\nkernel latencies), but if a failed result happens more often" "\nthan one time in twenty on an unloaded machine, please mail" "\nthe %s file produced by this failed analysis to" "\nparanoia-dev@xiph.org to assist developers in extending" "\nParanoia to handle this CDROM properly.\n\n",reportfile_name); return 1; } /* Dump the TOC */ if (query_only || verbose ) display_toc(d); if (query_only) exit(0); /* Nearly all CD-ROM/CD-R drives will add a sample offset (either positive or negative) to the position when reading audio data. This is usually around 500-700 audio samples (ca. 1/75 second) but can consist of multiple sectors for some drives. To account for this, the --sample-offset option can be specified to adjust for a drive's read offset by a given number of samples. In doing so, the exact data desired can be retrieved, assuming the proper offset is specified for a given drive. An audio CD sector is 2352 bytes in size, consisting of 1176 16-bit (2-byte) samples or 588 paris of samples (left and right channels). Therefore, every 588 samples of offset required for a given drive will necesitate shifting reads by N sectors and by M samples (assuming the sample offset is not an exact multiple of 588). For example: --sample-offset 0 (default) results in a sector offset of 0 and a sample offset of 0 --sample-offset +48 results in a sector offset of 0 and a sample offset of 48 --sample-offset +667 results in a sector offset of 1 and a sample offset of 79 --sample-offset +1776 results in a sector offset of 3 and a sample offset of 12 --sample-offset -54 results in a sector offset of -1 and a sample offset of 534 --sample-offset -589 results in a sector offset of -2 and a sample offset of 587 --sample-offset -1164 results in a sector offset of -2 and a sample offset of 12 toc_offset - accounts for the number of sectors to offset reads sample_offset - accounts for the number of samples to shift the results Note that if ripping includes the end of the CD and the --force-overread option is specified, this program will attempt to read partial sectors before or past the known user data area of the disc. The drive must suppport this or it will probably cause read errors on most drives and possibly even hard lockups on some buggy hardware. If the --force-overread is not provided, tracks will be padded with empty data rather than attempting to read beyond the disk lead-in/lead-out. For more info, see: - https://www.exactaudiocopy.de/en/index.php/support/faq/offset-questions/ - https://wiki.hydrogenaud.io/index.php?title=AccurateRip#Drive_read_offsets [Note to libcdio driver hackers: make sure all CD-drivers don't try to read outside of the stated disc boundaries.] */ if(sample_offset){ toc_offset+=sample_offset/588; sample_offset%=588; if(sample_offset<0){ sample_offset+=588; toc_offset--; } } if (toc_bias) { toc_offset = -cdda_track_firstsector(d,1); } if (d->nsectors==1) { report("WARNING: The autosensed/selected sectors per read value is\n" " one sector, making it very unlikely Paranoia can \n" " work.\n\n" " Attempting to continue...\n\n"); } /* parse the span, set up begin and end sectors */ { long i_first_lsn; long i_last_lsn; long batch_first; long batch_last; int batch_track; if (span) { /* look for the hyphen */ char *span2=strchr(span,'-'); if(strrchr(span,'-')!=span2){ report("Error parsing span argument"); exit(1); } if (span2!=NULL) { *span2='\0'; span2++; } i_first_lsn=parse_offset(d, span, -1); if(i_first_lsn==-1) i_last_lsn=parse_offset(d, span2, cdda_disc_firstsector(d)); else i_last_lsn=parse_offset(d, span2, i_first_lsn); if (i_first_lsn == -1) { if (i_last_lsn == -1) { report("Error parsing span argument"); exit(1); } else { i_first_lsn=cdda_disc_firstsector(d); } } else { if (i_last_lsn==-1) { if (span2) { /* There was a hyphen */ i_last_lsn=cdda_disc_lastsector(d); } else { i_last_lsn= cdda_track_lastsector(d,cdda_sector_gettrack(d, i_first_lsn)); } } } } else { i_first_lsn = cdda_disc_firstsector(d); i_last_lsn = cdda_disc_lastsector(d); } { /* Check for errors on lsn before getting track */ if(i_first_lsn < 0){ report("Error on begin of span: %li. Aborting.\n\n", i_first_lsn); exit(1); } if(i_last_lsn < 0 ){ report("Error on end of span: %li. Aborting.\n\n", i_last_lsn); exit(1); } int track1 = cdda_sector_gettrack(d, i_first_lsn); int track2 = cdda_sector_gettrack(d, i_last_lsn); int i; for( i=track1; i<=track2; i++ ) { if(i != 0 && !cdda_track_audiop(d,i)){ report("Selected span contains non audio track at track %02d. Aborting.\n\n", i); exit(1); } } long off1 = i_first_lsn - cdda_track_firstsector(d, track1); long off2 = i_last_lsn - cdda_track_firstsector(d, track2); report("Ripping from sector %7ld (track %2d [%d:%02d.%02d])\n" "\t to sector %7ld (track %2d [%d:%02d.%02d])\n", i_first_lsn, track1, (int) (off1/(CDIO_CD_FRAMES_PER_MIN)), (int) ((off1/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN), (int)(off1 % CDIO_CD_FRAMES_PER_SEC), i_last_lsn, track2, (int) (off2/(CDIO_CD_FRAMES_PER_MIN)), (int) ((off2/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN), (int)(off2 % CDIO_CD_FRAMES_PER_SEC)); } /* Apply read sector offset to the first and last sector indicies. If the option has not been given to force overreading, do not offset the last sector index beyond the last sector of the final track. */ i_first_lsn += toc_offset; lsn_t lasttrack_lastsector = cdda_track_lastsector(d, d->tracks); if (!force_overread && i_last_lsn + toc_offset >= lasttrack_lastsector) i_last_lsn = lasttrack_lastsector; else i_last_lsn += toc_offset; { long cursor; int16_t offset_buffer[1176]; int offset_buffer_used=0; int offset_skip=sample_offset*4; off_t sectorlen; #if defined(HAVE_GETUID) && (defined(HAVE_SETEUID) || defined(HAVE_SETEGID)) int dummy __attribute__((unused)); #endif p=paranoia_init(d); paranoia_modeset(p,paranoia_mode); if(force_cdrom_overlap!=-1)paranoia_overlapset(p,force_cdrom_overlap); if(verbose) { cdda_verbose_set(d,CDDA_MESSAGE_LOGIT,CDDA_MESSAGE_LOGIT); cdio_loglevel_default = CDIO_LOG_INFO; } else cdda_verbose_set(d,CDDA_MESSAGE_FORGETIT,CDDA_MESSAGE_FORGETIT); paranoia_seek(p,cursor=i_first_lsn,SEEK_SET); /* this is probably a good idea in general */ #if defined(HAVE_GETUID) && defined(HAVE_SETEUID) dummy = seteuid(getuid()); #endif #if defined(HAVE_GETGID) && defined(HAVE_SETEGID) dummy = setegid(getgid()); #endif while(cursor<=i_last_lsn){ char outfile_name[PATH_MAX]; if ( batch ){ batch_first = cursor; batch_track = cdda_sector_gettrack(d,cursor - toc_offset); batch_last = cdda_track_lastsector(d, batch_track) + toc_offset; if (batch_last>i_last_lsn) batch_last=i_last_lsn; } else { batch_first = i_first_lsn; batch_last = i_last_lsn; batch_track = -1; } callbegin=batch_first; callend=batch_last; /* argv[optind] is the span, argv[optind+1] (if exists) is outfile */ if (optind+1= PATH_MAX){ report("Output filename too long"); exit(1); } if(basename[0]=='\0'){ switch (output_type) { case 0: /* raw */ strncat(outfile_name, "cdda.raw", PATH_MAX - strlen(outfile_name) - 1); break; case 1: strncat(outfile_name, "cdda.wav", PATH_MAX - strlen(outfile_name) - 1); break; case 2: strncat(outfile_name, "cdda.aifc", PATH_MAX - strlen(outfile_name) - 1); break; case 3: strncat(outfile_name, "cdda.aiff", PATH_MAX - strlen(outfile_name) - 1); break; } } out=open(outfile_name,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,0666); if(out==-1){ report("Cannot open specified output file %s: %s", outfile_name, strerror(errno)); exit(1); } report("outputting to %s\n", outfile_name); if(logfile){ fprintf(logfile,"outputting to %s\n",outfile_name); fflush(logfile); } } } else { /* default */ if (batch) sprintf(outfile_name,"track%02d.", batch_track); else outfile_name[0]='\0'; switch(output_type){ case 0: /* raw */ strncat(outfile_name, "cdda.raw", PATH_MAX - strlen(outfile_name) - 1); break; case 1: strncat(outfile_name, "cdda.wav", PATH_MAX - strlen(outfile_name) - 1); break; case 2: strncat(outfile_name, "cdda.aifc", PATH_MAX - strlen(outfile_name) - 1); break; case 3: strncat(outfile_name, "cdda.aiff", PATH_MAX - strlen(outfile_name) - 1); break; } out = open(outfile_name, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); if(out==-1){ report("Cannot open default output file %s: %s", outfile_name, strerror(errno)); exit(1); } report("outputting to %s\n", outfile_name); if(logfile){ fprintf(logfile,"outputting to %s\n",outfile_name); fflush(logfile); } } sectorlen = batch_last - batch_first + 1; if (cdda_sector_gettrack(d, cursor - toc_offset) == d->tracks && toc_offset > 0 && !force_overread){ sectorlen += toc_offset; } switch(output_type) { case 0: /* raw */ break; case 1: /* wav */ WriteWav(out, sectorlen * CD_FRAMESIZE_RAW); break; case 2: /* aifc */ WriteAifc(out, sectorlen * CD_FRAMESIZE_RAW); break; case 3: /* aiff */ WriteAiff(out, sectorlen * CD_FRAMESIZE_RAW); break; } /* Off we go! */ if(offset_buffer_used){ /* partial sector from previous batch read */ cursor++; if (buffering_write(out, ((char *)offset_buffer)+offset_buffer_used, CDIO_CD_FRAMESIZE_RAW-offset_buffer_used)){ report("Error writing output: %s", strerror(errno)); exit(1); } } skipped_flag=0; while(cursor<=batch_last){ /* read a sector */ int16_t *readbuf=paranoia_read_limited(p, callback, max_retries); char *err=cdda_errors(d); char *mes=cdda_messages(d); if(mes || err) fprintf(stderr,"\r " " \r%s%s\n", mes?mes:"",err?err:""); if (err) free(err); if (mes) free(mes); if( readbuf==NULL) { if(errno==EBADF || errno==ENOMEDIUM){ report("\nparanoia_read: CDROM drive unavailable, bailing.\n"); exit(1); } skipped_flag=1; report("\nparanoia_read: Unrecoverable error, bailing.\n"); break; } if(skipped_flag && abort_on_skip){ cursor=batch_last+1; break; } skipped_flag=0; cursor++; if (output_endian!=bigendianp()) { int i; for (i=0; ibatch_last){ if (cdda_sector_gettrack(d, batch_last - toc_offset) < d->tracks || force_overread) { int i; /* Need to flush the buffer when overreading into the leadout */ if (cdda_sector_gettrack(d, batch_last) == d->tracks) paranoia_seek(p, cursor, SEEK_SET); /* read a sector and output the partial offset. Save the rest for the next batch iteration */ readbuf=paranoia_read_limited(p,callback,max_retries); err=cdda_errors(d);mes=cdda_messages(d); if(mes || err) fprintf(stderr,"\r " " \r%s%s\n", mes?mes:"",err?err:""); if (err) free(err); if (mes) free(mes); if(readbuf==NULL){ skipped_flag=1; report("\nparanoia_read: Unrecoverable error reading through " "sample_offset shift\n\tat end of track, bailing.\n"); break; } if (skipped_flag && abort_on_skip) break; skipped_flag=0; /* do not move the cursor */ if(output_endian!=bigendianp()) for(i=0;itracks && toc_offset > 0 && !force_overread) { char *silence; size_t missing_sector_bytes = CD_FRAMESIZE_RAW * toc_offset; silence = calloc(toc_offset, CD_FRAMESIZE_RAW); if (!silence || buffering_write(out, silence, missing_sector_bytes)) { report("Error writing output: %s", strerror(errno)); exit(1); } free(silence); } callback(cursor* (CDIO_CD_FRAMESIZE_RAW/2)-1, PARANOIA_CB_FINISHED); buffering_close(out); if(skipped_flag){ /* remove the file */ report("\nRemoving aborted file: %s", outfile_name); unlink(outfile_name); /* make the cursor correct if we have another track */ if(batch_track!=-1){ batch_track++; cursor=cdda_track_firstsector(d,batch_track); paranoia_seek(p,cursor, SEEK_SET); offset_skip=sample_offset*4; offset_buffer_used=0; } } report("\n"); } paranoia_free(p); p=NULL; } } report("Done.\n\n"); return 0; } libcdio-paranoia-release-10.2-2.0.2/src/getopt.c000066400000000000000000001022041461637345700211600ustar00rootroot00000000000000/* Getopt for GNU. NOTE: getopt is part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987-2014 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #include extern int getopt (int argc, char *const *argv, const char *optstring); /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #include #ifdef VMS # include #endif #ifdef _LIBC # include #else # define _(msgid) (msgid) #endif #if defined _LIBC # include #endif #ifndef attribute_hidden # define attribute_hidden #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" #include "getopt_int.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Keep a global copy of all internal members of getopt_data. */ static struct _getopt_data getopt_data; #ifndef __GNU_LIBRARY__ /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv (); #endif #endif /* not __GNU_LIBRARY__ */ #ifdef _LIBC /* Stored original parameters. XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ extern int __libc_argc; extern char **__libc_argv; /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ # ifdef USE_NONOPTION_FLAGS /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; # endif # ifdef USE_NONOPTION_FLAGS # define SWAP_FLAGS(ch1, ch2) \ if (d->__nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } # else # define SWAP_FLAGS(ch1, ch2) # endif #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ static void exchange (char **argv, struct _getopt_data *d) { int bottom = d->__first_nonopt; int middle = d->__last_nonopt; int top = d->optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (d->__nonoption_flags_len > 0 && top >= d->__nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) d->__nonoption_flags_len = d->__nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, d->__nonoption_flags_max_len), '\0', top + 1 - d->__nonoption_flags_max_len); d->__nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ d->__first_nonopt += (d->optind - d->__last_nonopt); d->__last_nonopt = d->optind; } /* Initialize the internal data when the first call is made. */ static const char * _getopt_initialize (int argc, char *const *argv, const char *optstring, struct _getopt_data *d, int posixly_correct) { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ d->__first_nonopt = d->__last_nonopt = d->optind; d->__nextchar = NULL; d->__posixly_correct = posixly_correct | !!getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { d->__ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { d->__ordering = REQUIRE_ORDER; ++optstring; } else if (d->__posixly_correct) d->__ordering = REQUIRE_ORDER; else d->__ordering = PERMUTE; #if defined _LIBC && defined USE_NONOPTION_FLAGS if (!d->__posixly_correct && argc == __libc_argc && argv == __libc_argv) { if (d->__nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') d->__nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = d->__nonoption_flags_max_len = strlen (orig_str); if (d->__nonoption_flags_max_len < argc) d->__nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (d->__nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) d->__nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', d->__nonoption_flags_max_len - len); } } d->__nonoption_flags_len = d->__nonoption_flags_max_len; } else d->__nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal_r (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only, struct _getopt_data *d, int posixly_correct) { int print_errors = d->opterr; if (argc < 1) return -1; d->optarg = NULL; if (d->optind == 0 || !d->__initialized) { if (d->optind == 0) d->optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring, d, posixly_correct); d->__initialized = 1; } else if (optstring[0] == '-' || optstring[0] == '+') optstring++; if (optstring[0] == ':') print_errors = 0; /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS # define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0' \ || (d->optind < d->__nonoption_flags_len \ && __getopt_nonoption_flags[d->optind] == '1')) #else # define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0') #endif if (d->__nextchar == NULL || *d->__nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (d->__last_nonopt > d->optind) d->__last_nonopt = d->optind; if (d->__first_nonopt > d->optind) d->__first_nonopt = d->optind; if (d->__ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) exchange ((char **) argv, d); else if (d->__last_nonopt != d->optind) d->__first_nonopt = d->optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (d->optind < argc && NONOPTION_P) d->optind++; d->__last_nonopt = d->optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (d->optind != argc && !strcmp (argv[d->optind], "--")) { d->optind++; if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) exchange ((char **) argv, d); else if (d->__first_nonopt == d->__last_nonopt) d->__first_nonopt = d->optind; d->__last_nonopt = argc; d->optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (d->optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (d->__first_nonopt != d->__last_nonopt) d->optind = d->__first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (d->__ordering == REQUIRE_ORDER) return -1; d->optarg = argv[d->optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr (optstring, argv[d->optind][1]))))) { char *nameend; unsigned int namelen; const struct option *p; const struct option *pfound = NULL; struct option_list { const struct option *p; struct option_list *next; } *ambig_list = NULL; int exact = 0; int indfound = -1; int option_index; for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; namelen = nameend - d->__nextchar; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, d->__nextchar, namelen)) { if (namelen == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) { /* Second or later nonexact match found. */ struct option_list *newp = alloca (sizeof (*newp)); newp->p = p; newp->next = ambig_list; ambig_list = newp; } } if (ambig_list != NULL && !exact) { if (print_errors) { struct option_list first; first.p = pfound; first.next = ambig_list; ambig_list = &first; #if defined _LIBC char *buf = NULL; size_t buflen = 0; FILE *fp = open_memstream (&buf, &buflen); if (fp != NULL) { fprintf (fp, _("%s: option '%s' is ambiguous; possibilities:"), argv[0], argv[d->optind]); do { fprintf (fp, " '--%s'", ambig_list->p->name); ambig_list = ambig_list->next; } while (ambig_list != NULL); fputc_unlocked ('\n', fp); if (__builtin_expect (fclose (fp) != EOF, 1)) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } } #else fprintf (stderr, _("%s: option '%s' is ambiguous; possibilities:"), argv[0], argv[d->optind]); do { fprintf (stderr, " '--%s'", ambig_list->p->name); ambig_list = ambig_list->next; } while (ambig_list != NULL); fputc ('\n', stderr); #endif } d->__nextchar += strlen (d->__nextchar); d->optind++; d->optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; d->optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) d->optarg = nameend + 1; else { if (print_errors) { #if defined _LIBC char *buf; int n; #endif if (argv[d->optind - 1][1] == '-') { /* --option */ #if defined _LIBC n = __asprintf (&buf, _("\ %s: option '--%s' doesn't allow an argument\n"), argv[0], pfound->name); #else fprintf (stderr, _("\ %s: option '--%s' doesn't allow an argument\n"), argv[0], pfound->name); #endif } else { /* +option or -option */ #if defined _LIBC n = __asprintf (&buf, _("\ %s: option '%c%s' doesn't allow an argument\n"), argv[0], argv[d->optind - 1][0], pfound->name); #else fprintf (stderr, _("\ %s: option '%c%s' doesn't allow an argument\n"), argv[0], argv[d->optind - 1][0], pfound->name); #endif } #if defined _LIBC if (n >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #endif } d->__nextchar += strlen (d->__nextchar); d->optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (d->optind < argc) d->optarg = argv[d->optind++]; else { if (print_errors) { #if defined _LIBC char *buf; if (__asprintf (&buf, _("\ %s: option '--%s' requires an argument\n"), argv[0], pfound->name) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, _("%s: option '--%s' requires an argument\n"), argv[0], pfound->name); #endif } d->__nextchar += strlen (d->__nextchar); d->optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } d->__nextchar += strlen (d->__nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[d->optind][1] == '-' || strchr (optstring, *d->__nextchar) == NULL) { if (print_errors) { #if defined _LIBC char *buf; int n; #endif if (argv[d->optind][1] == '-') { /* --option */ #if defined _LIBC n = __asprintf (&buf, _("%s: unrecognized option '--%s'\n"), argv[0], d->__nextchar); #else fprintf (stderr, _("%s: unrecognized option '--%s'\n"), argv[0], d->__nextchar); #endif } else { /* +option or -option */ #if defined _LIBC n = __asprintf (&buf, _("%s: unrecognized option '%c%s'\n"), argv[0], argv[d->optind][0], d->__nextchar); #else fprintf (stderr, _("%s: unrecognized option '%c%s'\n"), argv[0], argv[d->optind][0], d->__nextchar); #endif } #if defined _LIBC if (n >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #endif } d->__nextchar = (char *) ""; d->optind++; d->optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *d->__nextchar++; char *temp = strchr (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*d->__nextchar == '\0') ++d->optind; if (temp == NULL || c == ':' || c == ';') { if (print_errors) { #if defined _LIBC char *buf; int n; #endif #if defined _LIBC n = __asprintf (&buf, _("%s: invalid option -- '%c'\n"), argv[0], c); #else fprintf (stderr, _("%s: invalid option -- '%c'\n"), argv[0], c); #endif #if defined _LIBC if (n >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #endif } d->optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { if (longopts == NULL) goto no_longs; char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*d->__nextchar != '\0') { d->optarg = d->__nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ d->optind++; } else if (d->optind == argc) { if (print_errors) { #if defined _LIBC char *buf; if (__asprintf (&buf, _("%s: option requires an argument -- '%c'\n"), argv[0], c) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, _("%s: option requires an argument -- '%c'\n"), argv[0], c); #endif } d->optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `d->optind' once; increment it again when taking next ARGV-elt as argument. */ d->optarg = argv[d->optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) { if ((unsigned int) (nameend - d->__nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) { #if defined _LIBC char *buf; if (__asprintf (&buf, _("%s: option '-W %s' is ambiguous\n"), argv[0], d->optarg) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, _("%s: option '-W %s' is ambiguous\n"), argv[0], d->optarg); #endif } d->__nextchar += strlen (d->__nextchar); d->optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) d->optarg = nameend + 1; else { if (print_errors) { #if defined _LIBC char *buf; if (__asprintf (&buf, _("\ %s: option '-W %s' doesn't allow an argument\n"), argv[0], pfound->name) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, _("\ %s: option '-W %s' doesn't allow an argument\n"), argv[0], pfound->name); #endif } d->__nextchar += strlen (d->__nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (d->optind < argc) d->optarg = argv[d->optind++]; else { if (print_errors) { #if defined _LIBC char *buf; if (__asprintf (&buf, _("\ %s: option '-W %s' requires an argument\n"), argv[0], pfound->name) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, _("\ %s: option '-W %s' requires an argument\n"), argv[0], pfound->name); #endif } d->__nextchar += strlen (d->__nextchar); return optstring[0] == ':' ? ':' : '?'; } } else d->optarg = NULL; d->__nextchar += strlen (d->__nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } no_longs: d->__nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*d->__nextchar != '\0') { d->optarg = d->__nextchar; d->optind++; } else d->optarg = NULL; d->__nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*d->__nextchar != '\0') { d->optarg = d->__nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ d->optind++; } else if (d->optind == argc) { if (print_errors) { #if defined _LIBC char *buf; if (__asprintf (&buf, _("\ %s: option requires an argument -- '%c'\n"), argv[0], c) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, _("%s: option requires an argument -- '%c'\n"), argv[0], c); #endif } d->optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ d->optarg = argv[d->optind++]; d->__nextchar = NULL; } } return c; } } int _getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only, int posixly_correct) { int result; getopt_data.optind = optind; getopt_data.opterr = opterr; result = _getopt_internal_r (argc, argv, optstring, longopts, longind, long_only, &getopt_data, posixly_correct); optind = getopt_data.optind; optarg = getopt_data.optarg; optopt = getopt_data.optopt; return result; } int getopt (int argc, char *const *argv, const char *optstring) { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0, 0); } #ifdef _LIBC int __posix_getopt (int argc, char *const *argv, const char *optstring) { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0, 1); } #endif #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (int argc, char **argv) { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value '%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ libcdio-paranoia-release-10.2-2.0.2/src/getopt.h000066400000000000000000000147641461637345700212020ustar00rootroot00000000000000/* Declarations for getopt. Copyright (C) 1989-2014 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ #ifndef _GETOPT_H #ifndef __need_getopt # define _GETOPT_H 1 #endif /* If __GNU_LIBRARY__ is not already defined, either we are being used standalone, or this is the first header included in the source file. If we are being used with glibc, we need to include , but that does not exist if we are standalone. So: if __GNU_LIBRARY__ is not defined, include , which will pull in for us if it's from glibc. (Why ctype.h? It's guaranteed to exist and it doesn't flood the namespace with stuff the way some other headers do.) */ #if !defined __GNU_LIBRARY__ # include #endif #ifndef __THROW # ifndef __GNUC_PREREQ # define __GNUC_PREREQ(maj, min) (0) # endif # if defined __cplusplus && __GNUC_PREREQ (2,8) # define __THROW throw () # else # define __THROW # endif #endif #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; #ifndef __need_getopt /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { const char *name; /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ # define no_argument 0 # define required_argument 1 # define optional_argument 2 #endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for options given in OPTS. Return the option character from OPTS just read. Return -1 when there are no more options. For unrecognized options, or options missing arguments, `optopt' is set to the option letter, and '?' is returned. The OPTS string is a list of characters which are recognized option letters, optionally followed by colons, specifying that that letter takes an argument, to be placed in `optarg'. If a letter in OPTS is followed by two colons, its argument is optional. This behavior is specific to the GNU `getopt'. The argument `--' causes premature termination of argument scanning, explicitly telling `getopt' that there are no more options. If OPTS begins with `--', then non-option arguments are treated as arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ #ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) __THROW; # if defined __need_getopt && defined __USE_POSIX2 \ && !defined __USE_POSIX_IMPLICITLY && !defined __USE_GNU /* The GNU getopt has more functionality than the standard version. The additional functionality can be disable at runtime. This redirection helps to also do this at runtime. */ # ifdef __REDIRECT extern int __REDIRECT_NTH (getopt, (int ___argc, char *const *___argv, const char *__shortopts), __posix_getopt); # else extern int __posix_getopt (int ___argc, char *const *___argv, const char *__shortopts) __THROW; # define getopt __posix_getopt # endif # endif #else /* not __GNU_LIBRARY__ */ extern int getopt (); #endif /* __GNU_LIBRARY__ */ #ifndef __need_getopt extern int getopt_long (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind) __THROW; extern int getopt_long_only (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind) __THROW; #endif #ifdef __cplusplus } #endif /* Make sure we later can get all the definitions and declarations. */ #undef __need_getopt #endif /* getopt.h */ libcdio-paranoia-release-10.2-2.0.2/src/getopt1.c000066400000000000000000000111161461637345700212420ustar00rootroot00000000000000/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987-2014 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #ifdef _LIBC # include #else # include "getopt.h" #endif #include "getopt_int.h" #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index) { return _getopt_internal (argc, argv, options, long_options, opt_index, 0, 0); } int _getopt_long_r (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index, struct _getopt_data *d) { return _getopt_internal_r (argc, argv, options, long_options, opt_index, 0, d, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index) { return _getopt_internal (argc, argv, options, long_options, opt_index, 1, 0); } int _getopt_long_only_r (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index, struct _getopt_data *d) { return _getopt_internal_r (argc, argv, options, long_options, opt_index, 1, d, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST #include int main (int argc, char **argv) { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ libcdio-paranoia-release-10.2-2.0.2/src/getopt_int.h000066400000000000000000000111631461637345700220420ustar00rootroot00000000000000/* Internal declarations for getopt. Copyright (C) 1989-2014 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ #ifndef _GETOPT_INT_H #define _GETOPT_INT_H 1 extern int _getopt_internal (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only, int posixly_correct); /* Reentrant versions which can handle parsing multiple argument vectors at the same time. */ /* Data type for reentrant functions. */ struct _getopt_data { /* These have exactly the same meaning as the corresponding global variables, except that they are used for the reentrant versions of getopt. */ int optind; int opterr; int optopt; char *optarg; /* Internal members. */ /* True if the internal members have been initialized. */ int __initialized; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ char *__nextchar; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } __ordering; /* If the POSIXLY_CORRECT environment variable is set. */ int __posixly_correct; /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ int __first_nonopt; int __last_nonopt; #if defined _LIBC && defined USE_NONOPTION_FLAGS int __nonoption_flags_max_len; int __nonoption_flags_len; # endif }; /* The initializer is necessary to set OPTIND and OPTERR to their default values and to clear the initialization flag. */ #define _GETOPT_DATA_INITIALIZER { 1, 1 } extern int _getopt_internal_r (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only, struct _getopt_data *__data, int posixly_correct); extern int _getopt_long_r (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind, struct _getopt_data *__data); extern int _getopt_long_only_r (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind, struct _getopt_data *__data); #endif /* getopt_int.h */ libcdio-paranoia-release-10.2-2.0.2/src/header.c000066400000000000000000000064421461637345700211150ustar00rootroot00000000000000/* Copyright (C) 2004,2015 Rocky Bernstein #include #include #include static void PutNum(long num,int f,int endianness,int bytes){ int i; unsigned char c; if(!endianness) i=0; else i=bytes-1; while(bytes--){ c=(num>>(i<<3))&0xff; if(write(f,&c,1)==-1){ perror("Could not write to output."); exit(1); } if(endianness) i--; else i++; } } /** Writes WAV headers */ void WriteWav(int f, long int bytes) { int dummy __attribute__((unused)); /* quick and dirty */ dummy = write(f,"RIFF",4); /* 0-3 */ PutNum(bytes+44-8,f,0,4); /* 4-7 */ dummy = write(f,"WAVEfmt ",8); /* 8-15 */ PutNum(16,f,0,4); /* 16-19 */ PutNum(1,f,0,2); /* 20-21 */ PutNum(2,f,0,2); /* 22-23 */ PutNum(44100,f,0,4); /* 24-27 */ PutNum(44100*2*2,f,0,4); /* 28-31 */ PutNum(4,f,0,2); /* 32-33 */ PutNum(16,f,0,2); /* 34-35 */ dummy = write(f,"data",4); /* 36-39 */ PutNum(bytes,f,0,4); /* 40-43 */ } /** Writes AIFF headers */ void WriteAiff(int f, long int bytes) { long size=bytes+54; long frames=bytes/4; int dummy __attribute__((unused)); /* Again, quick and dirty */ dummy = write(f,"FORM",4); /* 4 */ PutNum(size-8,f,1,4); /* 8 */ dummy = write(f,"AIFF",4); /* 12 */ dummy = write(f,"COMM",4); /* 16 */ PutNum(18,f,1,4); /* 20 */ PutNum(2,f,1,2); /* 22 */ PutNum(frames,f,1,4); /* 26 */ PutNum(16,f,1,2); /* 28 */ dummy = write(f,"@\016\254D\0\0\0\0\0\0",10); /* 38 (44.100 as a float) */ dummy = write(f,"SSND",4); /* 42 */ PutNum(bytes+8,f,1,4); /* 46 */ PutNum(0,f,1,4); /* 50 */ PutNum(0,f,1,4); /* 54 */ } /** Writes AIFC headers */ void WriteAifc(int f, long bytes) { long size=bytes+86; long frames=bytes/4; int dummy __attribute__((unused)); /* Again, quick and dirty */ dummy = write(f,"FORM",4); /* 4 */ PutNum(size-8,f,1,4); /* 8 */ dummy = write(f,"AIFC",4); /* 12 */ dummy = write(f,"FVER",4); /* 16 */ PutNum(4,f,1,4); /* 20 */ PutNum(2726318400UL,f,1,4); /* 24 */ dummy = write(f,"COMM",4); /* 28 */ PutNum(38,f,1,4); /* 32 */ PutNum(2,f,1,2); /* 34 */ PutNum(frames,f,1,4); /* 38 */ PutNum(16,f,1,2); /* 40 */ dummy = write(f,"@\016\254D\0\0\0\0\0\0",10); /* 50 (44.100 as a float) */ dummy = write(f,"NONE",4); /* 54 */ PutNum(14,f,1,1); /* 55 */ dummy = write(f,"not compressed",14); /* 69 */ PutNum(0,f,1,1); /* 70 */ dummy = write(f,"SSND",4); /* 74 */ PutNum(bytes+8,f,1,4); /* 78 */ PutNum(0,f,1,4); /* 82 */ PutNum(0,f,1,4); /* 86 */ } libcdio-paranoia-release-10.2-2.0.2/src/header.h000066400000000000000000000006411461637345700211150ustar00rootroot00000000000000/* Copyright (C) 2008 Rocky Bernstein Copyright (C) 1998 Monty */ /** \file header.h * \brief header for WAV, AIFF and AIFC header-writing routines. */ /** Writes WAV headers */ extern void WriteWav(int f,long int i_bytes); /** Writes AIFC headers */ extern void WriteAifc(int f,long int i_bytes); /** Writes AIFF headers */ extern void WriteAiff(int f,long int_bytes); libcdio-paranoia-release-10.2-2.0.2/src/pod2c.pl000077500000000000000000000027431461637345700210700ustar00rootroot00000000000000#!/usr/bin/perl # $Id: pod2c.pl,v 1.4 2008/06/19 15:44:31 flameeyes Exp $ # Utility to turn pieces of pod text to help text. use File::Basename; die "Expecting exactly one argument, a filename" if @ARGV != 1; $filename = shift; ($name, $path, $suffix)=fileparse($filename,"\.txt"); close(STDIN); open(STDIN, "<$filename") || die "Can't open $filename for reading:\n$!"; #$outfile="../${filename}.h"; #open(STDOUT, ">$outfile") # || die "Can't open $outfile for writing:\n$!"; print "/* Copyright (C) 1999, 2005, 2007, 2008 Rocky Bernstein 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 3 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, see . */ static const char ${name}_help[] =\n"; while() { s/["]/\\"/g; # Change POD'ed items to quoted items, e.g. See L and L becomes # See "y" and "z" (with \'s around the quotes) s/[C,L,I,B,F]<(.+?)>/\\"$1\\"/g; chomp; if ( $^O eq "cygwin" ) { s/\ // } print "\"$_\\n\"\n"; } print ";\n"; libcdio-paranoia-release-10.2-2.0.2/src/report.c000066400000000000000000000011451461637345700211730ustar00rootroot00000000000000/* Copyright (C) 2004, 2008, 2010, 2011 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu */ /****************************************************************** * * reporting/logging routines * ******************************************************************/ /* config.h has to come first else _FILE_OFFSET_BITS are redefined in say opensolaris. */ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #include #include #include "report.h" int quiet=0; int verbose=CDDA_MESSAGE_FORGETIT; FILE *reportfile=NULL; libcdio-paranoia-release-10.2-2.0.2/src/report.h000066400000000000000000000010351461637345700211760ustar00rootroot00000000000000/* Copyright (C) 2008 Rocky Bernstein */ extern int verbose; extern int quiet; extern FILE *reportfile; #define report(...) {if(!quiet){fprintf(stderr, __VA_ARGS__);fputc('\n',stderr);} \ if(reportfile){fprintf(reportfile, __VA_ARGS__);fputc('\n',reportfile);}} #define reportC(...) {if(!quiet){fprintf(stderr, __VA_ARGS__);} \ if(reportfile){fprintf(reportfile, __VA_ARGS__);}} #define printC(...) {if(!quiet){fprintf(stderr, __VA_ARGS__);}} #define logC(...) {if(reportfile){fprintf(reportfile, __VA_ARGS__);}} libcdio-paranoia-release-10.2-2.0.2/src/usage-copy.h000066400000000000000000000162471461637345700217520ustar00rootroot00000000000000/* Copyright (C) 1999, 2005, 2008, 2009 Rocky Bernstein Copyright (C) 2014 Robert Kausch */ const char usage_help[] = "USAGE:\n" " cd-paranoia [options] [outfile]\n" "\n" "OPTIONS:\n" " -A --analyze-drive : run and log a complete analysis of drive\n" " caching, timing and reading behavior;\n" " verifies that cdparanoia is correctly\n" " modelling a specific drive's cache and\n" " read behavior. Implies -vQL\n" "\n" " -v --verbose : extra verbose operation\n" " -q --quiet : quiet operation\n" " -e --stderr-progress : force output of progress information to\n" " -l --log-summary : save result summary to file\n" " stderr (for wrapper scripts)\n" " -L --log-debug : save detailed device autosense and\n" " debugging output to file\n" " stderr (for wrapper scripts)\n" " -V --version : print version info and quit\n" " -Q --query : autosense drive, query disc and quit\n" " -B --batch : 'batch' mode (saves each track to a\n" " seperate file.\n" " -s --search-for-drive : do an exhaustive search for drive\n" " -h --help : print help\n" "\n" " -p --output-raw : output raw 16 bit PCM in host byte \n" " order\n" " -r --output-raw-little-endian : output raw 16 bit little-endian PCM\n" " -R --output-raw-big-endian : output raw 16 bit big-endian PCM\n" " -w --output-wav : output as WAV file (default)\n" " -f --output-aiff : output as AIFF file\n" " -a --output-aifc : output as AIFF-C file\n" "\n" " -c --force-cdrom-little-endian : force treating drive as little endian\n" " -C --force-cdrom-big-endian : force treating drive as big endian\n" " -n --force-default-sectors : force default number of sectors in read\n" " to n sectors\n" " -o --force-search-overlap : force minimum overlap search during\n" " verification to n sectors\n" " -d --force-cdrom-device : use specified device; disallow \n" " autosense\n" " -k --force-cooked-device : really an alias for -d. Kept for \n" " compatibility.\n" " -g --force-generic-device : really an alias for -d. Kept for \n" " compatibility.\n" " -S --force-read-speed : read from device at specified speed; by\n" " default, cdparanoia sets drive to full\n" " speed.\n" " -t --toc-offset : Add sectors to the values reported\n" " when addressing tracks. May be negative\n" " -T --toc-bias : Assume that the beginning offset of \n" " track 1 as reported in the TOC will be\n" " addressed as LBA 0. Necessary for some\n" " Toshiba drives to get track boundaries\n" " correct\n" " -m --mmc-timeout : Set SCSI-MMC timeout to seconds.\n" " -O --sample-offset : Add samples to the offset when\n" " reading data. May be negative.\n" " -z --never-skip[=n] : never accept any less than perfect\n" " data reconstruction (don't allow 'V's)\n" " but if [n] is given, skip after [n]\n" " retries without progress.\n" " -Z --disable-paranoia : disable all paranoia checking\n" " -Y --disable-extra-paranoia : only do cdda2wav-style overlap checking\n" " -X --abort-on-skip : abort on imperfect reads/skips\n" " -x --test-flags=mask : simulate CD-reading errors of ilk-mask n\n" " mask & 0x10 - simulate underrun errors\n" "\n" "OUTPUT SMILIES:\n" " :-) Normal operation, low/no jitter\n" " :-| Normal operation, considerable jitter\n" " :-/ Read drift\n" " :-P Unreported loss of streaming in atomic read operation\n" " 8-| Finding read problems at same point during reread; hard to correct\n" " :-0 SCSI/ATAPI transport error\n" " :-( Scratch detected\n" " ;-( Gave up trying to perform a correction\n" " 8-X Aborted (as per -X) due to a scratch/skip\n" " :^D Finished extracting\n" "\n" "PROGRESS BAR SYMBOLS:\n" " No corrections needed\n" " - Jitter correction required\n" " + Unreported loss of streaming/other error in read\n" " ! Errors are getting through stage 1 but corrected in stage2\n" " e SCSI/ATAPI transport error (corrected)\n" " V Uncorrected error/skip\n" "\n" "SPAN ARGUMENT:\n" "The span argument may be a simple track number or a offset/span\n" "specification. The syntax of an offset/span takes the rough form:\n" " \n" " 1[ww:xx:yy.zz]-2[aa:bb:cc.dd] \n" "\n" "Here, 1 and 2 are track numbers; the numbers in brackets provide a\n" "finer grained offset within a particular track. [aa:bb:cc.dd] is in\n" "hours/minutes/seconds/sectors format. Zero fields need not be\n" "specified: [::20], [:20], [20], [20.], etc, would be interpreted as\n" "twenty seconds, [10:] would be ten minutes, [.30] would be thirty\n" "sectors (75 sectors per second).\n" "\n" "When only a single offset is supplied, it is interpreted as a starting\n" "offset and ripping will continue to the end of he track. If a single\n" "offset is preceeded or followed by a hyphen, the implicit missing\n" "offset is taken to be the start or end of the disc, respectively. Thus:\n" "\n" " 1:[20.35] Specifies ripping from track 1, second 20, sector 35 to \n" " the end of track 1.\n" "\n" " 1:[20.35]- Specifies ripping from 1[20.35] to the end of the disc\n" "\n" " -2 Specifies ripping from the beginning of the disc up to\n" " (and including) track 2\n" "\n" " -2:[30.35] Specifies ripping from the beginning of the disc up to\n" " 2:[30.35]\n" "\n" " 2-4 Specifies ripping from the beginning of track two to the\n" " end of track 4.\n" "\n" "Don't forget to protect square brackets and preceeding hyphens from\n" "the shell...\n" "\n" "A few examples, protected from the shell:\n" " A) query only with exhaustive search for a drive and full reporting\n" " of autosense:\n" " cd-paranoia -vsQ\n" "\n" " B) extract up to and including track 3, putting each track in a seperate\n" " file:\n" " cd-paranoia -B -- \"-3\"\n" "\n" " C) extract from track 1, time 0:30.12 to 1:10.00:\n" " cd-paranoia \"[:30.12]-1[1:10]\"\n" "\n" "Submit bug reports to bug-libcdio@gnu.org\n" "\n" ; libcdio-paranoia-release-10.2-2.0.2/src/usage.txt.in000066400000000000000000000146771461637345700220040ustar00rootroot00000000000000USAGE: @CDPARANOIA_NAME@ [options] [outfile] OPTIONS: -A --analyze-drive : run and log a complete analysis of drive caching, timing and reading behavior; verifies that cdparanoia is correctly modelling a specific drive's cache and read behavior. Implies -vQL -v --verbose : extra verbose operation -q --quiet : quiet operation -e --stderr-progress : force output of progress information to stderr (for wrapper scripts) -l --log-summary : save result summary to file -L --log-debug : save detailed device autosense and debugging output to file -V --version : print version info and quit -Q --query : autosense drive, query disc and quit -B --batch : 'batch' mode (saves each track to a seperate file. -s --search-for-drive : do an exhaustive search for drive -h --help : print help -p --output-raw : output raw 16 bit PCM in host byte order -r --output-raw-little-endian : output raw 16 bit little-endian PCM -R --output-raw-big-endian : output raw 16 bit big-endian PCM -w --output-wav : output as WAV file (default) -f --output-aiff : output as AIFF file -a --output-aifc : output as AIFF-C file -c --force-cdrom-little-endian : force treating drive as little endian -C --force-cdrom-big-endian : force treating drive as big endian -n --force-default-sectors : force default number of sectors in read to n sectors -o --force-search-overlap : force minimum overlap search during verification to n sectors -d --force-cdrom-device : use specified device; disallow autosense -k --force-cooked-device : really an alias for -d. Kept for compatibility. -g --force-generic-device : really an alias for -d. Kept for compatibility. -S --force-read-speed : read from device at specified speed; by default, cdparanoia sets drive to full speed. -t --toc-offset : Add sectors to the values reported when addressing tracks. May be negative -T --toc-bias : Assume that the beginning offset of track 1 as reported in the TOC will be addressed as LBA 0. Necessary for some Toshiba drives to get track boundaries correct -m --mmc-timeout : Set SCSI-MMC timeout to seconds. -O --sample-offset : Add samples to the offset when reading data. May be negative. -z --never-skip[=n] : never accept any less than perfect data reconstruction (don't allow 'V's) but if [n] is given, skip after [n] retries without progress. -Z --disable-paranoia : disable all paranoia checking -Y --disable-extra-paranoia : only do cdda2wav-style overlap checking -X --abort-on-skip : abort on imperfect reads/skips -x --test-flags=mask : simulate CD-reading errors of ilk-mask n mask & 0x10 - simulate underrun errors OUTPUT SMILIES: :-) Normal operation, low/no jitter :-| Normal operation, considerable jitter :-/ Read drift :-P Unreported loss of streaming in atomic read operation 8-| Finding read problems at same point during reread; hard to correct :-0 SCSI/ATAPI transport error :-( Scratch detected ;-( Gave up trying to perform a correction 8-X Aborted (as per -X) due to a scratch/skip :^D Finished extracting PROGRESS BAR SYMBOLS: No corrections needed - Jitter correction required + Unreported loss of streaming/other error in read ! Errors are getting through stage 1 but corrected in stage2 e SCSI/ATAPI transport error (corrected) V Uncorrected error/skip SPAN ARGUMENT: The span argument may be a simple track number or a offset/span specification. The syntax of an offset/span takes the rough form: 1[ww:xx:yy.zz]-2[aa:bb:cc.dd] Here, 1 and 2 are track numbers; the numbers in brackets provide a finer grained offset within a particular track. [aa:bb:cc.dd] is in hours/minutes/seconds/sectors format. Zero fields need not be specified: [::20], [:20], [20], [20.], etc, would be interpreted as twenty seconds, [10:] would be ten minutes, [.30] would be thirty sectors (75 sectors per second). When only a single offset is supplied, it is interpreted as a starting offset and ripping will continue to the end of he track. If a single offset is preceeded or followed by a hyphen, the implicit missing offset is taken to be the start or end of the disc, respectively. Thus: 1:[20.35] Specifies ripping from track 1, second 20, sector 35 to the end of track 1. 1:[20.35]- Specifies ripping from 1[20.35] to the end of the disc -2 Specifies ripping from the beginning of the disc up to (and including) track 2 -2:[30.35] Specifies ripping from the beginning of the disc up to 2:[30.35] 2-4 Specifies ripping from the beginning of track two to the end of track 4. Don't forget to protect square brackets and preceeding hyphens from the shell... A few examples, protected from the shell: A) query only with exhaustive search for a drive and full reporting of autosense: @CDPARANOIA_NAME@ -vsQ B) extract up to and including track 3, putting each track in a separate file: @CDPARANOIA_NAME@ -B -- "-3" C) extract from track 1, time 0:30.12 to 1:10.00: @CDPARANOIA_NAME@ "[:30.12]-1[1:10]" Submit bug reports to bug-libcdio@gnu.org libcdio-paranoia-release-10.2-2.0.2/src/utils.h000066400000000000000000000026241461637345700210300ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2008, 2014 Rocky Bernstein Copyright (C) 1998 Monty */ #include #include #include #include #define copystring(s) (s) ? s : NULL; static inline char * catstring(char *buff, const char *s) { if(s){ if(buff) buff=realloc(buff,strlen(buff)+strlen(s)+1); else buff=calloc(strlen(s)+1,1); strcat(buff,s); } return(buff); } /** Returns basename(fullname) and sets path to the dirname. rename includes a trailing slash execpt when dirname is empty. */ static inline char * split_base_dir(char *fullpath, char *path, unsigned int max) { char *post = strrchr(fullpath, '/'); int pos = (post ? post-fullpath+1 : 0); path[0]='\0'; if (pos>max) return NULL; if (fullpath[pos] == '/') pos++; if (pos) strncat(path, fullpath, pos); return fullpath + pos; } /* By renaming this to utils.c and compiling like this: gcc -DSTANDALONE -o utils utils.h you can demo this code. */ #ifdef STANDALONE int main(int argc, char **argv) { int i; const char *paths[] = {"/abc/def", "hij/klm"}; char path[10]; for (i=0; i<2; i++) { char *fullpath = strdup(paths[i]); char *base = split_base_dir(fullpath, path, sizeof(path)); printf("dirname of %s is %s; basename is %s\n", fullpath, path, base); if (fullpath) free(fullpath); } } #endif libcdio-paranoia-release-10.2-2.0.2/src/version.h000066400000000000000000000013011461637345700213440ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2008 Rocky Bernstein Copyright (C) 2014 Robert Kausch Copyright (C) 2001 Monty */ /****************************************************************** * cdda_paranoia generation III release 10.2 libcdio ******************************************************************/ #include #define PARANOIA_VERSION \ "cdparanoia III release 10.2 libcdio " CDIO_VERSION "\n" \ "(C) 2001 Monty and Xiphophorus\n" \ "(C) 2004, 2005, 2008 Rocky Bernstein \n" \ "(C) 2014 Robert Kausch \n\n" \ "Report bugs to bug-libcdio@gnu.org\n" libcdio-paranoia-release-10.2-2.0.2/test/000077500000000000000000000000001461637345700177035ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/test/.gitignore000066400000000000000000000014361461637345700216770ustar00rootroot00000000000000/*.exe /*.exe.stackdump /*.o /*~ /.deps /.libs /Makefile /Makefile.in /cd-paranoia.log /cdda-1.raw /cdda-2.raw /cdda-be.bin /cdda-be.cue /cdda-good.raw /cdda-jitter.raw /cdda-le.bin /cdda-le.cue /cdda-matches.raw /cdda-underrun.raw /cdda.bin /cdda.raw /check_common_fn /check_cue.sh /check_iso.sh /check_nrg.sh /check_paranoia.sh /check_sizeof /check_start_track_not_one.sh /endian.sh /get_libcdio_version /isofs-m1.bin /start_track_not_one.bin /start_track_not_one.cue /start_track_not_one.sh /test_lib_driver_util /testassert /testassert.core /testbincue /testbincue.c /testdefault /testgetdevices /testgetdevices.c /testischar /testiso9660 /testisocd /testisocd2 /testisocd2.c /testlinux /testnrg /testnrg.c /testparanoia /testpregap /testpregap.c /testsolaris /testtoc /testunconfig /testutils libcdio-paranoia-release-10.2-2.0.2/test/Makefile.am000066400000000000000000000021341461637345700217370ustar00rootroot00000000000000#################################################### # Things for regression testing #################################################### # # SUBDIRS = cdda_interface data testparanoia=testparanoia testparanoia_LDADD = $(LIBCDIO_PARANOIA_LIBS) $(LIBCDIO_CDDA_LIBS) $(LIBCDIO_LIBS) $(LTLIBICONV) hack = $(testparanoia) DATA_DIR = @abs_top_srcdir@/test/data AM_CPPFLAGS = -I$(top_srcdir) $(LIBCDIO_CFLAGS) $(LIBCDIO_PARANOIA_CFLAGS) check_SCRIPTS = check_paranoia.sh endian.sh check_start_track_not_one.sh # If we beefed this up so it checked to see if a CD-DA was loaded # it could be an automatic test. But for now, not so. # check_paranoia.sh check_start_track_not_one.sh: get_libcdio_version check_PROGRAMS = testparanoia testutils get_libcdio_version check_DATA = cd-paranoia-log.right EXTRA_DIST = $(check_SCRIPTS) $(check_DATA) TESTS = $(check_PROGRAMS) $(check_SCRIPTS) MOSTLYCLEANFILES = core core.* *.dump cdda-orig.wav cdda-try.wav *.raw *.bin *.cue get_libcdio_version test: check-am # extra dependencies of tests check-am: get_libcdio_version CFLAGS += @LIBCDIO_CFLAGS@ libcdio-paranoia-release-10.2-2.0.2/test/cd-paranoia-log.right000066400000000000000000000000741461637345700237000ustar00rootroot00000000000000outputting to cdda.raw (== PROGRESS == [] == :^D * ==) libcdio-paranoia-release-10.2-2.0.2/test/cdda_interface/000077500000000000000000000000001461637345700226165ustar00rootroot00000000000000libcdio-paranoia-release-10.2-2.0.2/test/cdda_interface/.gitignore000066400000000000000000000000741461637345700246070ustar00rootroot00000000000000/.libs /.deps /Makefile /Makefile.in /toc /toc-toc.o /toc.c libcdio-paranoia-release-10.2-2.0.2/test/cdda_interface/Makefile.am000066400000000000000000000014461461637345700246570ustar00rootroot00000000000000#################################################### # lib/cdda_interface regression testing #################################################### AM_CPPFLAGS = $(LIBCDIO_CFLAGS) $(LIBISO9660_CFLAGS) $(LIBCDIO_PARANOIA_CFLAGS) DATA_DIR = $(abs_top_srcdir)/test/data toc_SOURCES = toc.c toc_LDADD = $(LIBCDIO_PARANOIA_LIBS) $(LIBCDIO_CDDA_LIBS) $(LIBCDIO_LIBS) $(LTLIBICONV) toc_CFLAGS = -DDATA_DIR=\"$(DATA_DIR)\" check_PROGRAMS = \ toc TESTS = $(check_PROGRAMS) EXTRA_DIST = \ toc.c.in MOSTLYCLEANFILES = \ $(check_PROGRAMS) \ core core.* *.dump cdda-orig.wav cdda-try.wav *.raw #: run regression tests. "test" is the same thing as "check" test: check-am #: Run all tests without bloated output check-short: $(MAKE) check 2>&1 | ruby @abs_top_srcdir@/make-check-filter.rb libcdio-paranoia-release-10.2-2.0.2/test/cdda_interface/toc.c.in000066400000000000000000000216701461637345700241620ustar00rootroot00000000000000/* Copyright (C) 2013, 2024 Rocky Bernstein Copyright (C) 2014 Robert Kausch 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 3 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, see . */ /* Regression test for lib/cdda_interface/toc.c To compile as s standalone program: gcc -g3 -Wall -DHAVE_CONFIG_H -I../.. -I../..include toc.c \ ../../lib/paranoia/libcdio_paranoia.la ../../lib/cdda_interface/.lib/libcdio_cdda.a -lcdio -o toc */ #ifdef HAVE_CONFIG_H #include "config.h" #define __CDIO_CONFIG_H__ 1 #endif #ifdef HAVE_STDIO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include #include #include #include #include int main(void) { printf("%d\n", LIBCDIO_VERSION_NUM); return EXIT_SUCCESS; } libcdio-paranoia-release-10.2-2.0.2/test/testparanoia.c000066400000000000000000000127211461637345700225440ustar00rootroot00000000000000/* Copyright (C) 2005-2006, 2008, 2011, 2014 Rocky Bernstein 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 3 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, see . */ /* Simple program to show using libcdio's version of cdparanoia. */ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #include #include #include #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef WORDS_BIGENDIAN #define BIGENDIAN 1 #else #define BIGENDIAN 0 #endif #define SKIP_TEST_RC 77 #define MAX_SECTORS 50 static uint8_t audio_buf[MAX_SECTORS][CDIO_CD_FRAMESIZE_RAW] = { {0}, }; static paranoia_cb_mode_t audio_status[MAX_SECTORS]; static unsigned int i = 0; static void callback(long int inpos, paranoia_cb_mode_t function) { audio_status[i] = function; } int main(int argc, const char *argv[]) { cdrom_drive_t *d = NULL; /* Place to store handle given by cd-parapnioa. */ driver_id_t driver_id; char **ppsz_cd_drives; /* List of all drives with a loaded CDDA in it. */ int i_rc=0; /* See if we can find a device with a loaded CD-DA in it. If successful drive_id will be set. */ ppsz_cd_drives = cdio_get_devices_with_cap_ret(NULL, CDIO_FS_AUDIO, false, &driver_id); if (ppsz_cd_drives && *ppsz_cd_drives) { /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in the list. */ d=cdda_identify(*ppsz_cd_drives, 1, NULL); } else { printf("-- Unable find or access a CD-ROM drive with an audio CD in it.\n"); exit(SKIP_TEST_RC); } /** We had a bug in is_device when driver_id == DRIVER_UNKNOWN or DRIVER_DEVICE. Let's make sure we've fixed that problem. **/ if (!cdio_is_device(*ppsz_cd_drives, DRIVER_UNKNOWN) || !cdio_is_device(*ppsz_cd_drives, DRIVER_DEVICE)) exit(99); /* Don't need a list of CD's with CD-DA's any more. */ cdio_free_device_list(ppsz_cd_drives); /* We'll set for verbose paranoia messages. */ cdda_verbose_set(d, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT); if ( 0 != cdio_cddap_open(d) ) { printf("Unable to open disc.\n"); exit(SKIP_TEST_RC); } /* Okay now set up to read up to the first 300 frames of the first audio track of the Audio CD. */ { cdrom_paranoia_t *p = paranoia_init(d); lsn_t i_first_lsn = cdda_disc_firstsector(d); if ( -1 == i_first_lsn ) { printf("Trouble getting starting LSN\n"); } else { lsn_t i_lsn; /* Current LSN to read */ lsn_t i_last_lsn = cdda_disc_lastsector(d); unsigned int i_sectors = i_last_lsn - i_first_lsn + 1; unsigned int j; unsigned int i_good = 0; unsigned int i_bad = 0; /* Set reading mode for full paranoia, but allow skipping sectors. */ paranoia_modeset(p, PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP); for ( j=0; j<10; j++ ) { /* Pick a place to start reading. */ i_lsn = i_first_lsn + (rand() % i_sectors); paranoia_seek(p, i_lsn, SEEK_SET); printf("-- Testing %d sectors starting at %ld\n", MAX_SECTORS, (long int) i_lsn); for ( i = 0; i < MAX_SECTORS && i_lsn <= i_last_lsn; i++, i_lsn++ ) { /* read a sector */ int16_t *p_readbuf = paranoia_read(p, callback); char *psz_err=cdio_cddap_errors(d); char *psz_mes=cdio_cddap_messages(d); memcpy(audio_buf[i], p_readbuf, CDIO_CD_FRAMESIZE_RAW); if (psz_mes || psz_err) printf("%s%s\n", psz_mes ? psz_mes: "", psz_err ? psz_err: ""); cdio_cddap_free_messages(psz_err); cdio_cddap_free_messages(psz_mes); if( !p_readbuf ) { printf("paranoia read error. Stopping.\n"); goto out; } } /* Compare with the sectors from paranoia. */ i_lsn -= MAX_SECTORS; for ( i = 0; i < MAX_SECTORS; i++, i_lsn++ ) { uint8_t readbuf[CDIO_CD_FRAMESIZE_RAW] = {0,}; if ( PARANOIA_CB_READ == audio_status[i] || PARANOIA_CB_VERIFY == audio_status[i] ) { /* We read the block via paranoia without an error. */ if ( 0 == cdio_read_audio_sector(d->p_cdio, readbuf, i_lsn) ) { if ( BIGENDIAN != d->bigendianp ) { /* We will compare in the slow, pedantic way*/ int j; for (j=0; j < CDIO_CD_FRAMESIZE_RAW ; j +=2) { if (audio_buf[i][j] != readbuf[j+1] && audio_buf[i][j+1] != readbuf[j] ) { printf("LSN %ld doesn't match\n", (long int) i_lsn); i_bad++; } else { i_good++; } } } else { if ( 0 != memcmp(audio_buf[i], readbuf, CDIO_CD_FRAMESIZE_RAW) ) { printf("LSN %ld doesn't match\n", (long int) i_lsn); i_bad++; } else { i_good++; } } } } else { printf("Skipping LSN %ld because of status: %s\n", (long int) i_lsn, paranoia_cb_mode2str[audio_status[i]]); } } } printf("-- %u sectors compared okay %u sectors were different\n", i_good, i_bad); if (i_bad > i_good) i_rc = 1; } out: paranoia_free(p); } cdio_cddap_close(d); exit(i_rc); } libcdio-paranoia-release-10.2-2.0.2/test/testutils.c000066400000000000000000000041471461637345700221150ustar00rootroot00000000000000/* Copyright (C) 2014 Rocky Bernstein 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 3 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, see . */ /* test of routines in src/utils.h. For more verbse output, pass an argument. For example: make testutils ./testutils debug */ #ifdef HAVE_CONFIG_H # include "config.h" # define __CDIO_CONFIG_H__ 1 #endif #include "../src/utils.h" typedef struct { const char *fullname; const char *dirname; const char *basename; } testdata; int main(int argc, const char *argv[]) { int i_rc=0; int i; const testdata paths[] = { {"/abc/def", "/abc/", "def"}, {"hij/klm", "hij/", "klm"}, {"1234567890/klm", NULL, NULL} }; char path[10]; for (i=0; i<3; i++) { char *fullpath = strdup(paths[i].fullname); char *base = split_base_dir(fullpath, path, sizeof(path)); if (base == NULL) { if (paths[i].basename != NULL) { fprintf(stderr, "Got an unexpected null. Expected %s\n", paths[i].basename); } else { if (argc > 1) printf("%s is too large as expected\n", fullpath); } } else { if (argc > 1) { printf("dirname of %s is %s; basename is %s\n", fullpath, path, base); } if (0 != strcmp(paths[i].basename, base)) { fprintf(stderr, "Expecting basename %s; got %s for %s\n", paths[i].basename, base, fullpath); i_rc = 1; } if (0 != strcmp(paths[i].dirname, path)) { fprintf(stderr, "Expecting dirname %s; got %s for %s\n", paths[i].dirname, path, fullpath); i_rc = 1; } } if (fullpath) free(fullpath); } exit(i_rc); }