diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d310744 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/build +*.dol +*.elf +/USBLoaderGX/meta.xml \ No newline at end of file diff --git a/.vscode/USBLoaderGX.code-workspace b/.vscode/USBLoaderGX.code-workspace new file mode 100644 index 0000000..bab1b7f --- /dev/null +++ b/.vscode/USBLoaderGX.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": ".." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..0184696 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,22 @@ +{ + "configurations": [ + { + "name": "Wii", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/source/**", + "/opt/devkitpro/devkitPPC/include/**", + "/opt/devkitpro/portlibs/ppc/include/**", + "/opt/devkitpro/libogc/include/**", + "/opt/devkitpro/libogc/include/wiiuse/**", + "/opt/devkitpro/devkitPPC/powerpc-eabi/include/**" + ], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "gnu18", + "cppStandard": "gnu++14", + "intelliSenseMode": "gcc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + 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 +. diff --git a/Languages/czech.lang b/Languages/czech.lang new file mode 100644 index 0000000..9d14327 --- /dev/null +++ b/Languages/czech.lang @@ -0,0 +1,2691 @@ +# USB Loader GX language source file. +# czech.lang - r1056 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:02+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: David Jelinek (djelinek@hotmail.com) e->e,r->r,u->u, c->c \n" +"Language-Team: r1056 - last version on http://djelinek.sweb.cz/_USBLoderGX/czech.lang \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " nelze stáhnout." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " byl uložen. Soubor nebyl zkontrolován. Nekteré cásti kódu nemusí fungovat s ostaními. Pokud dojde k problémum, overte text v editoru." + +msgid " is not on the server." +msgstr " není na serveru" + +#, c-format +msgid "%i files not found on the server!" +msgstr "" + +#, c-format +msgid "%i missing files" +msgstr "" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Každý)" + +msgid "1 (Child 7+)" +msgstr "1 (Díte 7+)" + +msgid "1 hour" +msgstr "1 hodina" + +msgid "10 min" +msgstr "10 minut" + +msgid "2 (Teen 12+)" +msgstr "2 (Mladistvý 12+)" + +msgid "20 min" +msgstr "20 minut" + +msgid "2D Cover Path" +msgstr "Cesta k 2D obalum" + +msgid "3 (Mature 16+)" +msgstr "3 (Zralý 16+)" + +msgid "3 min" +msgstr "3 minuty" + +msgid "30 min" +msgstr "30 minut" + +msgid "3D Cover Path" +msgstr "Cesta k 3D obalum" + +msgid "3D Covers" +msgstr "3D Obaly" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Pouze dospelí 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 minut" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "" + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "" + +msgid "All Partitions" +msgstr "Vsechny oddíly" + +msgid "All files extracted." +msgstr "" + +msgid "All images downloaded successfully." +msgstr "Všechny obrázky staženy úspešně." + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Všechny možnosti USB Loader GX jsou odemceny" + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Náhradní DOL" + +msgid "An example file was created here:" +msgstr "" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "Jazyk aplikace" + +msgid "Apply" +msgstr "" + +msgid "Apr" +msgstr "Dub" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "Opravdu si prejete uzamknout USB Loader GX?" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "Opravdu si prejete provest reset?" + +msgid "Are you sure?" +msgstr "Jste si jisti?" + +msgid "Aspect Ratio" +msgstr "" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "Srp" + +msgid "Author(s):" +msgstr "" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "Automatický start síte" + +msgid "BCA Codes Path" +msgstr "Cesta pro BCA kódy" + +msgid "Back" +msgstr "Zpet" + +msgid "Back to HBC or Wii Menu" +msgstr "Zpet do HBC nebo Wii nabídky" + +msgid "Backgroundmusic" +msgstr "Hudba na pozadí" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "Velké díky pro:" + +msgid "Block Categories Menu" +msgstr "" + +msgid "Block Categories Modify" +msgstr "" + +msgid "Block Cover Downloads" +msgstr "Zablokovat stažení obalů" + +msgid "Block Custom Paths" +msgstr "Zablokovat vlastní cesty" + +msgid "Block Feature Settings" +msgstr "" + +msgid "Block Game Install" +msgstr "Zablokovat instalaci her" + +msgid "Block Game Settings" +msgstr "Zablokovat nastavení her" + +msgid "Block GameID Change" +msgstr "Zablokovat zmenu ID hry" + +msgid "Block Global Settings" +msgstr "Zablokovat hlavní nastavení" + +msgid "Block Gui Settings" +msgstr "Zablokovat GUI nastavení" + +msgid "Block HBC Menu" +msgstr "Zablokovat HBC nabídku" + +msgid "Block Hard Drive Settings" +msgstr "" + +msgid "Block IOS Reload" +msgstr "Zablokovat opetovné zavedení IOS" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "Zablokovat nastavení spouštění" + +msgid "Block Parental Settings" +msgstr "Zablokovat rodičovskou kontrolu" + +msgid "Block Priiloader Override" +msgstr "" + +msgid "Block Reset Settings" +msgstr "Zablokovat původní nastavení" + +msgid "Block SD Reload Button" +msgstr "" + +msgid "Block Sound Settings" +msgstr "Zablokovat nastavení zvuku" + +msgid "Block Theme Downloader" +msgstr "Zablokovat stahování témat " + +msgid "Block Theme Menu" +msgstr "Zablokovat nabídku témat" + +msgid "Block Title Launcher" +msgstr "Zablokovat spouštění titulu" + +msgid "Block Updates" +msgstr "Zablokovat aktualizace" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "Spustit?" + +msgid "Both" +msgstr "Oboje" + +msgid "Both Ports" +msgstr "" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "" + +msgid "Can't be formatted" +msgstr "Nelze naformátovat" + +msgid "Can't create directory" +msgstr "Nelze vytvorit adresár" + +#, c-format +msgid "Can't create file: %s" +msgstr "" + +#, c-format +msgid "Can't create path: %s" +msgstr "Nelze vytvorit adresár: %s" + +msgid "Can't delete:" +msgstr "Nelze smazat:" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "" + +#, c-format +msgid "Can't read file: %s" +msgstr "" + +msgid "Cancel" +msgstr "Zrušit" + +msgid "Cannot write to destination." +msgstr "Nelze zapisovat na vybrané umístení." + +msgid "Categories" +msgstr "" + +msgid "Categories:" +msgstr "" + +msgid "Change Play Path" +msgstr "Zmena cesty prehrávání" + +msgid "Channel Launcher" +msgstr "" + +msgid "Channels" +msgstr "" + +msgid "Cheatfile is blank" +msgstr "Soubor s cheaty je prázdný" + +msgid "Clear" +msgstr "Vycistit" + +msgid "Click to Download Covers" +msgstr "Kliknete pro stažení obalu" + +msgid "Click to change game ID" +msgstr "Kliknete pro zmenu ID hry" + +msgid "Clock" +msgstr "Hodiny" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "zavrít" + +msgid "Code Download" +msgstr "Stažení kódu" + +#, c-format +msgid "Coded by: %s" +msgstr "Naprogramoval: %s" + +msgid "Coding:" +msgstr "Programování:" + +msgid "Connection to server timed out." +msgstr "Spojení se serverem vypršelo" + +msgid "Console" +msgstr "Konzole" + +msgid "Console Default" +msgstr "Puvodní nastavení konzole" + +msgid "Console Locked" +msgstr "Konzole uzamcena" + +msgid "Console must be unlocked for this option." +msgstr "Konzole musí být pro tuto možnost odemčena " + +msgid "Console must be unlocked to be able to use this." +msgstr "" + +msgid "Console should be unlocked to modify it." +msgstr "Konzole musí být odemcena pro tuto zmenu" + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "Pokracovat pri instalaci hry" + +msgid "Continue?" +msgstr "" + +msgid "Controllevel" +msgstr "Úroven rízení" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "Správné heslo" + +msgid "Could not connect to the server." +msgstr "Nelze se pripojit na server" + +msgid "Could not create GCT file" +msgstr "Nelze vytvorit GCT soubor" + +#, c-format +msgid "Could not create path: %s" +msgstr "Nelze vytvorit adresar: %s" + +msgid "Could not extract files for:" +msgstr "" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "Nelze nalézt informace pro tuto hru v wiitdb.xml." + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "Nelze inicializovat DIP modul!" + +msgid "Could not initialize network!" +msgstr "Nelze inicializovat sítové pripojení" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "Nelze otevrít disk" + +msgid "Could not open the WiiTDB.xml file." +msgstr "" + +msgid "Could not open wiitdb.xml." +msgstr "Nelze otevrít wiitdb.xml." + +msgid "Could not save." +msgstr "Nelze uložit." + +msgid "Could not write file." +msgstr "" + +msgid "Could not write to:" +msgstr "" + +msgid "Cover Download" +msgstr "Stažení obalu" + +msgid "Create" +msgstr "Vytvorit" + +msgid "Credits" +msgstr "Zásluhy" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "Vlastní cesty" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "Upravené/Originál" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "Cesta k DOL" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "List" + +msgid "Default" +msgstr "Puvodní" + +msgid "Default Gamesettings" +msgstr "Puvodní nastavení her" + +msgid "Default Settings" +msgstr "Puvodní nastavení" + +msgid "Delete" +msgstr "Smazat" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "Smazat Cheat GCT" + +msgid "Delete Cheat TXT" +msgstr "Smazat Cheat TXT" + +msgid "Delete Cover Artwork" +msgstr "Smazat obal krabicky" + +msgid "Delete Disc Artwork" +msgstr "Smazat potisk DVD" + +msgid "Delete category" +msgstr "" + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "" + +msgid "Details" +msgstr "" + +msgid "Developed by" +msgstr "Vyvinul" + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "Adresár neexistuje!" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "Stažení potisku DVD" + +msgid "Disc Artwork Path" +msgstr "Cesta k potiskum DVD" + +msgid "Disc Default" +msgstr "Puvodní nastavení disku" + +msgid "Disc Insert Detected" +msgstr "" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "" + +msgid "Display" +msgstr "Zobrazení" + +msgid "Display as a carousel" +msgstr "Zobrazit jako karusel" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "Zobrazit do mrížky" + +msgid "Display as a list" +msgstr "Zobrait jako seznam" + +msgid "Display favorites only" +msgstr "Zobrazit pouze oblíbené" + +msgid "Do you want to apply it now?" +msgstr "Prejete si aplikovat zmeny hned?" + +msgid "Do you want to apply this theme?" +msgstr "" + +msgid "Do you want to change language?" +msgstr "Prejete si zmenit jazyk?" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "Prejete si stáhnout toto téma?" + +msgid "Do you want to extract all the save games?" +msgstr "" + +msgid "Do you want to extract the save game?" +msgstr "" + +msgid "Do you want to format:" +msgstr "Prejete si formátovat" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "Prejete si nahrát výchozí téma?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "Prejete si synchronizovat informace o volných sektorech na vsech FAT 32 oddílech?" + +msgid "Do you wish to update/download all language files?" +msgstr "Prejete si zaktualizovat vsechny jazykové soubory?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "Stažení" + +msgid "Download Now" +msgstr "Stáhnout nyní" + +msgid "Download finished" +msgstr "Stažení dokonceno" + +msgid "Downloading 3D Covers" +msgstr "Stahování 3D obalu" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "Stahování plochých obalu" + +msgid "Downloading Full HQ Covers" +msgstr "" + +msgid "Downloading Full LQ Covers" +msgstr "" + +msgid "Downloading custom Discarts" +msgstr "Stahuji upravené potisky" + +msgid "Downloading file..." +msgstr "Stahuji soubor ..." + +msgid "Downloading image:" +msgstr "Stahuji obrázek:" + +msgid "Downloading original Discarts" +msgstr "Stahuji originální potisky" + +msgid "Downloading pagelist:" +msgstr "Stahuji stránku:" + +msgid "Dump NAND to EmuNand" +msgstr "" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "Dánsky" + +msgid "ERROR" +msgstr "CHYBA" + +msgid "ERROR:" +msgstr "CHYBA:" + +msgid "ERROR: Can't set up theme." +msgstr "CHYBA: Nelze nastavit téma." + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "" + +msgid "Emulated Nand" +msgstr "" + +msgid "English" +msgstr "Anglicky" + +msgid "Enter Path" +msgstr "" + +msgid "Error" +msgstr "Chyba" + +msgid "Error !" +msgstr "Chyba !" + +#, c-format +msgid "Error creating path: %s" +msgstr "Chyba pri vytvareni adresare: %s" + +msgid "Error opening downloaded file" +msgstr "Chyba pri otevirani stazeneho souboru" + +msgid "Error reading Disc" +msgstr "Nelze císt disk" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "Chyba pri stahovani souboru: %i" + +msgid "Error while downloding file" +msgstr "Chyba pri stahovani souboru" + +msgid "Error while opening the zip." +msgstr "Chyba pri otevirani ZIP" + +msgid "Error while transfering data." +msgstr "Chyba behem prenosu dat." + +msgid "Error while updating USB Loader GX." +msgstr "Chyba pri aktualizaci USB Loader GX." + +msgid "Error writing the data." +msgstr "Chyba pri zapisu dat." + +msgid "Error:" +msgstr "Chyba:" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "" + +msgid "Everything" +msgstr "" + +msgid "Exit" +msgstr "Ukoncit" + +msgid "Exit to where?" +msgstr "Opustit kam?" + +msgid "Export All Saves to EmuNand" +msgstr "" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "" + +msgid "Extracting file:" +msgstr "" + +msgid "Extracting files..." +msgstr "Rozbaluji soubory..." + +msgid "Extracting files:" +msgstr "" + +msgid "Extracting nand files:" +msgstr "" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "Neúspešné formátování" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "" + +msgid "Failed to extract." +msgstr "Nemohu rozbalit." + +msgid "Failed to initialize the USB storage device." +msgstr "" + +msgid "Failed to open partition" +msgstr "Nelze otevrít diskový oddíl" + +msgid "Failed to read ticket." +msgstr "" + +msgid "Failed to read tmd file." +msgstr "" + +msgid "Failed to read wad header." +msgstr "" + +msgid "Failed updating" +msgstr "Aktualizace selhala" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "" + +msgid "Features Settings" +msgstr "" + +msgid "Feb" +msgstr "Ún" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Soubor nenalezen" + +msgid "File read/write error." +msgstr "" + +msgid "Files extracted successfully." +msgstr "" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "Velikost souboru je %i Bytu." + +msgid "Filesize is 0 Byte." +msgstr "Velikost souboru je 0 Bytu" + +msgid "Flat Covers" +msgstr "Ploché obaly" + +msgid "Flip-X" +msgstr "" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "Vynutit NTSC" + +msgid "Force NTSC480p" +msgstr "" + +msgid "Force PAL480p" +msgstr "" + +msgid "Force PAL50" +msgstr "Vynutit PAL50" + +msgid "Force PAL60" +msgstr "Vynutit PAL60" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Formát" + +msgid "Formatting, please wait..." +msgstr "Formátuji, cekejte prosím ..." + +msgid "Found missing images." +msgstr "" + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "Volné místo" + +msgid "French" +msgstr "Francouzky" + +msgid "Full" +msgstr "" + +msgid "Full Cover Path" +msgstr "" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "Plná nabídka" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "Uplné ukoncení" + +msgid "GAMEID_Gamename" +msgstr "IdHry_NazevHry" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "Cesta pro cheat kódy" + +msgid "GCT File created" +msgstr "Soubor GCT vytvoren" + +msgid "GUI Settings" +msgstr "Nastavení GUI" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "ID hry" + +msgid "Game IOS" +msgstr "IOS hry" + +msgid "Game Language" +msgstr "Jazyk hry" + +msgid "Game Load" +msgstr "Nahrání hry" + +msgid "Game Lock" +msgstr "Zámek hry" + +msgid "Game Only" +msgstr "Pouze hry" + +msgid "Game Region" +msgstr "Region hry" + +msgid "Game Size" +msgstr "Velikost hry" + +msgid "Game Sound Mode" +msgstr "Zvukový mód hry" + +msgid "Game Sound Volume" +msgstr "Nastavení hlasitosti hry" + +msgid "Game Split Size" +msgstr "Velikost rozdelení hry" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "Hra je již nainstalována:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "Název hry [IdHry]" + +msgid "Games" +msgstr "Hry" + +msgid "Generating GXGameCategories.xml" +msgstr "" + +msgid "Genre:" +msgstr "Zánr:" + +msgid "German" +msgstr "Nemecky" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "Hlavní nastavení" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "Hlavní menu" + +msgid "Hard Drive Settings" +msgstr "" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "Cesta pro Homebrew aplikace" + +msgid "Homebrew Channel" +msgstr "Homebrew kanál" + +msgid "Homebrew Launcher" +msgstr "Spouštec Homebrew" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "Hodina" + +msgid "How do you want to update?" +msgstr "Jak si prejete provést aktualizaci?" + +msgid "How to Shutdown?" +msgstr "Jakým zpusobem ukoncit?" + +msgid "Import Categories" +msgstr "" + +msgid "Import operation successfully completed." +msgstr "" + +msgid "Importing categories" +msgstr "" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Príchozí soubor %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Príchozí soubor %0.2fMB" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "Inicializuji sítové pripojení" + +msgid "Insert Disk" +msgstr "Vložte disk" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "Instalace" + +msgid "Install Canceled" +msgstr "" + +msgid "Install Directories" +msgstr "" + +msgid "Install Error!" +msgstr "Chyba pri instalaci" + +msgid "Install Partitions" +msgstr "" + +msgid "Install a game" +msgstr "Nainstalovat hru" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "" + +msgid "Installing game:" +msgstr "Instalace hry:" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Zdá se, že máte informace, které by pro nás mohly být užitecné. Odešlete prosím tuto informaci na náš DEV tým." + +msgid "Italian" +msgstr "Italsky" + +msgid "Jan" +msgstr "Led" + +msgid "Japanese" +msgstr "Japonsky" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "Cervenec" + +msgid "June" +msgstr "Cerven" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Klávesnice" + +msgid "Korean" +msgstr "Korejsky" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "" + +msgid "Language change:" +msgstr "Zmena jazyka:" + +msgid "Languagefiles Path" +msgstr "Cesta k jazykovym souborum" + +msgid "Languagepath changed." +msgstr "Cesta k jazykum zmenena" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Left" +msgstr "Vlevo" + +msgid "Like SysMenu" +msgstr "Jako hlavní menu" + +msgid "List on Gamelaunch" +msgstr "Seznam pri spustení hry" + +msgid "Load" +msgstr "Spustit" + +msgid "Load From SD/USB" +msgstr "Nahrát z SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Nahrát soubor z: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Spustit tento DOL jako náhradní DOL?" + +msgid "Loader Settings" +msgstr "Nstavení spoustení" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "Nahrávám puvodní jazyk" + +msgid "Loading standard music." +msgstr "Nahrávám puvodní hudbu" + +msgid "Lock Console" +msgstr "Zamcení konzole" + +msgid "Lock USB Loader GX" +msgstr "Zamcení USB Loader GX" + +msgid "Locked" +msgstr "Zamceno" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "Adresárová smycka" + +msgid "Loop Music" +msgstr "Hudební smycka" + +msgid "Loop Sound" +msgstr "Zvuková smycka" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "Brez" + +msgid "Mark new games" +msgstr "Oznacir nové hry" + +msgid "May" +msgstr "Kvet" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "Aktualizace nástenky" + +msgid "Motion+ Video" +msgstr "WiiMotion+ Video" + +msgid "Mount DVD drive" +msgstr "Spustit z DVD" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "" + +msgid "Music Loop Mode" +msgstr "Mód hudební smycky" + +msgid "Music Volume" +msgstr "Hlasitost hudby" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "" + +msgid "Nand Channels" +msgstr "" + +msgid "Nand Emu Channel Path" +msgstr "" + +msgid "Nand Emu Path" +msgstr "" + +msgid "Nand Emulation" +msgstr "" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Žádný" + +msgid "Network is not initiated." +msgstr "Sít není inicializována" + +msgid "Next" +msgstr "Další" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "Ne" + +msgid "No Cheatfile found" +msgstr "Nebyl nalezen soubor s cheaty" + +msgid "No DOL file found on disc." +msgstr "Na disku nebyl nalezen DOL soubor." + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "Bez rozdelování" + +msgid "No URL or Path specified." +msgstr "Nebylo zadano URL nebo cesta." + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "Nebyl nalezen oddíl WBFS nebo FAT/NTFS/EXT" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "Nelze císt data?" + +msgid "No disc inserted." +msgstr "" + +msgid "No favorites selected." +msgstr "Oblíbené nejsou oznaceny" + +msgid "No file missing!" +msgstr "Nechybí žádný soubor!" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "" + +msgid "No new updates." +msgstr "Není dostupná žádná aktualizace." + +msgid "No themes found on the site." +msgstr "Žádné téma nebylo nalezeno na serveru." + +msgid "No themes found." +msgstr "" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "Žádný" + +msgid "Normal" +msgstr "Normální" + +msgid "Not Initialized" +msgstr "" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "Neplatné URL" + +msgid "Not a valid URL path" +msgstr "Neplatná URL cesta" + +msgid "Not a valid domain" +msgstr "Neplatný název domény" + +msgid "Not enough free memory." +msgstr "Není dostatek volné pameti." + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "Není dostatek volného místa!" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "Nedostatek pameti" + +msgid "Not required" +msgstr "Není nutné" + +msgid "Not supported format!" +msgstr "Nepodporovaný formát!" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "List" + +msgid "OFF" +msgstr "Vypnuto" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "Zapnuto" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "Ocarina (cheaty)" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Ríj" + +msgid "Official Site:" +msgstr "Oficiální místo:" + +msgid "Offset" +msgstr "Ofset" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "Pouze oddíl s hrami" + +msgid "Only for Install" +msgstr "Pouze pro instalaci" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Originál/Upravené" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Rodicovský zámek" + +msgid "Partial" +msgstr "" + +msgid "Partition" +msgstr "Oddíl" + +msgid "Password" +msgstr "Heslo" + +msgid "Password Changed" +msgstr "Heslo zmeneno" + +msgid "Password has been changed" +msgstr "Heslo bylo zmeneno" + +msgid "Patch Country Strings" +msgstr "Úprava nastavení zeme" + +msgid "Path Changed" +msgstr "Cesta zmenena" + +msgid "Permission denied." +msgstr "Prístup odmítnut" + +msgid "Pick from a list" +msgstr "Vyberte ze seznamu" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Spušteno" + +msgid "Play Next" +msgstr "Prehrát další" + +msgid "Play Once" +msgstr "Prehrát jednou" + +msgid "Play Previous" +msgstr "Prehrát predchozí" + +msgid "Playing Music:" +msgstr "Prehrávání hudby:" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "Cekejte prosím..." + +msgid "Power off the Wii" +msgstr "Vypnout Wii" + +msgid "Prev" +msgstr "Predchozí" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Potvrzovací tlacítka" + +msgid "Published by" +msgstr "Publikoval " + +msgid "Quick Boot" +msgstr "Rychlé zavedení" + +msgid "Random Directory Music" +msgstr "Náhodné prehrávání hudby" + +msgid "Real Nand" +msgstr "" + +msgid "Receiving file from:" +msgstr "Prijímám soubor z:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "Patch regionu" + +msgid "Released" +msgstr "Uvolnil" + +msgid "Reload SD" +msgstr "Znovunactení SD" + +msgid "Reloading game list now, please wait..." +msgstr "" + +msgid "Remember Unlock" +msgstr "" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "Odstranit aktualizaci" + +msgid "Rename Game Title" +msgstr "" + +msgid "Rename category" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Reset BG Music" +msgstr "Obnovit hudbu na pozadí" + +msgid "Reset Playcounter" +msgstr "Vynulovat cítac spuštení" + +msgid "Reset to default BGM?" +msgstr "Vrátit puvodní hudbu na pozadí?" + +msgid "Restarting..." +msgstr "Restartuji..." + +msgid "Return" +msgstr "Návrat" + +msgid "Return To" +msgstr "Návrat do" + +msgid "Return to Wii Menu" +msgstr "Návrat do Wii nabídky" + +msgid "Right" +msgstr "Vpravo" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Vibrace" + +msgid "SChinese" +msgstr "Cínsky" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "Hlasitost SFX" + +msgid "Save" +msgstr "Uložit" + +msgid "Save Failed. No device inserted?" +msgstr "Ulození selhalo. Je pripojeno zarízení?" + +msgid "Save Game List to" +msgstr "Uložit seznam her do" + +msgid "Save List" +msgstr "" + +msgid "Saved" +msgstr "Uloženo" + +msgid "Savegame might not exist for this game." +msgstr "" + +msgid "Screensaver" +msgstr "Sporic obrazovky" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "Vyber" + +msgid "Select DOL Offset" +msgstr "Vyberte DOL ofset" + +msgid "Select a DOL" +msgstr "Vyberte DOL" + +msgid "Select a DOL from Game" +msgstr "Vybrat DOL ze hry" + +msgid "Select game categories" +msgstr "" + +msgid "Select loader mode" +msgstr "" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "" + +msgid "Sept" +msgstr "Zárí" + +msgid "Set Search-Filter" +msgstr "Nastavit vyhledávací filtr" + +msgid "Settings" +msgstr "Nastavení" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "Zobrazit volné místo" + +msgid "Show Play Count" +msgstr "" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "Ukoncit systém" + +msgid "Shutdown Wii" +msgstr "Vypnout Wii" + +msgid "Skip Errors" +msgstr "" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Trídení dle abecedy" + +msgid "Sort by number of players" +msgstr "" + +msgid "Sort by rank" +msgstr "Trídit podle hodnocení" + +msgid "Sort order by most played" +msgstr "Trídení podle spuštení" + +msgid "Sound" +msgstr "Zvuk" + +msgid "Sound Settings" +msgstr "Nastavení zvuku" + +msgid "Sound+BGM" +msgstr "Zvuk+BGM" + +msgid "Sound+Quiet" +msgstr "Zvuk+ticho" + +msgid "Spanish" +msgstr "Španelsky" + +msgid "Special thanks to:" +msgstr "Speciální podekování pro" + +msgid "Split each 2GB" +msgstr "Rozdelit po 2GB" + +msgid "Split each 4GB" +msgstr "Rozdelit po 4GB" + +msgid "Standby" +msgstr "Uspání" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "Úspešne" + +msgid "Success." +msgstr "" + +msgid "Success:" +msgstr "Úspešne:" + +msgid "Successfully Saved" +msgstr "Úspešne uloženo" + +msgid "Successfully Updated" +msgstr "Úspešne zaktualizováno" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "Úspešne smazáno:" + +msgid "Successfully extracted theme." +msgstr "Úspešne rozbalené téma." + +msgid "Successfully installed:" +msgstr "Úspešne nainstalováno" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "" + +msgid "Sync FAT32 FS Info" +msgstr "FAT32 volné místo" + +msgid "Synchronizing..." +msgstr "Synchronizuji ..." + +msgid "System Default" +msgstr "Puvodní nastavení systému" + +msgid "TChinese" +msgstr "Cínsky" + +msgid "TXT Cheatcodes Path" +msgstr "Cesta k TXT cheatum" + +msgid "The .them file was not found in the zip." +msgstr "Soubor .them nebyl nalezen v ZIP." + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "Zadaný adresár neexistuje. Chcete ho vytvorit?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "Soubor WAD byl nainstalován" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "Instalace souboru WAD selhala s chybou %i" + +msgid "Theme Downloader" +msgstr "Stahování témat" + +msgid "Theme Menu" +msgstr "" + +msgid "Theme Path" +msgstr "Cesta k tématum" + +msgid "Theme Title:" +msgstr "Název tématu" + +msgid "Themes by www.spiffy360.com" +msgstr "Téma od www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "Tento IOS je BootMii IOS. Pokud si jste jisti ze toto není BootMii a máte zde nainstalováno neco jiného, pak ignorujte toto varování." + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "Tento IOS nebyl nalezen na seznamu. Pokud si jste jisti ze jej máte nainstalován, pak ignorujte toto varování." + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "Zbývá:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Spouštec kanálu" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "Popisky" + +msgid "Transfer failed" +msgstr "Prenos selhal" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX je zabezpecen" + +msgid "USB Port" +msgstr "" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "Odinstalace" + +msgid "Uninstall Game" +msgstr "Odinstalace hry" + +msgid "Uninstall Menu" +msgstr "Menu odinstalací" + +msgid "Uninstall all" +msgstr "Odinstalovat vse" + +msgid "Unknown" +msgstr "Neznámé" + +msgid "Unlock USB Loader GX" +msgstr "Odemknout USB Loader GX" + +msgid "Unlocked" +msgstr "Odemceno" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "Nepodporovaný formát, poskuste se rucne rozbalit TempTheme.zip." + +msgid "Update" +msgstr "Aktualizace" + +msgid "Update All" +msgstr "Plná aktualizace" + +msgid "Update DOL" +msgstr "Aktualizace DOL" + +msgid "Update Files" +msgstr "Zaktualizuj soubory" + +msgid "Update Path" +msgstr "Cesta pro aktualizaci" + +msgid "Update all Language Files" +msgstr "Zaktualizuj vsechny jazykové soubory" + +msgid "Update failed" +msgstr "Aktualizace selhala" + +msgid "Update successfull" +msgstr "Aktualizace probehla uspesne" + +msgid "Updating Language Files:" +msgstr "Aktualizuji jazykové soubory:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Odeslaný ZIP soubor nainstalován do adresáre homebrew" + +msgid "Use System Font" +msgstr "" + +msgid "Use global" +msgstr "" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "VIDTV korekce" + +msgid "Version:" +msgstr "" + +#, c-format +msgid "Version: %s" +msgstr "Verze: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Video mód" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "" + +msgid "WDM Files Path" +msgstr "Cesta k WDM soborum" + +msgid "WIP Patches Path" +msgstr "Cesta k WIP patchum" + +msgid "Waiting..." +msgstr "Cekám..." + +msgid "Warning" +msgstr "" + +msgid "Warning:" +msgstr "Varování:" + +msgid "What do you want to do?" +msgstr "" + +msgid "What do you want to update?" +msgstr "Co si prejete zaktualizovat?" + +msgid "What should be deleted for this game title:" +msgstr "Co si prejete smazat pro tento titul:" + +msgid "What to extract from NAND?" +msgstr "" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "WiFi možnosti" + +msgid "Widescreen Factor" +msgstr "" + +msgid "Widescreen Fix" +msgstr "Korekce širokoúhlé obrazovky" + +msgid "Wii Games" +msgstr "" + +msgid "Wii Menu" +msgstr "Wii menu" + +msgid "Wii Settings" +msgstr "Nastavení Wii" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "Wii svetlo" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "" + +msgid "Wiird Debugger" +msgstr "" + +#, c-format +msgid "Write error on file: %s" +msgstr "" + +msgid "Writing GXGameCategories.xml" +msgstr "" + +msgid "Wrong Password" +msgstr "Špatné heslo" + +msgid "Yes" +msgstr "Ano" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "Pokousíte se vybrat oddíl FAT32/NTFS/EXT s cIOS 249 Rev < 18. To není podporováno. Pokracujte na vasi odpovednost." + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "" + +msgid "You cannot delete this category." +msgstr "" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "a prekladatelé pro jazykové aktualizace" + +msgid "available" +msgstr "dostupný" + +msgid "does not exist!" +msgstr "neexistuje!" + +msgid "does not exist! Loading game without cheats." +msgstr "neexistuje. Nahrávání hry bez cheatu." + +msgid "files left" +msgstr "souboru zbývá" + +msgid "for FAT/NTFS support" +msgstr "pro FAT/NTFS podporu" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "" + +msgid "for Ocarina" +msgstr "za Ocarina" + +msgid "for diverse patches" +msgstr "za ruzné opravy" + +msgid "for his awesome tool LibWiiGui" +msgstr "za jeho hrozný nástroj LibWiiGui" + +msgid "for hosting the themes" +msgstr "pro hostování témat" + +msgid "for the USB Loader source" +msgstr "za zdrojový kód pro USB Loader" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "formátováno!" + +msgid "free" +msgstr "volné" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "nenastaveno" + +msgid "of" +msgstr "z " + +msgid "seconds left" +msgstr "sekund zbývá" + +#~ msgid "Error 002 fix" +#~ msgstr "Oprava chyby 002" + +#~ msgid "Main tester:" +#~ msgstr "Muj tester:" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "Prejmenovat hru na WBFS" + +#~ msgid "Successfully Updated thanks to www.techjawa.com" +#~ msgstr "Úspešne zaktualizováno díky www.techjawa.com" + +#~ msgid "for hosting the update files" +#~ msgstr "za umístení souboru pro aktualizaci " + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Vložte Wii disk" + +#~ msgid "Issue manager /" +#~ msgstr "Správce problému" + +#~ msgid "No cheats were selected" +#~ msgstr "Nebyly vybrány žádné cheaty" + +#~ msgid "Not a Wii Disc" +#~ msgstr "Toto není Wii disk" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> Odstraňuji tikety..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> Odstraňuji tikety...CHYBA! " + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> Odstraňuji tikety...Ok! " + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> Odstraňuji titul...CHYBA! " + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> Odstraňuji titul...Ok!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> Odstraňuji obsah titulu..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> Odstraňuji obsah titulu...CHYBA! " + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> Odstraňuji obsah titulu...Ok!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> Odstraňuji titul..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> Ukoncuji instalaci..." + +#~ msgid ">> Installing content #" +#~ msgstr ">> Instaluji obsah #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> Instaluji tiket..." + +#~ msgid ">> Installing title..." +#~ msgstr ">> Instaluji titul..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> Nacítám WAD data..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> Nacítám WAD data...CHYBA! " + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> Nacítám WAD data...Ok! " + +#~ msgid "Done!" +#~ msgstr "Hotovo!" + +#~ msgid "Error..." +#~ msgstr "Chyba..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "Ukoncuji instalaci... Ok!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "Instaluji obsah... Ok!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "Instaluji tiket... Ok!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "Instaluji titul... Ok!" + +#~ msgid "Installing wad" +#~ msgstr "Instaluji WAD" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "Nacítám WAD data... Ok!" + +#~ msgid "Uninstalling wad" +#~ msgstr "Odinstalace WAD" + +#~ msgid "The game installation is disabled under this IOS because of instability in usb write." +#~ msgstr "Instalace her je zakázána s tímto IOS kvuli nestabilite v USB zápisu." + +#~ msgid "You are currently using IOS" +#~ msgstr "Nyní pouzíváte IOS:" + +#~ msgid "New Disc Detected" +#~ msgstr "Detekován nový disk" + +#~ msgid "USB Device not found" +#~ msgstr "USB zarízení nenalezeno" + +#~ msgid "You need to select or format a partition" +#~ msgstr "Musíte vybrat nebo naformátovat oddíl" + +#~ msgid "Language File" +#~ msgstr "Jazykový soubor" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Názvy z WiiTDB" + +#~ msgid "WiiTDB Files" +#~ msgstr "WiiTDB Soubory" + +#~ msgid "WiiTDB Path" +#~ msgstr "Cesta k WiiTDB" + +#~ msgid "WiiTDB is up to date." +#~ msgstr "WiiTDB je aktuální" + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "za WiiTDB a hostování obalu / potisku DVD" + +#~ msgid "Install directories" +#~ msgstr "Instalacní adresáre" + +#~ msgid "Install partitions" +#~ msgstr "Instalacní oddíly" + +#~ msgid " Wad Saved as:" +#~ msgstr " WAD uložen jako:" + +#~ msgid "Delete ?" +#~ msgstr "Smazat?" + +#~ msgid "Keep" +#~ msgstr "Držet" + +#~ msgid "Not a WAD file." +#~ msgstr "Nejedná se o WAD soubor." + +#~ msgid "Author:" +#~ msgstr "Autor:" + +#~ msgid "Do you want to load this theme?" +#~ msgstr "Prejete si nahrát toto téma?" + +#~ msgid "Loading default theme." +#~ msgstr "Nahrávám původní téma." + +#~ msgid "Theme path is changed." +#~ msgstr "Cesta k tématum zmenena" + +#~ msgid "Use IOS58" +#~ msgstr "Použít IOS58" + +#~ msgid "Custom Disc Images" +#~ msgstr "Vlastní potisky DVD" + +#~ msgid "Download Boxart image?" +#~ msgstr "Stáhnout obal krabicky?" + +#~ msgid "Download Discart image?" +#~ msgstr "Stáhnout potisk DVD?" + +#~ msgid "Downloading file" +#~ msgstr "Stahuji soubor" + +#~ msgid "Missing files" +#~ msgstr "Chybející soubory" + +#~ msgid "Original Disc Images" +#~ msgstr "Originální potisky DVD" + +#~ msgid "files not found on the server!" +#~ msgstr "souboru nenalezeno na serveru" diff --git a/Languages/danish.lang b/Languages/danish.lang new file mode 100644 index 0000000..805be47 --- /dev/null +++ b/Languages/danish.lang @@ -0,0 +1,2595 @@ +# USB Loader GX language source file. +# danish.lang - r1148 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:02+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: Fox888[dk]\n" +"Language-Team: [dk]\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " kunne ikke downloades." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " er blevet gemt. Koderne er ikke blevet kontrolleret. Nogle af koderne virker måske ikke samtidigt. Hvis der er problemer, åbn da tekstfilen i en editor for at få mere information." + +msgid " is not on the server." +msgstr " er ikke på serveren." + +#, c-format +msgid "%i files not found on the server!" +msgstr "%i filer ikke fundet på server!" + +#, c-format +msgid "%i missing files" +msgstr "%i filer mangler" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Alle)" + +msgid "1 (Child 7+)" +msgstr "1 (Børn 7+)" + +msgid "1 hour" +msgstr "1 time" + +msgid "10 min" +msgstr "10 min." + +msgid "2 (Teen 12+)" +msgstr "2 (teenagere 12+)" + +msgid "20 min" +msgstr "20 min." + +msgid "2D Cover Path" +msgstr "Sti til 2-d covers" + +msgid "3 (Mature 16+)" +msgstr "3 (teenagere 16+)" + +msgid "3 min" +msgstr "3 min." + +msgid "30 min" +msgstr "30 min." + +msgid "3D Cover Path" +msgstr "Sti til 3-d covers" + +msgid "3D Covers" +msgstr "3D-Covers" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Voksne 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 min." + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "Tilføje kategori" + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "Alle" + +msgid "All Partitions" +msgstr "Alle Partitioner" + +msgid "All files extracted." +msgstr "Alle filer er udpakket." + +msgid "All images downloaded successfully." +msgstr "Lykkedes at downloade alle billeder." + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Alle USB Loader GX's funktioner er låst op." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Alternativ DOL" + +msgid "An example file was created here:" +msgstr "En f.eks. fil er lavet her:" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "Programsprog" + +msgid "Apply" +msgstr "Indlæs" + +msgid "Apr" +msgstr "" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "Er du sikker på at du ville slette denne kategori?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "Er du sikker på at du ville hente Spil kategorier fra GameTDB?" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "Er du sikker på at du vil låse USB Loader GX?" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "Er du sikker på at du vil nulstille?" + +msgid "Are you sure?" +msgstr "Er du sikker?" + +msgid "Aspect Ratio" +msgstr "Formatforhold" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "" + +msgid "Author(s):" +msgstr "Forfatter" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "AutoInit netværk" + +msgid "BCA Codes Path" +msgstr "Sti til BCA koder" + +msgid "Back" +msgstr "Tilbage" + +msgid "Back to HBC or Wii Menu" +msgstr "Tilbage til HBC eller Wii-menuen" + +msgid "Backgroundmusic" +msgstr "Baggrundsmusik" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "En stor tak til:" + +msgid "Block Categories Menu" +msgstr "Bloker kategori menu" + +msgid "Block Categories Modify" +msgstr "Bloker kategori modificering" + +msgid "Block Cover Downloads" +msgstr "Bloker Cover downloads" + +msgid "Block Custom Paths" +msgstr "Bloker brugdefineret sti" + +msgid "Block Feature Settings" +msgstr "Bloker særlige indstillinger" + +msgid "Block Game Install" +msgstr "Bloker spil installering" + +msgid "Block Game Settings" +msgstr "Bloker Spil indstillinger" + +msgid "Block GameID Change" +msgstr "Bloker Spil ID ændringer" + +msgid "Block Global Settings" +msgstr "Bloker hoved indstillinger" + +msgid "Block Gui Settings" +msgstr "Bloker Gui indstillinger" + +msgid "Block HBC Menu" +msgstr "Bloker HBC menu" + +msgid "Block Hard Drive Settings" +msgstr "Bloker Hard disk indstillinger" + +msgid "Block IOS Reload" +msgstr "Blokér IOS-reload" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "Bloker Loader mode knap" + +msgid "Block Loader Settings" +msgstr "Bloker loader indstillinger" + +msgid "Block Parental Settings" +msgstr "Bloker forældre indstillinger" + +msgid "Block Priiloader Override" +msgstr " Bloker Priiloader override" + +msgid "Block Reset Settings" +msgstr "Bloker nulstils indstillinger" + +msgid "Block SD Reload Button" +msgstr "Blocker SD reload knap" + +msgid "Block Sound Settings" +msgstr "Bloker lyd indstillinger" + +msgid "Block Theme Downloader" +msgstr "Bloker tema downloader" + +msgid "Block Theme Menu" +msgstr "Bloker tema menu" + +msgid "Block Title Launcher" +msgstr "Bloker indlæsning af titler" + +msgid "Block Updates" +msgstr "Bloker opdateringer" + +msgid "Boot Content" +msgstr "indlæs indhold" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "Genstart?" + +msgid "Both" +msgstr "Begge" + +msgid "Both Ports" +msgstr "Begge porte" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "Cache titler" + +msgid "Can't be formatted" +msgstr "Kan ikke formateres" + +msgid "Can't create directory" +msgstr "Kan ikke lave ny mappe" + +#, c-format +msgid "Can't create file: %s" +msgstr "Kan ikke lave fil: %s" + +#, c-format +msgid "Can't create path: %s" +msgstr "Kan ikke lave sti: %s" + +msgid "Can't delete:" +msgstr "Kan ikke slettes:" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "Kan ikke åbne fil: %s" + +#, c-format +msgid "Can't read file: %s" +msgstr "Kan ikke læse fil: %s" + +msgid "Cancel" +msgstr "Annullér" + +msgid "Cannot write to destination." +msgstr "Kan ikke skrive til destinationen." + +msgid "Categories" +msgstr "Kategorier" + +msgid "Categories:" +msgstr "Kategorier:" + +msgid "Change Play Path" +msgstr "Ændre sti til musik" + +msgid "Channel Launcher" +msgstr "Kanal Launcher" + +msgid "Channels" +msgstr "Kanaler" + +msgid "Cheatfile is blank" +msgstr "Cheatfilen er tom" + +msgid "Clear" +msgstr "Ryd" + +msgid "Click to Download Covers" +msgstr "Klik for at downloade covers" + +msgid "Click to change game ID" +msgstr "Klik for at ændre spil-ID" + +msgid "Clock" +msgstr "Ur" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "Luk" + +msgid "Code Download" +msgstr "Download af koder" + +#, c-format +msgid "Coded by: %s" +msgstr "Programmeret af: %s" + +msgid "Coding:" +msgstr "Programmering:" + +msgid "Connection to server timed out." +msgstr "Forbindelse til server timed out." + +msgid "Console" +msgstr "Konsol" + +msgid "Console Default" +msgstr "Konsol-standard" + +msgid "Console Locked" +msgstr "Konsollen er låst" + +msgid "Console must be unlocked for this option." +msgstr "Konsollen skal være låst op for denne mulighed." + +msgid "Console must be unlocked to be able to use this." +msgstr "Konsollen skal være låst op for at kunne bruge dette." + +msgid "Console should be unlocked to modify it." +msgstr "Konsollen skal være låst op for ændre dette." + +msgid "Continue" +msgstr "Fortsæt" + +msgid "Continue to install game?" +msgstr "Fortsæt med at installere spillet?" + +msgid "Continue?" +msgstr "Fortsæt?" + +msgid "Controllevel" +msgstr "Kontrolniveau" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "Korrekt Password" + +msgid "Could not connect to the server." +msgstr "Kunne ikke forbinde til server." + +msgid "Could not create GCT file" +msgstr "Kunne ikke oprette GCT-fil" + +#, c-format +msgid "Could not create path: %s" +msgstr "Kunne ikke lave sti: %s" + +msgid "Could not extract files for:" +msgstr "Kunne ikke udpakker filer for:" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "Kunne ikke finde information for dette spil i wiitdb.xml" + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "Kunne ikke initialisere DIP-modul!" + +msgid "Could not initialize network!" +msgstr "Kunne ikke initialisere netforbindelse!" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "Kunne ikke åbne DVD" + +msgid "Could not open the WiiTDB.xml file." +msgstr "Kunne ikke åbne WiiTDB.xml fil." + +msgid "Could not open wiitdb.xml." +msgstr "Kunne ikke åbne wiitdb.xml" + +msgid "Could not save." +msgstr "Kunne ikke gemme." + +msgid "Could not write file." +msgstr "Kunne ikke skrive fil" + +msgid "Could not write to:" +msgstr "Kunne ikke skrive til:" + +msgid "Cover Download" +msgstr "Cover-download" + +msgid "Create" +msgstr "Opret" + +msgid "Credits" +msgstr "Lavet af:" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "Sti-indstillinger" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "Tilpassede/Originale" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "Sti til DOL" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "" + +msgid "Default" +msgstr "Standard" + +msgid "Default Gamesettings" +msgstr "Standard spil-indstillinger" + +msgid "Default Settings" +msgstr "Standardindstillinger" + +msgid "Delete" +msgstr "Slet" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "Slet cheat GCT" + +msgid "Delete Cheat TXT" +msgstr "Slet Cheat TXT" + +msgid "Delete Cover Artwork" +msgstr "Slet boxart" + +msgid "Delete Disc Artwork" +msgstr "Slet DVD-billede" + +msgid "Delete category" +msgstr "Slet kategori" + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "" + +msgid "Details" +msgstr "Detaljer" + +msgid "Developed by" +msgstr "Udviklet af" + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "Mappen eksisterer ikke!" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "Download DVD-billeder" + +msgid "Disc Artwork Path" +msgstr "Sti til DVD-billeder" + +msgid "Disc Default" +msgstr "Spillets standard" + +msgid "Disc Insert Detected" +msgstr "Ny Disc opdaget" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "" + +msgid "Display" +msgstr "Spilinfo." + +msgid "Display as a carousel" +msgstr "Vis som karusel" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "Vis som tabel" + +msgid "Display as a list" +msgstr "Vis som liste" + +msgid "Display favorites only" +msgstr "Vis kun favoritter" + +msgid "Do you want to apply it now?" +msgstr "Skal det aktiveres nu?" + +msgid "Do you want to apply this theme?" +msgstr "Vil du inlæse dette tema?" + +msgid "Do you want to change language?" +msgstr "Skal sproget ændres?" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "Skal dette tema downloades?" + +msgid "Do you want to extract all the save games?" +msgstr "Vil du udpakke alle save games?" + +msgid "Do you want to extract the save game?" +msgstr "Vil du udpakke dette save game?" + +msgid "Do you want to format:" +msgstr "Vil du formatere:" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "Vil du indlæse standard tema?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "Vil du genetablere netværket?" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "Vil du synkronisere fri plads info sector på alle FAT32 Partitioner?" + +msgid "Do you wish to update/download all language files?" +msgstr "Skal alle sprogfiler opdateres/downloades?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "" + +msgid "Download Now" +msgstr "Download nu" + +msgid "Download finished" +msgstr "Download færdig" + +msgid "Downloading 3D Covers" +msgstr "Downloader 3D Covers" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "Downloader Flade Covers" + +msgid "Downloading Full HQ Covers" +msgstr "Downloader Fuld HQ Covers" + +msgid "Downloading Full LQ Covers" +msgstr "Downloader Fuld LQ Covers" + +msgid "Downloading custom Discarts" +msgstr "Downloader tilpasset DVD billeder" + +msgid "Downloading file..." +msgstr "Downloader fil..." + +msgid "Downloading image:" +msgstr "Downloader billede:" + +msgid "Downloading original Discarts" +msgstr "Downloader org. DVD billeder" + +msgid "Downloading pagelist:" +msgstr "Downloader pagelist:" + +msgid "Dump NAND to EmuNand" +msgstr "Kopier Wii NAND til EmuNand" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "Hollandsk" + +msgid "ERROR" +msgstr "FEJL" + +msgid "ERROR:" +msgstr "FEJL:" + +msgid "ERROR: Can't set up theme." +msgstr "FEJL: Temaet kan ikke bruges." + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "EmuNand kanaler" + +msgid "Emulated Nand" +msgstr "Emuleret Nand" + +msgid "English" +msgstr "Engelsk" + +msgid "Enter Path" +msgstr "Skriv sti" + +msgid "Error" +msgstr "Fejl" + +msgid "Error !" +msgstr "Fejl!" + +#, c-format +msgid "Error creating path: %s" +msgstr "Fejl kunne ikke lave sti: %s" + +msgid "Error opening downloaded file" +msgstr "Fejl kunne ikke åbne downloadet fil" + +msgid "Error reading Disc" +msgstr "DVDen kunne ikke læses" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "Fejl kunne ikke download fil: %i" + +msgid "Error while downloding file" +msgstr "Fejl under hentning af fil" + +msgid "Error while opening the zip." +msgstr "Fejl under udpakning af zip fil." + +msgid "Error while transfering data." +msgstr "Fejl under overførsel af data." + +msgid "Error while updating USB Loader GX." +msgstr "Fejl under opdatering af USB Loader GX." + +msgid "Error writing the data." +msgstr "Fejl kunne ikke skrive data." + +msgid "Error:" +msgstr "Fejl:" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "Fejl opstået" + +msgid "Everything" +msgstr "Alt" + +msgid "Exit" +msgstr "Forlad" + +msgid "Exit to where?" +msgstr "Hvorhen?" + +msgid "Export All Saves to EmuNand" +msgstr "Kopier alle saves til EmuNand" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "Kopier Save til EmuNand" + +msgid "Extracting file:" +msgstr "Udpakker Fil:" + +msgid "Extracting files..." +msgstr "Pakker filer ud..." + +msgid "Extracting files:" +msgstr "Udpakker Filer:" + +msgid "Extracting nand files:" +msgstr "Udpakker nand filer:" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "Fejlede" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "Formateringen mislykkedes" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "Fejlede at udpakke alle filer. Savegame eksistere muligvis ikke." + +msgid "Failed to extract." +msgstr "Udpakningen mislykkedes." + +msgid "Failed to initialize the USB storage device." +msgstr "Fejlede at initialisere USB enheden." + +msgid "Failed to open partition" +msgstr "Kunne ikke åbne partition" + +msgid "Failed to read ticket." +msgstr "Kunne ikke læse ticket." + +msgid "Failed to read tmd file." +msgstr "Kunne ikke læse tmd fil." + +msgid "Failed to read wad header." +msgstr "Kunne ikke læse wad header." + +msgid "Failed updating" +msgstr "Opdatering fejlede" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "Særlige" + +msgid "Features Settings" +msgstr "Særlige indstillinger" + +msgid "Feb" +msgstr "" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Fil ikke fundet." + +msgid "File read/write error." +msgstr "Fil læse/skrive fejl." + +msgid "Files extracted successfully." +msgstr "Lykkes at udpakke filer." + +#, c-format +msgid "Filesize is %i Byte." +msgstr "Fil størrelse er %i Byte." + +msgid "Filesize is 0 Byte." +msgstr "Fil størrelse er 0 Byte." + +msgid "Flat Covers" +msgstr "Flad Cover" + +msgid "Flip-X" +msgstr "" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "" + +msgid "Force 16:9" +msgstr "Tving 16:9" + +msgid "Force 4:3" +msgstr "Tving 4:3" + +msgid "Force NTSC" +msgstr "Tving NTSC" + +msgid "Force NTSC480p" +msgstr "Tving NTSC480p" + +msgid "Force PAL480p" +msgstr "Tving PAL480p" + +msgid "Force PAL50" +msgstr "Tving PAL50" + +msgid "Force PAL60" +msgstr "Tving PAL60" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Formater" + +msgid "Formatting, please wait..." +msgstr "Formatere, vent venligst..." + +msgid "Found missing images." +msgstr "Fundet manglende billeder" + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "Ledig plads" + +msgid "French" +msgstr "Fransk" + +msgid "Full" +msgstr "Fuld" + +msgid "Full Cover Path" +msgstr "Sti til Fuld Cover" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "Fuld Menu" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "Luk helt ned" + +msgid "GAMEID_Gamename" +msgstr "" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "Sti til cheatcodes" + +msgid "GCT File created" +msgstr "GCT-fil oprettet" + +msgid "GUI Settings" +msgstr "Konfigurér GUI" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "Spil-ID" + +msgid "Game IOS" +msgstr "Spil-IOS" + +msgid "Game Language" +msgstr "Sprog" + +msgid "Game Load" +msgstr "Spilindstillinger" + +msgid "Game Lock" +msgstr "Spil låst" + +msgid "Game Only" +msgstr "Kun Spil" + +msgid "Game Region" +msgstr "Region" + +msgid "Game Size" +msgstr "Spilstørrelse" + +msgid "Game Sound Mode" +msgstr "Spillyd" + +msgid "Game Sound Volume" +msgstr "Spillyd lydstyrke" + +msgid "Game Split Size" +msgstr "Spil Split størrelse" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "Dette spil er allerede installeret:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "Spil/Installation partition" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "" + +msgid "Games" +msgstr "Spil" + +msgid "Generating GXGameCategories.xml" +msgstr "Opretter GXGameCategories.xml" + +msgid "Genre:" +msgstr "Genre:" + +msgid "German" +msgstr "Tysk" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "Almindelig Indstillinger" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "" + +msgid "Hard Drive Settings" +msgstr "Hard Disk instillinger" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "Sti til homebrew-programmer" + +msgid "Homebrew Channel" +msgstr "Homebrew Kanal" + +msgid "Homebrew Launcher" +msgstr "Homebrew-starter" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "timer" + +msgid "How do you want to update?" +msgstr "Hvordan skal der opdateres?" + +msgid "How to Shutdown?" +msgstr "Hvordan skal der slukkes?" + +msgid "Import Categories" +msgstr "Importer kategorier" + +msgid "Import operation successfully completed." +msgstr "Import operation er færdig med succes" + +msgid "Importing categories" +msgstr "Importere kategorier" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Henter fil %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Henter fil %0.2fMB" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "Initialiserer netforbindelse" + +msgid "Insert Disk" +msgstr "Indsæt en DVD" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "Installér" + +msgid "Install Canceled" +msgstr "installering annulleret" + +msgid "Install Directories" +msgstr "Installer mappe" + +msgid "Install Error!" +msgstr "Installationsfejl!" + +msgid "Install Partitions" +msgstr "Installer partitioner" + +msgid "Install a game" +msgstr "Installér nyt spil" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "Installering færdig" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "Installerer indhold" + +msgid "Installing game:" +msgstr "Installerer spillet:" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "Ugyldig wad fil." + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Det ser ud til, at du har information, der vil kunne hjælpe os. Vær rar at sende denne information til udviklerne." + +msgid "Italian" +msgstr "Italiensk" + +msgid "Jan" +msgstr "" + +msgid "Japanese" +msgstr "Japansk" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "Juli" + +msgid "June" +msgstr "Juni" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Tastatur" + +msgid "Korean" +msgstr "Koreansk" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "Sprog filer" + +msgid "Language change:" +msgstr "Skift sprog:" + +msgid "Languagefiles Path" +msgstr "Sti til sprog filer" + +msgid "Languagepath changed." +msgstr "Sti til sprogfiler ændret." + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Indlæsning af Emu nand kanaler virker kun med d2x cIOS! Ændre spil IOS til en d2x cIOS først." + +msgid "Left" +msgstr "Venstre" + +msgid "Like SysMenu" +msgstr "Ligesom wii-menuen" + +msgid "List on Gamelaunch" +msgstr "Vis ved opstart af spil" + +msgid "Load" +msgstr "Indlæs" + +msgid "Load From SD/USB" +msgstr "Indlæs fra SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Indlæs fil fra %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Indlæs denne DOL som alternativ DOL?" + +msgid "Loader Settings" +msgstr "Loader Indstillinger" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "Indlæser standardsprog." + +msgid "Loading standard music." +msgstr "Indlæser standardmusik." + +msgid "Lock Console" +msgstr "Lås konsol" + +msgid "Lock USB Loader GX" +msgstr "Lås USB Loader GX" + +msgid "Locked" +msgstr "Låst" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "Afspil mappe i løkke" + +msgid "Loop Music" +msgstr "Afspil musik i løkke" + +msgid "Loop Sound" +msgstr "Afspil lyd i løkke" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "" + +msgid "Mark new games" +msgstr "Maker nye spil" + +msgid "May" +msgstr "Maj" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "Messageboard opdatering" + +msgid "Motion+ Video" +msgstr "" + +msgid "Mount DVD drive" +msgstr "Mount DVD-drev" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "Multiple Partitioner" + +msgid "Music Loop Mode" +msgstr "Musik i løkke" + +msgid "Music Volume" +msgstr "Lydstyrke" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "Nand Kanal emulation" + +msgid "Nand Channels" +msgstr "Nand Kanaler" + +msgid "Nand Emu Channel Path" +msgstr "Sti til Nand Emu kanal" + +msgid "Nand Emu Path" +msgstr "Sti til Emu Nand." + +msgid "Nand Emulation" +msgstr "Nand emulering" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "Nand emulering er kun mulig med d2x cIOS" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "Nand emulering virker kun med FAT/FAT32 partitioner!" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Ingen" + +msgid "Network is not initiated." +msgstr "Netværk er ikke initialiseret." + +msgid "Next" +msgstr "Næste" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "Nej" + +msgid "No Cheatfile found" +msgstr "Cheat-fil ikke fundet" + +msgid "No DOL file found on disc." +msgstr "Der blev ikke fundet nogle DOL-filer på DVDen." + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "Ingen" + +msgid "No URL or Path specified." +msgstr "Ingen URL eller sti er angivet." + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "Ingen WBFS eller FAT/NTFS/EXT partition er fundet" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "Ingen Wiinnertag.xml fundet i config stien. Vil du oprette en prøve fil?" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "Data kunne ikke læses." + +msgid "No disc inserted." +msgstr "Ingen Disc indsat" + +msgid "No favorites selected." +msgstr "Ingen favoritter er valgt." + +msgid "No file missing!" +msgstr "Ingen filer mangler!" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "Ingen sprog filer at opdatere på din enhed! Vil du hente nye sprog filer?" + +msgid "No new updates." +msgstr "Ingen nye opdateringer." + +msgid "No themes found on the site." +msgstr "Der blev ikke fundet nogle temaer på denne side." + +msgid "No themes found." +msgstr "Ingen temaer fundet." + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "Ingen" + +msgid "Normal" +msgstr "Normal" + +msgid "Not Initialized" +msgstr "Ikke initialiseret" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "Ikke en gyldig URL" + +msgid "Not a valid URL path" +msgstr "Ikke en gyldig URL sti" + +msgid "Not a valid domain" +msgstr "Ikke et gyldig domæne" + +msgid "Not enough free memory." +msgstr "Ikke nok fri hukommelse." + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "Ikke nok ledig plads!" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "Ikke nok hukommelse." + +msgid "Not required" +msgstr "Ikke påkrævet" + +msgid "Not supported format!" +msgstr "Ikke et understøttet format" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "" + +msgid "OFF" +msgstr "Fra" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "Til" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Okt" + +msgid "Official Site:" +msgstr "Officiel side:" + +msgid "Offset" +msgstr "" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "Kun spil Partition" + +msgid "Only for Install" +msgstr "Kun til installering" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Originale/Tilpassede" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Børnelås" + +msgid "Partial" +msgstr "Delvis" + +msgid "Partition" +msgstr "Partition" + +msgid "Password" +msgstr "Password" + +msgid "Password Changed" +msgstr "Password ændret" + +msgid "Password has been changed" +msgstr "Passwordet er blevet ændret" + +msgid "Patch Country Strings" +msgstr "Patch landeindstillinger" + +msgid "Path Changed" +msgstr "Sti er ændret" + +msgid "Permission denied." +msgstr "Tilladelse nægtet." + +msgid "Pick from a list" +msgstr "Vælg fra en liste" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Spiltæller" + +msgid "Play Next" +msgstr "Afspil næste" + +msgid "Play Once" +msgstr "Afspil én gang" + +msgid "Play Previous" +msgstr "Afspil forrige" + +msgid "Playing Music:" +msgstr "Afspiller musik:" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "Vent venligst..." + +msgid "Power off the Wii" +msgstr "Sluk Wiien" + +msgid "Prev" +msgstr "Forrige" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "Proces færdig." + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Knaptekster" + +msgid "Published by" +msgstr "Udgivet af" + +msgid "Quick Boot" +msgstr "Hurtig opstart" + +msgid "Random Directory Music" +msgstr "Musik fra tilfældig mappe" + +msgid "Real Nand" +msgstr "Ægte Nand" + +msgid "Receiving file from:" +msgstr "Henter fil fra:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "" + +msgid "Released" +msgstr "Udkommet" + +msgid "Reload SD" +msgstr "Genindlæs SD" + +msgid "Reloading game list now, please wait..." +msgstr "Genindlæser Spil liste, Vent venligst..." + +msgid "Remember Unlock" +msgstr "Husk at låse op" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "Fjern opdatering" + +msgid "Rename Game Title" +msgstr "" + +msgid "Rename category" +msgstr "Omdøb kategori" + +msgid "Reset" +msgstr "Nulstil" + +msgid "Reset BG Music" +msgstr "Nulstil BG-musik" + +msgid "Reset Playcounter" +msgstr "Nulstil spiltæller" + +msgid "Reset to default BGM?" +msgstr "Nulstil til standard BGM?" + +msgid "Restarting..." +msgstr "Genstarter..." + +msgid "Return" +msgstr "Tilbage" + +msgid "Return To" +msgstr "Tilbage til" + +msgid "Return to Wii Menu" +msgstr "Tilbage til Wii-menuen" + +msgid "Right" +msgstr "Højre" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Vibration" + +msgid "SChinese" +msgstr "Kinesisk (std.)" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "Lydstyrke for effekter" + +msgid "Save" +msgstr "Gem" + +msgid "Save Failed. No device inserted?" +msgstr "Gem fejlede. Ingen enheder indsat?" + +msgid "Save Game List to" +msgstr "Gem spilliste på" + +msgid "Save List" +msgstr "Gem list" + +msgid "Saved" +msgstr "Gemt" + +msgid "Savegame might not exist for this game." +msgstr "Savegame eksistere muligvis ikke for dette spil." + +msgid "Screensaver" +msgstr "Pauseskærm" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "Vælg" + +msgid "Select DOL Offset" +msgstr "Vælg DOL offset" + +msgid "Select a DOL" +msgstr "Vælg en DOL" + +msgid "Select a DOL from Game" +msgstr "Vælg DOL fra spil" + +msgid "Select game categories" +msgstr "Vælg spille Kategorier" + +msgid "Select loader mode" +msgstr "Vælg Loader måde" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "Vælg title kilde." + +msgid "Sept" +msgstr "" + +msgid "Set Search-Filter" +msgstr "Søgefilter" + +msgid "Settings" +msgstr "Indstillinger" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "Vis kategorier" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "Vis fri plads" + +msgid "Show Play Count" +msgstr "Vis spil tæller" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "Sluk (rødt lys)" + +msgid "Shutdown Wii" +msgstr "Sluk Wii" + +msgid "Skip Errors" +msgstr "" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Sortér alfabetisk" + +msgid "Sort by number of players" +msgstr "Sorter efter antal af spillere" + +msgid "Sort by rank" +msgstr "Sortér efter favoritstatus" + +msgid "Sort order by most played" +msgstr "Sortér efter popularitet" + +msgid "Sound" +msgstr "Lyd" + +msgid "Sound Settings" +msgstr "Lyd Indstillinger" + +msgid "Sound+BGM" +msgstr "Lyd+BGM" + +msgid "Sound+Quiet" +msgstr "Lyd+Stille" + +msgid "Spanish" +msgstr "Spansk" + +msgid "Special thanks to:" +msgstr "Specielt tak til:" + +msgid "Split each 2GB" +msgstr "Split hver 2GB" + +msgid "Split each 4GB" +msgstr "Split hver 4GB" + +msgid "Standby" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "Succes" + +msgid "Success." +msgstr "Succes." + +msgid "Success:" +msgstr "Succes:" + +msgid "Successfully Saved" +msgstr "Gem lykkedes" + +msgid "Successfully Updated" +msgstr "Opdateringen lykkedes" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "Det lykkedes at slette:" + +msgid "Successfully extracted theme." +msgstr "Udpakning af tema lykkedes." + +msgid "Successfully installed:" +msgstr "Installationen lykkedes:" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "Skift til Kanal list måde." + +msgid "Sync FAT32 FS Info" +msgstr "Synkronisere FAT32 FS Info" + +msgid "Synchronizing..." +msgstr "Synkronisere..." + +msgid "System Default" +msgstr "System-standard" + +msgid "TChinese" +msgstr "Kinesisk (trad.)" + +msgid "TXT Cheatcodes Path" +msgstr "Sti til TXTCheatcodes" + +msgid "The .them file was not found in the zip." +msgstr "kunne ikke finde .them fil i zip" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "Den angivne mappe eksisterer ikke. Skal den oprettes?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "Dette save game vil bliver udpakket til din Emu Nand sti." + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "Wad fil var installeret" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "Installering af wad fil fejlede med fejl %i" + +msgid "Theme Downloader" +msgstr "Tema-downloader" + +msgid "Theme Menu" +msgstr "Tema menu" + +msgid "Theme Path" +msgstr "Sti til temaer" + +msgid "Theme Title:" +msgstr "Tema titel:" + +msgid "Themes by www.spiffy360.com" +msgstr "Temaer af www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "Denne IOS er BootMii ios. Hvis du er sikker på at det ikke er BootMii og du har noget andet installeret der, ignorer denne advarsel." + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "Denne IOS var ikke fundet i titel listen. Hvis du er sikker på at den er installeret ignorer denne advarsel." + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "Tid tilbage:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Titel-starter" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "Titler fra GameTDB" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "Værktøjstips" + +msgid "Transfer failed" +msgstr "Overførelse fejlede" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX er beskyttet" + +msgid "USB Port" +msgstr "" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "Skift af USB port er kun muligt med Hermes cIOS." + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "Afinstaller" + +msgid "Uninstall Game" +msgstr "Afinstallér spil" + +msgid "Uninstall Menu" +msgstr "Afinstallationsmenu" + +msgid "Uninstall all" +msgstr "Afinstaller alle" + +msgid "Unknown" +msgstr "Ukendt" + +msgid "Unlock USB Loader GX" +msgstr "Lås USB Loader GX op" + +msgid "Unlocked" +msgstr "Låst op" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "Format ikke understøttet, prøv at udpakke TempTheme.zip manuelt" + +msgid "Update" +msgstr "Opdatér" + +msgid "Update All" +msgstr "Opdatér alt" + +msgid "Update DOL" +msgstr "Opdatér DOL" + +msgid "Update Files" +msgstr "Opdatér filer" + +msgid "Update Path" +msgstr "Sti til opdateringer" + +msgid "Update all Language Files" +msgstr "Opdatér alle sprogfiler" + +msgid "Update failed" +msgstr "Opdateringen mislykkedes" + +msgid "Update successfull" +msgstr "Opdatering Lykkedes" + +msgid "Updating Language Files:" +msgstr "Opdaterer sprogfiler:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Den uploadede ZIP-fil er installeret i homebrew-mappen." + +msgid "Use System Font" +msgstr "Brug system font" + +msgid "Use global" +msgstr "Brug global" + +msgid "VBI (Default)" +msgstr "VBI (standard)" + +msgid "VIDTV Patch" +msgstr "VIDTV-patch" + +msgid "Version:" +msgstr "" + +#, c-format +msgid "Version: %s" +msgstr "" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Video-mode" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "Virtual pointer hastighed" + +msgid "WDM Files Path" +msgstr "Sti til WDM filer" + +msgid "WIP Patches Path" +msgstr "Sti til WIP patches" + +msgid "Waiting..." +msgstr "Venter..." + +msgid "Warning" +msgstr "Advarsel" + +msgid "Warning:" +msgstr "Advarsel:" + +msgid "What do you want to do?" +msgstr "Hvad ønsker du at gøre?" + +msgid "What do you want to update?" +msgstr "Hvad skal opdateres?" + +msgid "What should be deleted for this game title:" +msgstr "Hvad skal der slettes for dette spil:" + +msgid "What to extract from NAND?" +msgstr "Hvad skal der udpakkes fra NAND?" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "WiFi-indstillinger" + +msgid "Widescreen Factor" +msgstr "" + +msgid "Widescreen Fix" +msgstr "Bredformat-fix" + +msgid "Wii Games" +msgstr "Wii Spil" + +msgid "Wii Menu" +msgstr "" + +msgid "Wii Settings" +msgstr "Wii-indstillinger" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "WiiTDB.xml er opdateret." + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "Sti til Wiinnertag" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Wiinnertag kræver at du har automatisk netværk forbindelse sat til ved prg. opstart. Vil du sætte det TIL nu?" + +msgid "Wiird Debugger" +msgstr "" + +#, c-format +msgid "Write error on file: %s" +msgstr "Fejl skrivening til fil: %s" + +msgid "Writing GXGameCategories.xml" +msgstr "Skriver GXGameCategories.xml" + +msgid "Wrong Password" +msgstr "Forkert password" + +msgid "Yes" +msgstr "Ja" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "Du prøver at vælge en FAT32/NTFS/EXT partition med cIOS 249 Rev < 18. Dette er ikke understøttet. Fortsætte er på egen risiko" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "Du kan vælge eller formatter en partition eller kanal loader måde." + +msgid "You cannot delete this category." +msgstr "Du kan ikke slette denne kategori." + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "og oversættere for sprog filer" + +msgid "available" +msgstr "tilgængelig" + +msgid "does not exist!" +msgstr "eksisterer ikke!" + +msgid "does not exist! Loading game without cheats." +msgstr "eksisterer ikke! Indlæser spillet uden cheats." + +msgid "files left" +msgstr "filer tilbage" + +msgid "for FAT/NTFS support" +msgstr "for FAT/NTFS understøttelse" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "for GameTDB og for at hoste covers/DVD-billeder" + +msgid "for Ocarina" +msgstr "" + +msgid "for diverse patches" +msgstr "for diverse patches" + +msgid "for his awesome tool LibWiiGui" +msgstr "for hans seje værktøj LibWiiGui" + +msgid "for hosting the themes" +msgstr "for at hoste temaerne" + +msgid "for the USB Loader source" +msgstr "for USB Loader sourcen" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "formateret!" + +msgid "free" +msgstr "ledig" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "ikke sat" + +msgid "of" +msgstr "af" + +msgid "seconds left" +msgstr "sekunder tilbage" + +#~ msgid "Install WAD to EmuNand" +#~ msgstr "Installer WAD til EmuNand" + +#~ msgid "WAD Installation" +#~ msgstr " WAD installation" + +#~ msgid "GameTDB Path" +#~ msgstr "Sti til GameTDB" + +#~ msgid "Error 002 fix" +#~ msgstr "Error 002 fix" + +#~ msgid "Main tester:" +#~ msgstr "Hoved tester:" + +#~ msgid "USB Device not found." +#~ msgstr "USB enhed blev ikke fundet." + +#~ msgid "Custom Discarts" +#~ msgstr "Tilpasset DVD billeder" + +#~ msgid "Full HQ Covers" +#~ msgstr "Fuld HQ Covers" + +#~ msgid "Full LQ Covers" +#~ msgstr "Fuld LQ Covers" + +#~ msgid "Original Discarts" +#~ msgstr "Originale DVD Billeder" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "Omdøb spil på WBFS" + +#~ msgid "Successfully Updated thanks to www.techjawa.com" +#~ msgstr "Opdateringen lykkedes takket været www.techjawa.com" + +#~ msgid "Beginning" +#~ msgstr "Begyndelse" + +#~ msgid "Content" +#~ msgstr "Indhold" + +#~ msgid "for hosting the update files" +#~ msgstr "for at hoste opdateringer" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Indsæt en Wii-DVD!" + +#~ msgid "Issue manager /" +#~ msgstr "Problem manager /" + +#~ msgid "No cheats were selected" +#~ msgstr "Der blev ikke valgt nogle cheats" + +#~ msgid "Not a Wii Disc" +#~ msgstr "Ikke en Wii-DVD" + +#~ msgid "The files will be extracted to your emu nand path. Attention: All existing files will be overwritten." +#~ msgstr "Filerne vil bliver udpakket til din Emu Nand sti. Advarsel : alle eksisterene filer vil bliver overskrevet." + +#~ msgid "The save games will be extracted to your emu nand path. Attention: All existing saves will be overwritten." +#~ msgstr "Alle Save games vil bliver udpakket til din Emu Nand sti. Advarsel: Alle eksisterene save games vil bliver overskrevet." + +#~ msgid "Installing title" +#~ msgstr "Installerer titel" + +#~ msgid "USB Device not found" +#~ msgstr "USB-enhed ikke fundet" + +#~ msgid "You need to select or format a partition" +#~ msgstr "Du skal vælge eller formattere en partition" + +#~ msgid "Language File" +#~ msgstr "Sprog Fil" + +#~ msgid "Are you sure you want to import game categories from WiiTDB?" +#~ msgstr "Er du sikker på at du ville importere spille kategorier fra WiiTDB?" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Titler fra WiiTDB" + +#~ msgid "WiiTDB Files" +#~ msgstr "WiiTDB-filer" + +#~ msgid "WiiTDB Path" +#~ msgstr "Sti til WiiTDB" + +#~ msgid "WiiTDB is up to date." +#~ msgstr "WiiTDB er op til dato." + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "for WiiTDB og for at hoste covers/DVD-billeder" diff --git a/Languages/dutch.lang b/Languages/dutch.lang new file mode 100644 index 0000000..8ed4894 --- /dev/null +++ b/Languages/dutch.lang @@ -0,0 +1,2532 @@ +# USB Loader GX language source file. +# dutch.lang - r1217 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:02+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " kon niet worden gedownload" + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " is opgeslagen. De tekst is niet gecontroleerd. Delen van de code kunnen elkaar tegenwerken.. Als je moeilijkheden ondervind, open dan de tekst in een echte tekstverwerker voor meer informatie." + +msgid " is not on the server." +msgstr " staat niet op de server." + +#, c-format +msgid "%i files not found on the server!" +msgstr "%i bestanden niet gevonden op de server!" + +#, c-format +msgid "%i missing files" +msgstr "%i missende bestanden" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "%s accepteerd alleen GameCube backups in ISO formaat." + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "%s benodigd AHB toegang! Laad USBLoaderGX vanuit HBC of vanuit een geüpdatete channel of forwarder." + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Iedereen 3+)" + +msgid "1 (Child 7+)" +msgstr "1 (Kinderen 7+)" + +msgid "1 hour" +msgstr "1 uur" + +msgid "10 min" +msgstr "" + +msgid "2 (Teen 12+)" +msgstr "2 (Tiener 12+)" + +msgid "20 min" +msgstr "" + +msgid "2D Cover Path" +msgstr "Locatie 2D hoesjes" + +msgid "3 (Mature 16+)" +msgstr "3 (Jongeren 16+)" + +msgid "3 min" +msgstr "" + +msgid "30 min" +msgstr "" + +msgid "3D Cover Path" +msgstr "Locatie 3D hoesjes" + +msgid "3D Covers" +msgstr "3D Hoesjes" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Volwassen 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "Automatisch" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "Categorie toevoegen" + +msgid "Adjust Overscan X" +msgstr "Aanpassen Overscan X" + +msgid "Adjust Overscan Y" +msgstr "Aanpassen Overscan Y" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "Alles" + +msgid "All Partitions" +msgstr "Alle partities" + +msgid "All files extracted." +msgstr "Alle bestanden uitgepakt." + +msgid "All images downloaded successfully." +msgstr "Alle plaatjes succesvol gedownload." + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Alle functies van USB Loader GX zijn vrijgegeven." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Alternatieve DOL" + +msgid "An example file was created here:" +msgstr "Er is hier een voorbeeldbestand gemaakt:" + +msgid "Animation Start" +msgstr "Animatie Start" + +msgid "App Language" +msgstr "Applicatie Taal" + +msgid "Apply" +msgstr "Toepassen" + +msgid "Apr" +msgstr "" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "Weet je zeker dat je alle geselecteerde games van de SD kaart wilt verwijderen?" + +msgid "Are you sure you want to delete this category?" +msgstr "Weet je zeker dat je deze categorie wilt verwijderen?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "Weet je zeker dat je spel categorieën wilt importeren van GameTBD?" + +msgid "Are you sure you want to install on SD?" +msgstr "Weet je zeker dat je wilt installeren op SD?" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "Weet je zeker dat je USB Loader GX wilt vergrendelen?" + +msgid "Are you sure you want to remount SD?" +msgstr "Weet je zeker dat je de SD wilt hermounten?" + +msgid "Are you sure you want to reset?" +msgstr "Wet je zeker dat je wilt resetten?" + +msgid "Are you sure?" +msgstr "Zeker weten?" + +msgid "Aspect Ratio" +msgstr "verhouding ratio" + +msgid "Attention!" +msgstr "Opgelet!" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "" + +msgid "Author(s):" +msgstr "Auteur(s):" + +msgid "Auto" +msgstr "Auto" + +msgid "Auto Boot" +msgstr "Auto Opstart" + +msgid "AutoInit Network" +msgstr "Netwerk AutoStart" + +msgid "BCA Codes Path" +msgstr "Locatie BCA codes" + +msgid "Back" +msgstr "Terug" + +msgid "Back to HBC or Wii Menu" +msgstr "Terug naar HBC of Wii Menu" + +msgid "Backgroundmusic" +msgstr "Achtergrondmuziek" + +msgid "Banner Animation" +msgstr "Banner Animatie" + +msgid "Banner Animation Settings" +msgstr "Banner Animatie Instellingen" + +msgid "Banner On Channels" +msgstr "Banner Bij Kanalen" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "Banner raster indeling is alleen beschikbaar met AHBPROT! Overweeg het updaten van HBC." + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "Banner scherm is alleen beschikbaar met AHBPROT! Overweeg het updaten van HBC." + +msgid "Big thanks to:" +msgstr "Grote dank aan:" + +msgid "Block Categories Menu" +msgstr "Blokkeer Categorie Menu" + +msgid "Block Categories Modify" +msgstr "Blokkeer Categorieën Wijzigen" + +msgid "Block Cover Downloads" +msgstr "Blokkeer Downloads Van Hoesjes" + +msgid "Block Custom Paths" +msgstr "Blokkeer Aangepaste Locaties" + +msgid "Block Feature Settings" +msgstr "Blokkeer Functie Instellingen" + +msgid "Block Game Install" +msgstr "Blokkeer Spel Installatie" + +msgid "Block Game Settings" +msgstr "Blokkeer Spel Instellingen" + +msgid "Block GameID Change" +msgstr "Blokkeer SpelID Wijzigen" + +msgid "Block Global Settings" +msgstr "Blokkeer Globale Instellingen" + +msgid "Block Gui Settings" +msgstr "Blokkeer GUI Instellingen" + +msgid "Block HBC Menu" +msgstr "Blokkeer HBC Menu" + +msgid "Block Hard Drive Settings" +msgstr "Blokkeer Harddisk Instellingen" + +msgid "Block IOS Reload" +msgstr "Blokkeer IOS Herladen" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "Blokkeer Loader Instellingen" + +msgid "Block Parental Settings" +msgstr "Blokkeer Ouderlijk Toezicht" + +msgid "Block Priiloader Override" +msgstr "Blokkeer Priiloader Override" + +msgid "Block Reset Settings" +msgstr "Blokkeer Reset Instellingen" + +msgid "Block SD Reload Button" +msgstr "Blokkeer SD Herlaad Knop" + +msgid "Block Sound Settings" +msgstr "Blokkeer Geluid Instellingen" + +msgid "Block Theme Downloader" +msgstr "Blokkeer Thema Downloader" + +msgid "Block Theme Menu" +msgstr "Blokkeer Thema Menu" + +msgid "Block Title Launcher" +msgstr "Blokkeer Titel Launcher" + +msgid "Block Updates" +msgstr "Blokkeer Updates" + +msgid "Boot Content" +msgstr "Start Content" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "Start?" + +msgid "Both" +msgstr "Beide" + +msgid "Both Ports" +msgstr "Beide poorten" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "Cache BNR Bestanden" + +msgid "Cache BNR Files Path" +msgstr "Cache BNR Bestandspad" + +msgid "Cache Titles" +msgstr "Titels cachen" + +msgid "Can't be formatted" +msgstr "Kan niet geformatteerd worden" + +msgid "Can't create directory" +msgstr "Kan map niet aanmaken" + +#, c-format +msgid "Can't create file: %s" +msgstr "Kan bestand niet aanmaken: %s" + +#, c-format +msgid "Can't create path: %s" +msgstr "Kan pad niet maken: %s" + +msgid "Can't delete:" +msgstr "Kan niet verwijderen:" + +msgid "Can't mount or unknown disc format." +msgstr "Kan niet mounten of onbekend schijf formaat." + +#, c-format +msgid "Can't open file for write: %s" +msgstr "Kan bestand niet openen voor schrijven: %s" + +#, c-format +msgid "Can't open file: %s" +msgstr "Kan bestand niet openen: %s" + +#, c-format +msgid "Can't read file: %s" +msgstr "Kan bestand niet lezen: %s" + +msgid "Cancel" +msgstr "Annuleren" + +msgid "Cannot write to destination." +msgstr "Kan niet naar bestemming schrijven." + +msgid "Categories" +msgstr "Categorieën" + +msgid "Categories:" +msgstr "Categorieën:" + +msgid "Change Play Path" +msgstr "Verander afspeel locatie" + +msgid "Channel Launcher" +msgstr "Kanaal Launcher" + +msgid "Channels" +msgstr "Kanalen" + +msgid "Cheatfile is blank" +msgstr "Cheatbestand is leeg" + +msgid "Clear" +msgstr "Wissen" + +msgid "Click to Download Covers" +msgstr "Klik om hoesjes te downloaden" + +msgid "Click to change game ID" +msgstr "Klik om het spel ID te wijzigen" + +msgid "Clock" +msgstr "Klok" + +msgid "Clock Scale Factor" +msgstr "Klok Schaal Factor" + +msgid "Close" +msgstr "Sluiten" + +msgid "Code Download" +msgstr "Code Download" + +#, c-format +msgid "Coded by: %s" +msgstr "Geprogrammeerd door: %s" + +msgid "Coding:" +msgstr "Codering:" + +msgid "Connection to server timed out." +msgstr "Verbinding met de server duurt te lang." + +msgid "Console" +msgstr "Console" + +msgid "Console Default" +msgstr "Console standaard" + +msgid "Console Locked" +msgstr "Console vergrendeld" + +msgid "Console must be unlocked for this option." +msgstr "Console moet ontgrendeld zijn voor deze optie." + +msgid "Console must be unlocked to be able to use this." +msgstr "Console moet worden vrijgegeven om dit te kunnen gebruiken." + +msgid "Console should be unlocked to modify it." +msgstr "Console moet worden vrijgegeven om te wijzigen." + +msgid "Continue" +msgstr "Doorgaan" + +msgid "Continue to install game?" +msgstr "Installatie spel voortzetten?" + +msgid "Continue?" +msgstr "Doorgaan?" + +msgid "Controllevel" +msgstr "Controle niveau" + +msgid "Copy" +msgstr "Kopie" + +msgid "Copying Canceled" +msgstr "Kopiëren geannuleerd" + +msgid "Copying GC game..." +msgstr "GC game kopiëren..." + +msgid "Copying files..." +msgstr "Bestanden kopiëren..." + +msgid "Correct Password" +msgstr "Juiste Wachtwoord" + +msgid "Could not connect to the server." +msgstr "Kan geen verbinding met de server maken." + +msgid "Could not create GCT file" +msgstr "Kan GCT bestand niet aanmaken" + +#, c-format +msgid "Could not create path: %s" +msgstr "Kan pad niet maken: %s" + +msgid "Could not extract files for:" +msgstr "Kan bestanden niet uitpakken voor:" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "Kan geen info over dit spel vinden in de wiitdb.xml." + +msgid "Could not get free device space for game." +msgstr "Kon geen vrije ruimte krijgen voor het spel." + +msgid "Could not initialize DIP module!" +msgstr "Kan DIP module niet initialiseren!" + +msgid "Could not initialize network!" +msgstr "Kan netwerk niet initialiseren!" + +msgid "Could not initialize network, time out!" +msgstr "Kan netwerk niet initialiseren, time-out!" + +msgid "Could not open Disc" +msgstr "Kan disk niet openen" + +msgid "Could not open the WiiTDB.xml file." +msgstr "Kan het WiiTDB.xml bestand niet openen." + +msgid "Could not open wiitdb.xml." +msgstr "Kan wiitdb.xml niet openen." + +msgid "Could not save." +msgstr "Kan niet opslaan." + +msgid "Could not write file." +msgstr "Kan niet naar bestand schrijven." + +msgid "Could not write to:" +msgstr "Kan niet schrijven naar:" + +msgid "Cover Download" +msgstr "Download hoesjes" + +msgid "Create" +msgstr "Maak" + +msgid "Credits" +msgstr "Credits" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "Aangepaste Banners" + +msgid "Custom Paths" +msgstr "Aangepaste Locaties" + +msgid "Customs" +msgstr "Aangepaste" + +msgid "Customs/Original" +msgstr "Aangepast/Origineel" + +msgid "D Buttons" +msgstr "D Knoppen" + +msgid "DOL Path" +msgstr "DOL Pad" + +msgid "Debug" +msgstr "Debug" + +msgid "Debug Wait" +msgstr "Debug Wachttijd" + +msgid "Debugger Paused Start" +msgstr "Debugger Gepauseerd Start" + +msgid "Dec" +msgstr "" + +msgid "Default" +msgstr "Standaard" + +msgid "Default Gamesettings" +msgstr "Standaard spel instellingen" + +msgid "Default Settings" +msgstr "Standaardinstellingen" + +msgid "Delete" +msgstr "Verwijderen" + +msgid "Delete Cached Banner" +msgstr "Verwijder Gecachete Banner" + +msgid "Delete Cheat GCT" +msgstr "Cheat GCT verwijderen" + +msgid "Delete Cheat TXT" +msgstr "Cheat TXT verwijderen" + +msgid "Delete Cover Artwork" +msgstr "Hoesjes verwijderen" + +msgid "Delete Disc Artwork" +msgstr "Disk labels verwijderen" + +msgid "Delete category" +msgstr "Verwijder categorie" + +msgid "Deleting directories..." +msgstr "Mappen verwijderen..." + +msgid "Deleting files..." +msgstr "Bestanden verwijderen..." + +msgid "Design:" +msgstr "Ontwerp:" + +msgid "Details" +msgstr "Details" + +msgid "Developed by" +msgstr "Ontwikkeld door" + +msgid "Developer:" +msgstr "Ontwikkelaar:" + +msgid "Devolution" +msgstr "Devolution" + +msgid "Devolution Loader Path" +msgstr "Devolution Loader Locatie" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "Devolution's loader.bin bestand kan niet worden geladen." + +msgid "Directory does not exist!" +msgstr "Map bestaat niet!" + +msgid "Disc 1" +msgstr "Disc 1" + +msgid "Disc 2" +msgstr "Disc 2" + +msgid "Disc Artwork Download" +msgstr "Download disk labels" + +msgid "Disc Artwork Path" +msgstr "Locatie disk labels" + +msgid "Disc Default" +msgstr "Disk standaard" + +msgid "Disc Insert Detected" +msgstr "Disk invoer gedetecteerd" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "Disk leesfout." + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "Disc2 moet in een ongecomprimeerd formaat worden opgeslagen om te werken met DM (L) V2.6+, weet je zeker dat je wilt installeren in een gecomprimeerd formaat?" + +msgid "Discarts" +msgstr "Disk afbeeldingen" + +msgid "DiskFlip" +msgstr "" + +msgid "Display" +msgstr "Tonen" + +msgid "Display as a carousel" +msgstr "Carrouselweergave" + +msgid "Display as a channel grid" +msgstr "Kanaalrasterweergave" + +msgid "Display as a grid" +msgstr "Rasterweergave" + +msgid "Display as a list" +msgstr "Lijstweergave" + +msgid "Display favorites only" +msgstr "Alleen favorieten weergeven" + +msgid "Do you want to apply it now?" +msgstr "Wil je dit nu toepassen?" + +msgid "Do you want to apply this theme?" +msgstr "Wil je dit thema toepassen?" + +msgid "Do you want to change language?" +msgstr "Wil je de taal wijzigen?" + +msgid "Do you want to continue with next game?" +msgstr "Wil je doorgaan met het volgende spel?" + +msgid "Do you want to copy now?" +msgstr "Wil je nu kopiëren?" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "Wil je een spel naar de SD kopiëren of er een van verwijderen?" + +msgid "Do you want to delete a game on SD?" +msgstr "Wil je een spel verwijderen van de SD" + +msgid "Do you want to discard changes?" +msgstr "Wil je alle gemaakte wijzigingen verwerpen?" + +msgid "Do you want to download this theme?" +msgstr "Wil je dit thema downloaden?" + +msgid "Do you want to extract all the save games?" +msgstr "Wil je alle opgeslagen spellen uitpakken?" + +msgid "Do you want to extract the save game?" +msgstr "Wil je dit opgeslagen spel uitpakken?" + +msgid "Do you want to format:" +msgstr "Wil je formatteren:" + +msgid "Do you want to install selected games?" +msgstr "Wil je de geselecteerde spellen installeren?" + +msgid "Do you want to load the default theme?" +msgstr "Wil je het standaard thema laden?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "Wil je het netwerk herinitialiseren?" + +msgid "Do you want to start the game now?" +msgstr "Wil je het spel nu starten?" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "Wil je de vrije ruimte informatie sector synchroniseren op alle FAT32 partities?" + +msgid "Do you wish to update/download all language files?" +msgstr "Wil je alle taalbestanden updaten/downloaden?" + +msgid "Dol Video Patch" +msgstr "DOL Video Patch" + +msgid "Download" +msgstr "Download" + +msgid "Download Now" +msgstr "Download nu" + +msgid "Download finished" +msgstr "Download voltooid" + +msgid "Downloading 3D Covers" +msgstr "3D hoesjes aan het downloaden" + +msgid "Downloading Custom Banners" +msgstr "Aangepaste banners aan het downloaden" + +msgid "Downloading Flat Covers" +msgstr "Platte hoesjes aan het downloaden" + +msgid "Downloading Full HQ Covers" +msgstr "HQ volledige hoesjes downloaden" + +msgid "Downloading Full LQ Covers" +msgstr "LQ volledige hoesjes downloaden " + +msgid "Downloading custom Discarts" +msgstr "Aangepaste disc afbeeldingen downloaden" + +msgid "Downloading file..." +msgstr "Bestand downloaden..." + +msgid "Downloading image:" +msgstr "Afbeelding downloaden:" + +msgid "Downloading original Discarts" +msgstr "Originele disc afbeeldingen downloaden" + +msgid "Downloading pagelist:" +msgstr "Paginalijst downloaden:" + +msgid "Dump NAND to EmuNand" +msgstr "NAND Dumpen naar EmuNand" + +msgid "During zoom" +msgstr "Tijdens zoom" + +msgid "Dutch" +msgstr "Nederlands" + +msgid "ERROR" +msgstr "FOUT" + +msgid "ERROR:" +msgstr "FOUT:" + +msgid "ERROR: Can't set up theme." +msgstr "FOUT: Kan thema niet instellen" + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "EmuNand Kanalen" + +msgid "Emulated Nand" +msgstr "Geëmuleerd Nand" + +msgid "English" +msgstr "Engels" + +msgid "Enter Path" +msgstr "Voer pad in" + +msgid "Error" +msgstr "Fout" + +msgid "Error !" +msgstr "Fout !" + +#, c-format +msgid "Error creating path: %s" +msgstr "Kan pad niet maken: %s" + +msgid "Error opening downloaded file" +msgstr "Fout bij het openen van gedownload bestand" + +msgid "Error reading Disc" +msgstr "Fout bij lezen disk" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "Fout bij het downloaden van bestand: %i" + +msgid "Error while downloding file" +msgstr "Fout tijdens bestand downloaden" + +msgid "Error while opening the zip." +msgstr "Fout bij het openen van de zip." + +msgid "Error while transfering data." +msgstr "Fout bij overplaatsen van data." + +msgid "Error while updating USB Loader GX." +msgstr "Fout bij het updaten van USB Loader GX" + +msgid "Error writing the data." +msgstr "Fout bij het schrijven van de data." + +msgid "Error:" +msgstr "Fout:" + +msgid "Error: Not enough space on SD." +msgstr "Fout: Niet genoeg ruimte op SD." + +msgid "Errors occured." +msgstr "Fouten opgetreden." + +msgid "Everything" +msgstr "Alles" + +msgid "Exit" +msgstr "Stoppen" + +msgid "Exit to where?" +msgstr "Stoppen naar?" + +msgid "Export All Saves to EmuNand" +msgstr "Alle Saves exporteren naar EmuNand" + +msgid "Export Miis to EmuNand" +msgstr "Exporteer Miis naar EmuNand" + +msgid "Export SYSCONF to EmuNand" +msgstr "Exporteerd SYSCONF naar EmuNand" + +msgid "Extract Miis to the Emu NAND?" +msgstr "Miis naar EmuNand uitpakken?" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "SYSCONF naar EmuNand uitpakken?" + +msgid "Extract Save to EmuNand" +msgstr "Save Exporteren naar EmuNand" + +msgid "Extracting file:" +msgstr "Uitpakken:" + +msgid "Extracting files..." +msgstr "Bestanden uitpakken..." + +msgid "Extracting files:" +msgstr "Uitpakken:" + +msgid "Extracting nand files:" +msgstr "NAND Uitpakken:" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "Mislukt" + +msgid "Failed copying file" +msgstr "Kopiëren van bestand mislukt" + +msgid "Failed formating" +msgstr "Formatteren mislukt" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "Uitpakken mislukt. Savegame bestaat wellicht niet." + +msgid "Failed to extract." +msgstr "Uitpakken mislukt." + +msgid "Failed to initialize the USB storage device." +msgstr "USB apparaat niet kunnen initialiseren." + +msgid "Failed to open partition" +msgstr "Partitie openen mislukt" + +msgid "Failed to read ticket." +msgstr "Kon ticket niet lezen" + +msgid "Failed to read tmd file." +msgstr "Kon tmd bestand niet lezen" + +msgid "Failed to read wad header." +msgstr "Kon wad header niet lezen" + +msgid "Failed updating" +msgstr "Updaten mislukt" + +msgid "Favorite Level" +msgstr "Favoriete Level" + +msgid "Features" +msgstr "Functies" + +msgid "Features Settings" +msgstr "Functie Instellingen" + +msgid "Feb" +msgstr "" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Bestand niet gevonden." + +msgid "File read/write error." +msgstr "Bestand lees/schrijf fout." + +msgid "Files extracted successfully." +msgstr "Bestanden succesvol uitgepakt." + +#, c-format +msgid "Filesize is %i Byte." +msgstr "Bestandsgrootte is %i Byte." + +msgid "Filesize is 0 Byte." +msgstr "Bestandsgrootte is 0 Byte." + +msgid "Flat Covers" +msgstr "Platte hoesjes" + +msgid "Flip-X" +msgstr "X omwisselen" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "Lettertype Schaal Factor" + +msgid "Force 16:9" +msgstr "Forceer 16:9" + +msgid "Force 4:3" +msgstr "Forceer 4:3" + +msgid "Force NTSC" +msgstr "Forceer NTSC" + +msgid "Force NTSC480p" +msgstr "Forceer NTSC480p" + +msgid "Force PAL480p" +msgstr "Forceer PAL480p" + +msgid "Force PAL50" +msgstr "Forceer PAL50" + +msgid "Force PAL60" +msgstr "Forceer PAL60" + +msgid "Force Titles from Disc" +msgstr "Forceer titels van Disk" + +msgid "Force Widescreen" +msgstr "Forceer Breedbeeld" + +msgid "Format" +msgstr "Formatteer" + +msgid "Formatting, please wait..." +msgstr "Bezig met formatteren..." + +msgid "Found missing images." +msgstr "Missende plaatje gevonden." + +msgid "Frame" +msgstr "Rand" + +msgid "Frame Projection Height" +msgstr "Rand projectie hoogte" + +msgid "Frame Projection Width" +msgstr "Rand projectie breedte" + +msgid "Frame Projection X-Offset" +msgstr "Rand projectie X-compensatie" + +msgid "Frame Projection Y-Offset" +msgstr "Rand projectie Y-compensatie" + +msgid "Frames" +msgstr "Randen" + +msgid "Free Space" +msgstr "Vrije ruimte" + +msgid "French" +msgstr "Frans" + +msgid "Full" +msgstr "Volledig" + +msgid "Full Cover Path" +msgstr "Volledige hoesjes pad" + +msgid "Full Covers" +msgstr "Volledige Hoesjes" + +msgid "Full Menu" +msgstr "Volledig Menu" + +msgid "Full covers Download" +msgstr "Volledige hoesjes download" + +msgid "Full shutdown" +msgstr "Volledig uitzetten" + +msgid "GAMEID_Gamename" +msgstr "SPELID_Spelnaam" + +msgid "GC Banner Scale" +msgstr "GC Banner Schaal" + +msgid "GC Games" +msgstr "GC Spellen" + +msgid "GC Install 32K Aligned" +msgstr "GC Installeer 32K Aligned" + +msgid "GC Install Compressed" +msgstr "GC Installeer Gecomprimeerd" + +msgid "GCT Cheatcodes Path" +msgstr "Locatie GCT cheatcodes" + +msgid "GCT File created" +msgstr "GCT bestand aangemaakt" + +msgid "GUI Settings" +msgstr "Menu opties" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "GameCube Spel Verwijderen" + +msgid "Game Cube Install Menu" +msgstr "GameCube Installatie Menu" + +msgid "Game ID" +msgstr "Spel ID" + +msgid "Game IOS" +msgstr "Spel IOS" + +msgid "Game Language" +msgstr "Spel taal" + +msgid "Game Load" +msgstr "Spel opties" + +msgid "Game Lock" +msgstr "Spel vergrendelen" + +msgid "Game Only" +msgstr "Alleen Spel" + +msgid "Game Region" +msgstr "Spel Regio" + +msgid "Game Size" +msgstr "Spel grootte" + +msgid "Game Sound Mode" +msgstr "Spel geluid mode" + +msgid "Game Sound Volume" +msgstr "Spel geluid volume" + +msgid "Game Split Size" +msgstr "Spel splits grootte" + +msgid "Game Window Mode" +msgstr "Spel Scherm Modus" + +msgid "Game is already installed:" +msgstr "Spel is al geïnstalleerd:" + +msgid "Game's IOS" +msgstr "Spel's IOS" + +msgid "Game/Install Partition" +msgstr "Spel/Installatie partitie" + +msgid "GameCube" +msgstr "GameCube" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "GameCube Modus" + +msgid "GameCube Source" +msgstr "GameCube Bron" + +msgid "Gamename [GAMEID]" +msgstr "Spelnaam [SPELID]" + +msgid "Games" +msgstr "Spellen" + +msgid "Generating GXGameCategories.xml" +msgstr "Genereren GXGameCategories.xml" + +msgid "Genre:" +msgstr "Genre:" + +msgid "German" +msgstr "Duits" + +msgid "Getting file list..." +msgstr "Bestandenlijst laden..." + +msgid "Getting game folder size..." +msgstr "Spelmap grote berekenen..." + +msgid "Global Settings" +msgstr "Globale instellingen" + +msgid "Grid Scroll Speed" +msgstr "Raster Scroll Snelheid" + +msgid "HOME Menu" +msgstr "HOME Menu" + +msgid "Hard Drive Settings" +msgstr "Harddisk Instellingen" + +msgid "High Quality" +msgstr "Hoge Kwaliteit" + +msgid "High/Low" +msgstr "Hoog/Laag" + +msgid "Homebrew Apps Path" +msgstr "Locatie homebrew apps" + +msgid "Homebrew Channel" +msgstr "Homebrew Kanaal" + +msgid "Homebrew Launcher" +msgstr "Homebrew Launcher" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "Uur" + +msgid "How do you want to update?" +msgstr "Hoe wil je updaten?" + +msgid "How to Shutdown?" +msgstr "Hoe uitzetten?" + +msgid "Import Categories" +msgstr "Importeer Categorieën" + +msgid "Import operation successfully completed." +msgstr "Importeren succesvol afgerond." + +msgid "Importing categories" +msgstr "Categorieën importeren" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Binnenkomend bestand %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Binnenkomend bestand %0.2fMB" + +msgid "Individual" +msgstr "Individueel" + +msgid "Initializing Network" +msgstr "Netwerk initialiseren" + +msgid "Insert Disk" +msgstr "Voer een disk in" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "Voer een Wii of GameCube Disk in!" + +msgid "Install" +msgstr "Installeer" + +msgid "Install Canceled" +msgstr "Installatie geannuleerd" + +msgid "Install Directories" +msgstr "Installeer mappen" + +msgid "Install Error!" +msgstr "Installatiefout!" + +msgid "Install Partitions" +msgstr "Installatie Partitie" + +msgid "Install a game" +msgstr "Spel installeren" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "Installatie voltooid" + +msgid "Installing Game Cube Game..." +msgstr "GameCube Spel Installeren..." + +msgid "Installing content" +msgstr "Content Installeren" + +msgid "Installing game:" +msgstr "Bezig met installeren:" + +msgid "Installing title..." +msgstr "Titel installeren..." + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "Foutief IOS nummer ingevoerd. Het nummer moet -1 zijn voor volgen origineel of 200 - 255." + +msgid "Invalid wad file." +msgstr "Fout wad bestand" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Je hebt informatie gevonden die ons kan helpen. Geeft u alstublieft deze info door aan ons ontwikkelingsteam." + +msgid "Italian" +msgstr "Italiaans" + +msgid "Jan" +msgstr "" + +msgid "Japanese" +msgstr "Japans" + +msgid "Japanese Patch" +msgstr "Japanse Patch" + +msgid "Joypad" +msgstr "Joypad" + +msgid "July" +msgstr "Jul" + +msgid "June" +msgstr "Jun" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Toetsenbord" + +msgid "Korean" +msgstr "Koreaans" + +msgid "LED Activity" +msgstr "LED Activiteit" + +msgid "Language Files" +msgstr "Taalbestanden" + +msgid "Language change:" +msgstr "Taal wijzigen:" + +msgid "Languagefiles Path" +msgstr "Locatie Taalbestanden" + +msgid "Languagepath changed." +msgstr "Locatie taal gewijzigd." + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Spellen met EmuNand werken alleen op een d2x cIOS! Verander eerst de spel IOS naar een d2x cIOS." + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Nand kanalen met EmuNand werken alleen op een d2x cIOS! Verander eerst de spel IOS naar een d2x cIOS." + +msgid "Left" +msgstr "Links" + +msgid "Like SysMenu" +msgstr "Als SysteemMenu" + +msgid "List on Gamelaunch" +msgstr "Lijst bij Spelstart" + +msgid "Load" +msgstr "Laad" + +msgid "Load From SD/USB" +msgstr "Laden van SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Laad bestand van: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Deze DOL als alternatieve DOL gebruiken?" + +msgid "Loader Settings" +msgstr "Loader Instellingen" + +msgid "Loader's IOS" +msgstr "Loader's IOS" + +msgid "Loading standard language." +msgstr "Standaardtaal laden." + +msgid "Loading standard music." +msgstr "Standaardmuziek laden." + +msgid "Lock Console" +msgstr "Console vergrendelen" + +msgid "Lock USB Loader GX" +msgstr "Vergrendel USB Loader GX" + +msgid "Locked" +msgstr "Vergrendeld" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "Herhaal Map" + +msgid "Loop Music" +msgstr "Herhaal Muziek" + +msgid "Loop Sound" +msgstr "Geluid herhalen" + +msgid "Low Quality" +msgstr "Lage kwaliteit" + +msgid "Low/High" +msgstr "Laag/Hoog" + +msgid "MIOS (Default & Customs)" +msgstr "MIOS (Standaard & Aangepast)" + +msgid "Main DOL" +msgstr "Hoofd DOL" + +msgid "Main GameCube Games Path" +msgstr "Hoofd GameCube Spellen Locatie" + +msgid "Main GameCube Path" +msgstr "Hoofd GameCube Locatie" + +msgid "Main Path" +msgstr "Hoofd Locatie" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "Mrt" + +msgid "Mark new games" +msgstr "Markeer nieuwe spellen" + +msgid "May" +msgstr "Mei" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "Memory Card Emulatie" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "Prikbord Update" + +msgid "Motion+ Video" +msgstr "Mation+ Video" + +msgid "Mount DVD drive" +msgstr "DVD Laden" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "Meerdere partities" + +msgid "Music Loop Mode" +msgstr "Muziek Herhaal Mode" + +msgid "Music Volume" +msgstr "Muziekvolume" + +msgid "NMM Mode" +msgstr "NMM Modus" + +msgid "Nand Chan. Emulation" +msgstr "Nand Kan. Emulatie" + +msgid "Nand Channels" +msgstr "Nand Kanalen" + +msgid "Nand Emu Channel Path" +msgstr "Nand Emu Kanaal Locatie" + +msgid "Nand Emu Path" +msgstr "Nand Emu Locatie" + +msgid "Nand Emulation" +msgstr "Nand Emulatie" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "Nand Emulatie is alleen mogelijk met D2X cIOS" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "Nand Emulatie werkt alleen op FAT/FAT32 partities!" + +msgid "Nand Saves Emulation" +msgstr "Nand Opslag Emulatie" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Geen" + +msgid "Network is not initiated." +msgstr "Netwerk is niet gestart." + +msgid "Next" +msgstr "Volgende" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "Nintendont Loader Locatie" + +msgid "No" +msgstr "Nee" + +msgid "No Cheatfile found" +msgstr "Geen cheatbestand gevonden" + +msgid "No DOL file found on disc." +msgstr "Geen DOL bestand gevonden op disk." + +msgid "No Disc+" +msgstr "Geen Disk+" + +msgid "No Splitting" +msgstr "Niet splitsen" + +msgid "No URL or Path specified." +msgstr "Geen URL of pad gespecificeerd." + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "Geen WBFS of FAT/NTFS/EXT partitie gevonden" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "Geen Wiinertag.xml gevonden in het configuratie pad. Wil je een voorbeeld bestand maken?" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "Geen cheats geselecteerd! Moet het GCT bestand worden verwijderd?" + +msgid "No data could be read." +msgstr "Data kon niet gelezen worden." + +msgid "No disc inserted." +msgstr "Geen schijf ingevoerd." + +msgid "No favorites selected." +msgstr "Geen favorieten geselecteerd." + +msgid "No file missing!" +msgstr "Geen missende bestanden!" + +msgid "No games found on the disc" +msgstr "Geen spellen gevonden op disk" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "Geen taalbestanden om te updateten op je apparaten! Wil je nieuwe taalbestanden downloaden?" + +msgid "No new updates." +msgstr "Geen nieuwe updates." + +msgid "No themes found on the site." +msgstr "Geen thema's gevonden op de site." + +msgid "No themes found." +msgstr "Geen thema's gevonden." + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "Geen" + +msgid "Normal" +msgstr "Normaal" + +msgid "Not Initialized" +msgstr "Niet Geïnitialiseerd" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "Geen Wii of GameCube Disk" + +msgid "Not a valid URL" +msgstr "Geen geldige URL" + +msgid "Not a valid URL path" +msgstr "Geen geldig URL pad" + +msgid "Not a valid domain" +msgstr "Geen geldig domein" + +msgid "Not enough free memory." +msgstr "Niet genoeg vrije ruimte." + +msgid "Not enough free space on device." +msgstr "Niet genoeg vrije ruimte op apparaat." + +msgid "Not enough free space!" +msgstr "Niet genoeg vrije ruimte!" + +msgid "Not enough memory for FST." +msgstr "Niet genoeg ruimte voor FST." + +msgid "Not enough memory." +msgstr "Onvoldoende geheugen." + +msgid "Not required" +msgstr "Niet nodig" + +msgid "Not supported format!" +msgstr "Formaat niet ondersteund!" + +msgid "Nothing selected to delete." +msgstr "Niets geselecteerd om te verwijderen." + +msgid "Nothing selected to install." +msgstr "Niets geselecteerd om te installeren." + +msgid "Nov" +msgstr "" + +msgid "OFF" +msgstr "Uit" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "Aan" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Okt" + +msgid "Official Site:" +msgstr "Officiële site:" + +msgid "Offset" +msgstr "Compensatie" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "Alleen Spel Partitie" + +msgid "Only for Install" +msgstr "Alleen bij installeren" + +msgid "Original" +msgstr "Origineel" + +msgid "Original/Customs" +msgstr "Origineel/Aangepast" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Ouderlijk toezicht" + +msgid "Partial" +msgstr "Gedeeltelijk" + +msgid "Partition" +msgstr "Partitie" + +msgid "Password" +msgstr "Wachtwoord" + +msgid "Password Changed" +msgstr "Wachtwoord gewijzigd" + +msgid "Password has been changed" +msgstr "Wachtwoord is gewijzigd" + +msgid "Patch Country Strings" +msgstr "Land Teksten Patchen" + +msgid "Path Changed" +msgstr "Pad gewijzigd" + +msgid "Permission denied." +msgstr "Toegang geweigerd." + +msgid "Pick from a list" +msgstr "Kiezen uit lijst" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Gespeeld" + +msgid "Play Next" +msgstr "Speel Volgende" + +msgid "Play Once" +msgstr "Speel één maal" + +msgid "Play Previous" +msgstr "Speel Vorige" + +msgid "Playing Music:" +msgstr "Speelt nu:" + +msgid "Please wait" +msgstr "Even geduld" + +msgid "Please wait..." +msgstr "Even geduld..." + +msgid "Power off the Wii" +msgstr "Wii uitschakelen" + +msgid "Prev" +msgstr "Vorige" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "Proces afgerond." + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Weergave knoppen" + +msgid "Published by" +msgstr "Uitgegeven door" + +msgid "Quick Boot" +msgstr "Snelle start" + +msgid "Random Directory Music" +msgstr "Willekeurige Map Muziek" + +msgid "Real Nand" +msgstr "Echte Nand" + +msgid "Receiving file from:" +msgstr "Bestand ontvangen van:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "Regio Patch" + +msgid "Released" +msgstr "Uitgegeven" + +msgid "Reload SD" +msgstr "SD herladen" + +msgid "Reloading game list now, please wait..." +msgstr "Spellijst wordt herladen, een moment..." + +msgid "Remember Unlock" +msgstr "Unlock onthouden" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "Verwijder update" + +msgid "Rename Game Title" +msgstr "Speltitel veranderen" + +msgid "Rename category" +msgstr "Hernoem categorie" + +msgid "Reset" +msgstr "Resetten" + +msgid "Reset BG Music" +msgstr "Reset achtergrond muziek" + +msgid "Reset Playcounter" +msgstr "Speeltellers resetten" + +msgid "Reset to default BGM?" +msgstr "Reset naar standaard achtergrond muziek?" + +msgid "Restarting..." +msgstr "Herstarten..." + +msgid "Return" +msgstr "Terug" + +msgid "Return To" +msgstr "Terug naar" + +msgid "Return to Wii Menu" +msgstr "Terug naar Wii menu" + +msgid "Right" +msgstr "Rechts" + +msgid "Rotating Disc" +msgstr "Draaiende Disk" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Trilfunctie" + +msgid "SChinese" +msgstr "SChinees" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "Geen toegang tot SD kaart." + +msgid "SD GameCube Games Path" +msgstr "SD GameCube Spellen Pad" + +msgid "SD GameCube Path" +msgstr "SD GameCube Pad" + +msgid "SD Path" +msgstr "SD Pad" + +msgid "SFX Volume" +msgstr "Volume geluidseffecten" + +msgid "Save" +msgstr "Opslaan" + +msgid "Save Failed. No device inserted?" +msgstr "Opslaan Mislukt. Geen media aanwezig?" + +msgid "Save Game List to" +msgstr "Spellenlijst opslaan in" + +msgid "Save List" +msgstr "Save lijst" + +msgid "Saved" +msgstr "Opgeslagen" + +msgid "Savegame might not exist for this game." +msgstr "Savegame bestaat wellicht niet voor dit spel." + +msgid "Screensaver" +msgstr "Schermbeveiliging" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "Selecteer" + +msgid "Select DOL Offset" +msgstr "Selecteer DOL Offset" + +msgid "Select a DOL" +msgstr "Selecteer een DOL" + +msgid "Select a DOL from Game" +msgstr "Selecteer een DOL van Spel" + +msgid "Select game categories" +msgstr "Selecteer spel categorieën" + +msgid "Select loader mode" +msgstr "Selecteer loader modus" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "Selecteer titels bron." + +msgid "Sept" +msgstr "Sep" + +msgid "Set Search-Filter" +msgstr "Zoekfilter instellen" + +msgid "Settings" +msgstr "Instellingen" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "Toon categorieën" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "Vrije ruimte weergeven" + +msgid "Show Play Count" +msgstr "Geef speelteller weer" + +msgid "Show SD" +msgstr "Geef SD weer" + +msgid "Shutdown System" +msgstr "Systeem uitzetten" + +msgid "Shutdown Wii" +msgstr "Wii uitzetten" + +msgid "Skip Errors" +msgstr "Fouten overslaan" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Alfabetisch sorteren" + +msgid "Sort by number of players" +msgstr "Sorteer op aantal spelers" + +msgid "Sort by rank" +msgstr "Sorteren op rang" + +msgid "Sort order by most played" +msgstr "Sorteer op meest gespeeld" + +msgid "Sound" +msgstr "Geluid" + +msgid "Sound Settings" +msgstr "Geluids Instellingen" + +msgid "Sound+BGM" +msgstr "Geluid+Achtergrondmuziek" + +msgid "Sound+Quiet" +msgstr "Geluid+Stilte" + +msgid "Spanish" +msgstr "Spaans" + +msgid "Special thanks to:" +msgstr "Speciale dank aan:" + +msgid "Split each 2GB" +msgstr "Splits iedere 2GB" + +msgid "Split each 4GB" +msgstr "Splits iedere 4GB" + +msgid "Standby" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "Succes" + +msgid "Success." +msgstr "Succes." + +msgid "Success:" +msgstr "Succes:" + +msgid "Successfully Saved" +msgstr "Met succes opgeslagen!" + +msgid "Successfully Updated" +msgstr "Met succes ge-update!" + +msgid "Successfully copied" +msgstr "Met succes gekopiëerd" + +msgid "Successfully deleted:" +msgstr "Met succes gedelete" + +msgid "Successfully extracted theme." +msgstr "Thema succesvol uitgepakt" + +msgid "Successfully installed:" +msgstr "Met succes geïnstalleerd" + +msgid "Successfully updated." +msgstr "Met succes geüpdate" + +msgid "Switching to channel list mode." +msgstr "Schakel naar kanaal lijst modus" + +msgid "Sync FAT32 FS Info" +msgstr "" + +msgid "Synchronizing..." +msgstr "Synchroniseren..." + +msgid "System Default" +msgstr "Systeem standaard" + +msgid "TChinese" +msgstr "Chinees Trad." + +msgid "TXT Cheatcodes Path" +msgstr "Locatie TXT cheats" + +msgid "The .them file was not found in the zip." +msgstr "Het .them bestand is niet gevonden in het zip bestand." + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "De optie Forceer Breedbeeld benodigd DIOS MIOS v2.1 of hoger. Deze instelling word genegeerd." + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "De Miis zullen worden uitgepakt naar EmuNand pad en EmuNand kanaalpad. Let op: Alle bestaande bestanden worden overschreven." + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "De optie Geen Disk+ benodigd DIOS MIOS 2.2 update2. Deze instelling word genegeerd." + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Het SYSCONF bestand zal uitgepakt worden naar EmuNand pad en EmuNand kanaal pad. Let op: Alle bestaande bestanden worden overschreven." + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "De applicatie kan crashen als er al schrijf/lees rechten zijn voor de SD kaart!" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "De opgegeven map bestaat niet. Wil je deze aanmaken?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "De bestanden worden uitgepakt naar je EmuNand Save en Kanaal pad. Let op: Alle bestaande bestanden worden overschreven." + +msgid "The game is on SD Card." +msgstr "Het spel is op de SD kaart." + +msgid "The game is on USB." +msgstr "Het spel is op USB." + +msgid "The save game will be extracted to your emu nand path." +msgstr "De Savegame wordt geëxporteerd naar uw EmuNand Pad." + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "De opgeslagen spellen worden uitgepakt naar je EmuNand Save en Kanaal pad. Let op: Alle bestaande bestanden worden overschreven." + +msgid "The wad file was installed" +msgstr "Het wad bestand is geïnstalleerd." + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "De wad installatie is mislukt met fout %i" + +msgid "Theme Downloader" +msgstr "Thema downloader" + +msgid "Theme Menu" +msgstr "Thema Menu" + +msgid "Theme Path" +msgstr "Locatie thema" + +msgid "Theme Title:" +msgstr "Thema Titel:" + +msgid "Themes by www.spiffy360.com" +msgstr "Thema's door www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "Deze IOS is de BootMii IOS. Als je zeker weet dat dit niet BootMii is en daar iets anders is geïnstalleerd kun je deze waarschuwing negeren." + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "Deze IOS is niet gevonden in de titel lijst. Als je zeker weet dat deze geïnstalleerd is kun je deze waarschuwing negeren." + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "Dit spel heeft meerdere disks. Geef aub aan welke er gestart dient te worden." + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "Dit pad moet op de SD kaart zijn!" + +msgid "Time left:" +msgstr "Tijd resterend:" + +msgid "Timer Fix" +msgstr "Timer Fix" + +msgid "Title Launcher" +msgstr "Titel Launcher" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "Titels van GameTDB" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "Om GameCube spellen vanaf disk te spelen moet je de GameCube modus op MIOS zetten in de spel instellingen." + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "Om GameCube games met %s te spelen moet je ze op een USB FAT32 partitie plaatsen." + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "Om GameCube spellen met %s te spelen moet je je 'Hoofd GameCube Pad' op een USB FAT32 partitie instellen." + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "Om GameCube spellen met %s te spelen moet je gebruik maken van een 512 bytes/sector schijf." + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "Om GameCube spellen met %s te spelen moet je gebruik maken van een partitie met 32k bytes/cluster of minder." + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "Om GameCube spellen met Devolution te spelen moet heb je het loader.bin bestand nodig in je Devolution Loader Locatie" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "Om GameCube spellen met Nintendont te spelen heb je boot.dol nodig in je Nintendont Loader Pad" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "Hulpballon Vertraging" + +msgid "Tooltips" +msgstr "Hulpballonnen" + +msgid "Transfer failed" +msgstr "Overdracht mislukt." + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX is vergrendeld" + +msgid "USB Port" +msgstr "USB Poort" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "USB Poort wisselen word alleen door Hermes cIOS ondersteund." + +msgid "USB-HID Controller" +msgstr "USB-HID Controller" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "USBLoaderGX kon Nintendont boot.dol niet verifiëren. Deze boot.dol toch starten?" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "USBLoaderGX kon Nintendont config bestand niet schrijven. Nintendont toch starten?" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "Verwijderen" + +msgid "Uninstall Game" +msgstr "Spel verwijderen" + +msgid "Uninstall Menu" +msgstr "Menu Verwijderen" + +msgid "Uninstall all" +msgstr "Verwijder alle" + +msgid "Unknown" +msgstr "Onbekend" + +msgid "Unlock USB Loader GX" +msgstr "Ontgrendel USB Loader GX" + +msgid "Unlocked" +msgstr "Vrijgegeven" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "Niet ondersteund formaat, probeer TempTheme.zip handmatig uit te pakken." + +msgid "Update" +msgstr "Updaten" + +msgid "Update All" +msgstr "Alles updaten" + +msgid "Update DOL" +msgstr "DOL updaten" + +msgid "Update Files" +msgstr "Bestanden Updaten" + +msgid "Update Path" +msgstr "Updatelocatie" + +msgid "Update all Language Files" +msgstr "Alle taalbestanden updaten" + +msgid "Update failed" +msgstr "Update mislukt" + +msgid "Update successfull" +msgstr "Update succesvol" + +msgid "Updating Language Files:" +msgstr "Taalbestanden updaten:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Geuploade ZIP is geïnstalleerd in je homebrew locatie." + +msgid "Use System Font" +msgstr "Gebruik Systeem lettertype" + +msgid "Use global" +msgstr "Gebruik globaal" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "VIDTV Patch" + +msgid "Version:" +msgstr "Versie:" + +#, c-format +msgid "Version: %s" +msgstr "Versie: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Video Modus" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "Virtuele Muis Snelheid" + +msgid "WDM Files Path" +msgstr "Locatie WDM bestanden" + +msgid "WIP Patches Path" +msgstr "Locatie WIP patches" + +msgid "Waiting..." +msgstr "Wachten..." + +msgid "Warning" +msgstr "Waarschuwing" + +msgid "Warning:" +msgstr "Waarschuwing:" + +msgid "What do you want to do?" +msgstr "Wat wil je doen?" + +msgid "What do you want to update?" +msgstr "Wat wil je updaten?" + +msgid "What should be deleted for this game title:" +msgstr "Wat moet er verwijderd worden voor deze spel titel:" + +msgid "What to extract from NAND?" +msgstr "Wat uitpakken van NAND?" + +msgid "Where should the game be installed to?" +msgstr "Waar moet het spel naar geïnstelleerd worden?" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "WiFi Functies" + +msgid "Widescreen Factor" +msgstr "Breedbeeld Factor" + +msgid "Widescreen Fix" +msgstr "Breedbeeld Fix" + +msgid "Wii Games" +msgstr "Wii Spellen" + +msgid "Wii Menu" +msgstr "Wii Menu" + +msgid "Wii Settings" +msgstr "Wii Instellingen" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "WiiTDB.xml is up to date." + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "WiiLight" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "Wiinertag Pad" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Wiinnertag vereist dat automatisch netwerk verbinden bij applicatie start aan staat. Wil je dit nu aanzetten?" + +msgid "Wiird Debugger" +msgstr "Wiird Debugger" + +#, c-format +msgid "Write error on file: %s" +msgstr "Schrijf fout bij bestand: %s" + +msgid "Writing GXGameCategories.xml" +msgstr "GXGameCategories.xml schrijven" + +msgid "Wrong Password" +msgstr "Fout wachtwoord" + +msgid "Yes" +msgstr "Ja" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "Je probeert een FAT32/NTFS/EXT partitie te selecteren met cIOS 249 Rev < 18. Dit word niet ondersteund. Verder gaan is op eigen risico." + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "Je kunt een een partitie selecteren of formateren of gebruik maken van de kanaal loader modus." + +msgid "You cannot delete this category." +msgstr "Je kunt deze categorie niet verwijderen." + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "Je moet DIOS MIOS Lite v1.2 of hoger installeren." + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "Je moet een extra GameCube loader installeren of selecteer een andere GameCube Modus om GameCube spellen te spelen vanaf USB of SD kaart." + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "Zoom tijd (snelheid)" + +msgid "and translators for language files updates" +msgstr "en vertalers voor taalbestand updates" + +msgid "available" +msgstr "beschikbaar" + +msgid "does not exist!" +msgstr "bestaat niet!" + +msgid "does not exist! Loading game without cheats." +msgstr "bestaat niet! Spel word geladen zonder cheats." + +msgid "files left" +msgstr "bestanden resterend" + +msgid "for FAT/NTFS support" +msgstr "voor FAT/NTFS ondersteuning" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "voor GameTDB en het hosten van covers en Disc plaatjes" + +msgid "for Ocarina" +msgstr "voor Ocarina" + +msgid "for diverse patches" +msgstr "voor diverse correcties" + +msgid "for his awesome tool LibWiiGui" +msgstr "voor zijn geweldige tool LibWiiGui" + +msgid "for hosting the themes" +msgstr "voor het hosten van de thema's" + +msgid "for the USB Loader source" +msgstr "voor USB Loader source" + +msgid "for their work on the wiki page" +msgstr "voor hun werk op de wiki pagina" + +msgid "formatted!" +msgstr "geformatteerd!" + +msgid "free" +msgstr "vrij" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "niet ingesteld" + +msgid "of" +msgstr "van" + +msgid "seconds left" +msgstr "seconde resterend" + +#~ msgid "Install WAD to EmuNand" +#~ msgstr "Installeer WAD naar EmuNand" + +#~ msgid "WAD Installation" +#~ msgstr "WAD Installatie" + +#~ msgid "GameTDB Path" +#~ msgstr "Map naar GameTBD" + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on a primary partition." +#~ msgstr "Om GameCube spellen met %s te spelen moet je je 'Hoofd GameCube Pad' op een primary partitie zetten." + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first partition of the Hard Drive." +#~ msgstr "Om GameCube spellen met %s te spelen moet je je 'Hoofd GameCube Pad' op de eerste partitie van de hardeschijf zetten." + +#~ msgid "Error 002 fix" +#~ msgstr "Herstel fout 002" + +#~ msgid "Use Game Settings" +#~ msgstr "Gebruik spel instellingen" + +#~ msgid "Main tester:" +#~ msgstr "Hoofd tester:" + +#~ msgid "Nintendont currently only supports GameCube games on SD card." +#~ msgstr "Nintendont ondersteund momenteel alleen GameCube games op SD kaart." + +#~ msgid "USB Device not found." +#~ msgstr "USB Apparaat niet gevonden." diff --git a/Languages/english.lang b/Languages/english.lang new file mode 100644 index 0000000..6c8e1ac --- /dev/null +++ b/Languages/english.lang @@ -0,0 +1,2502 @@ +# USB Loader GX language source file. +# english.lang - rxxxx +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:02+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr "" + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr "" + +msgid " is not on the server." +msgstr "" + +#, c-format +msgid "%i files not found on the server!" +msgstr "" + +#, c-format +msgid "%i missing files" +msgstr "" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "" + +msgid "1 (Child 7+)" +msgstr "" + +msgid "1 hour" +msgstr "" + +msgid "10 min" +msgstr "" + +msgid "2 (Teen 12+)" +msgstr "" + +msgid "20 min" +msgstr "" + +msgid "2D Cover Path" +msgstr "" + +msgid "3 (Mature 16+)" +msgstr "" + +msgid "3 min" +msgstr "" + +msgid "30 min" +msgstr "" + +msgid "3D Cover Path" +msgstr "" + +msgid "3D Covers" +msgstr "" + +msgid "4 (Adults Only 18+)" +msgstr "" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "" + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "" + +msgid "All Partitions" +msgstr "" + +msgid "All files extracted." +msgstr "" + +msgid "All images downloaded successfully." +msgstr "" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "" + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "" + +msgid "An example file was created here:" +msgstr "" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "" + +msgid "Apply" +msgstr "" + +msgid "Apr" +msgstr "" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "" + +msgid "Are you sure?" +msgstr "" + +msgid "Aspect Ratio" +msgstr "" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "" + +msgid "Author(s):" +msgstr "" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "" + +msgid "BCA Codes Path" +msgstr "" + +msgid "Back" +msgstr "" + +msgid "Back to HBC or Wii Menu" +msgstr "" + +msgid "Backgroundmusic" +msgstr "" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "" + +msgid "Block Categories Menu" +msgstr "" + +msgid "Block Categories Modify" +msgstr "" + +msgid "Block Cover Downloads" +msgstr "" + +msgid "Block Custom Paths" +msgstr "" + +msgid "Block Feature Settings" +msgstr "" + +msgid "Block Game Install" +msgstr "" + +msgid "Block Game Settings" +msgstr "" + +msgid "Block GameID Change" +msgstr "" + +msgid "Block Global Settings" +msgstr "" + +msgid "Block Gui Settings" +msgstr "" + +msgid "Block HBC Menu" +msgstr "" + +msgid "Block Hard Drive Settings" +msgstr "" + +msgid "Block IOS Reload" +msgstr "" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "" + +msgid "Block Parental Settings" +msgstr "" + +msgid "Block Priiloader Override" +msgstr "" + +msgid "Block Reset Settings" +msgstr "" + +msgid "Block SD Reload Button" +msgstr "" + +msgid "Block Sound Settings" +msgstr "" + +msgid "Block Theme Downloader" +msgstr "" + +msgid "Block Theme Menu" +msgstr "" + +msgid "Block Title Launcher" +msgstr "" + +msgid "Block Updates" +msgstr "" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "" + +msgid "Both" +msgstr "" + +msgid "Both Ports" +msgstr "" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "" + +msgid "Can't be formatted" +msgstr "" + +msgid "Can't create directory" +msgstr "" + +#, c-format +msgid "Can't create file: %s" +msgstr "" + +#, c-format +msgid "Can't create path: %s" +msgstr "" + +msgid "Can't delete:" +msgstr "" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "" + +#, c-format +msgid "Can't read file: %s" +msgstr "" + +msgid "Cancel" +msgstr "" + +msgid "Cannot write to destination." +msgstr "" + +msgid "Categories" +msgstr "" + +msgid "Categories:" +msgstr "" + +msgid "Change Play Path" +msgstr "" + +msgid "Channel Launcher" +msgstr "" + +msgid "Channels" +msgstr "" + +msgid "Cheatfile is blank" +msgstr "" + +msgid "Clear" +msgstr "" + +msgid "Click to Download Covers" +msgstr "" + +msgid "Click to change game ID" +msgstr "" + +msgid "Clock" +msgstr "" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "" + +msgid "Code Download" +msgstr "" + +#, c-format +msgid "Coded by: %s" +msgstr "" + +msgid "Coding:" +msgstr "" + +msgid "Connection to server timed out." +msgstr "" + +msgid "Console" +msgstr "" + +msgid "Console Default" +msgstr "" + +msgid "Console Locked" +msgstr "" + +msgid "Console must be unlocked for this option." +msgstr "" + +msgid "Console must be unlocked to be able to use this." +msgstr "" + +msgid "Console should be unlocked to modify it." +msgstr "" + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "" + +msgid "Continue?" +msgstr "" + +msgid "Controllevel" +msgstr "" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "" + +msgid "Could not connect to the server." +msgstr "" + +msgid "Could not create GCT file" +msgstr "" + +#, c-format +msgid "Could not create path: %s" +msgstr "" + +msgid "Could not extract files for:" +msgstr "" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "" + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "" + +msgid "Could not initialize network!" +msgstr "" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "" + +msgid "Could not open the WiiTDB.xml file." +msgstr "" + +msgid "Could not open wiitdb.xml." +msgstr "" + +msgid "Could not save." +msgstr "" + +msgid "Could not write file." +msgstr "" + +msgid "Could not write to:" +msgstr "" + +msgid "Cover Download" +msgstr "" + +msgid "Create" +msgstr "" + +msgid "Credits" +msgstr "" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "" + +msgid "Default" +msgstr "" + +msgid "Default Gamesettings" +msgstr "" + +msgid "Default Settings" +msgstr "" + +msgid "Delete" +msgstr "" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "" + +msgid "Delete Cheat TXT" +msgstr "" + +msgid "Delete Cover Artwork" +msgstr "" + +msgid "Delete Disc Artwork" +msgstr "" + +msgid "Delete category" +msgstr "" + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "" + +msgid "Details" +msgstr "" + +msgid "Developed by" +msgstr "" + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "" + +msgid "Disc Artwork Path" +msgstr "" + +msgid "Disc Default" +msgstr "" + +msgid "Disc Insert Detected" +msgstr "" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "" + +msgid "Display" +msgstr "" + +msgid "Display as a carousel" +msgstr "" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "" + +msgid "Display as a list" +msgstr "" + +msgid "Display favorites only" +msgstr "" + +msgid "Do you want to apply it now?" +msgstr "" + +msgid "Do you want to apply this theme?" +msgstr "" + +msgid "Do you want to change language?" +msgstr "" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "" + +msgid "Do you want to extract all the save games?" +msgstr "" + +msgid "Do you want to extract the save game?" +msgstr "" + +msgid "Do you want to format:" +msgstr "" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "" + +msgid "Do you wish to update/download all language files?" +msgstr "" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "" + +msgid "Download Now" +msgstr "" + +msgid "Download finished" +msgstr "" + +msgid "Downloading 3D Covers" +msgstr "" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "" + +msgid "Downloading Full HQ Covers" +msgstr "" + +msgid "Downloading Full LQ Covers" +msgstr "" + +msgid "Downloading custom Discarts" +msgstr "" + +msgid "Downloading file..." +msgstr "" + +msgid "Downloading image:" +msgstr "" + +msgid "Downloading original Discarts" +msgstr "" + +msgid "Downloading pagelist:" +msgstr "" + +msgid "Dump NAND to EmuNand" +msgstr "" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "" + +msgid "ERROR" +msgstr "" + +msgid "ERROR:" +msgstr "" + +msgid "ERROR: Can't set up theme." +msgstr "" + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "" + +msgid "Emulated Nand" +msgstr "" + +msgid "English" +msgstr "" + +msgid "Enter Path" +msgstr "" + +msgid "Error" +msgstr "" + +msgid "Error !" +msgstr "" + +#, c-format +msgid "Error creating path: %s" +msgstr "" + +msgid "Error opening downloaded file" +msgstr "" + +msgid "Error reading Disc" +msgstr "" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "" + +msgid "Error while downloding file" +msgstr "" + +msgid "Error while opening the zip." +msgstr "" + +msgid "Error while transfering data." +msgstr "" + +msgid "Error while updating USB Loader GX." +msgstr "" + +msgid "Error writing the data." +msgstr "" + +msgid "Error:" +msgstr "" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "" + +msgid "Everything" +msgstr "" + +msgid "Exit" +msgstr "" + +msgid "Exit to where?" +msgstr "" + +msgid "Export All Saves to EmuNand" +msgstr "" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "" + +msgid "Extracting file:" +msgstr "" + +msgid "Extracting files..." +msgstr "" + +msgid "Extracting files:" +msgstr "" + +msgid "Extracting nand files:" +msgstr "" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "" + +msgid "Failed to extract." +msgstr "" + +msgid "Failed to initialize the USB storage device." +msgstr "" + +msgid "Failed to open partition" +msgstr "" + +msgid "Failed to read ticket." +msgstr "" + +msgid "Failed to read tmd file." +msgstr "" + +msgid "Failed to read wad header." +msgstr "" + +msgid "Failed updating" +msgstr "" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "" + +msgid "Features Settings" +msgstr "" + +msgid "Feb" +msgstr "" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "" + +msgid "File read/write error." +msgstr "" + +msgid "Files extracted successfully." +msgstr "" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "" + +msgid "Filesize is 0 Byte." +msgstr "" + +msgid "Flat Covers" +msgstr "" + +msgid "Flip-X" +msgstr "" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "" + +msgid "Force NTSC480p" +msgstr "" + +msgid "Force PAL480p" +msgstr "" + +msgid "Force PAL50" +msgstr "" + +msgid "Force PAL60" +msgstr "" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "" + +msgid "Formatting, please wait..." +msgstr "" + +msgid "Found missing images." +msgstr "" + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "" + +msgid "French" +msgstr "" + +msgid "Full" +msgstr "" + +msgid "Full Cover Path" +msgstr "" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "" + +msgid "GAMEID_Gamename" +msgstr "" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "" + +msgid "GCT File created" +msgstr "" + +msgid "GUI Settings" +msgstr "" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "" + +msgid "Game IOS" +msgstr "" + +msgid "Game Language" +msgstr "" + +msgid "Game Load" +msgstr "" + +msgid "Game Lock" +msgstr "" + +msgid "Game Only" +msgstr "" + +msgid "Game Region" +msgstr "" + +msgid "Game Size" +msgstr "" + +msgid "Game Sound Mode" +msgstr "" + +msgid "Game Sound Volume" +msgstr "" + +msgid "Game Split Size" +msgstr "" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "" + +msgid "Games" +msgstr "" + +msgid "Generating GXGameCategories.xml" +msgstr "" + +msgid "Genre:" +msgstr "" + +msgid "German" +msgstr "" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "" + +msgid "Hard Drive Settings" +msgstr "" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "" + +msgid "Homebrew Channel" +msgstr "" + +msgid "Homebrew Launcher" +msgstr "" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "" + +msgid "How do you want to update?" +msgstr "" + +msgid "How to Shutdown?" +msgstr "" + +msgid "Import Categories" +msgstr "" + +msgid "Import operation successfully completed." +msgstr "" + +msgid "Importing categories" +msgstr "" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "" + +msgid "Insert Disk" +msgstr "" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "" + +msgid "Install Canceled" +msgstr "" + +msgid "Install Directories" +msgstr "" + +msgid "Install Error!" +msgstr "" + +msgid "Install Partitions" +msgstr "" + +msgid "Install a game" +msgstr "" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "" + +msgid "Installing game:" +msgstr "" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "" + +msgid "Italian" +msgstr "" + +msgid "Jan" +msgstr "" + +msgid "Japanese" +msgstr "" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "" + +msgid "June" +msgstr "" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "" + +msgid "Korean" +msgstr "" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "" + +msgid "Language change:" +msgstr "" + +msgid "Languagefiles Path" +msgstr "" + +msgid "Languagepath changed." +msgstr "" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Left" +msgstr "" + +msgid "Like SysMenu" +msgstr "" + +msgid "List on Gamelaunch" +msgstr "" + +msgid "Load" +msgstr "" + +msgid "Load From SD/USB" +msgstr "" + +#, c-format +msgid "Load file from: %s ?" +msgstr "" + +msgid "Load this DOL as alternate DOL?" +msgstr "" + +msgid "Loader Settings" +msgstr "" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "" + +msgid "Loading standard music." +msgstr "" + +msgid "Lock Console" +msgstr "" + +msgid "Lock USB Loader GX" +msgstr "" + +msgid "Locked" +msgstr "" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "" + +msgid "Loop Music" +msgstr "" + +msgid "Loop Sound" +msgstr "" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "" + +msgid "Mark new games" +msgstr "" + +msgid "May" +msgstr "" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "" + +msgid "Motion+ Video" +msgstr "" + +msgid "Mount DVD drive" +msgstr "" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "" + +msgid "Music Loop Mode" +msgstr "" + +msgid "Music Volume" +msgstr "" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "" + +msgid "Nand Channels" +msgstr "" + +msgid "Nand Emu Channel Path" +msgstr "" + +msgid "Nand Emu Path" +msgstr "" + +msgid "Nand Emulation" +msgstr "" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "" + +msgid "Network is not initiated." +msgstr "" + +msgid "Next" +msgstr "" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "" + +msgid "No Cheatfile found" +msgstr "" + +msgid "No DOL file found on disc." +msgstr "" + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "" + +msgid "No URL or Path specified." +msgstr "" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "" + +msgid "No disc inserted." +msgstr "" + +msgid "No favorites selected." +msgstr "" + +msgid "No file missing!" +msgstr "" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "" + +msgid "No new updates." +msgstr "" + +msgid "No themes found on the site." +msgstr "" + +msgid "No themes found." +msgstr "" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "" + +msgid "Normal" +msgstr "" + +msgid "Not Initialized" +msgstr "" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "" + +msgid "Not a valid URL path" +msgstr "" + +msgid "Not a valid domain" +msgstr "" + +msgid "Not enough free memory." +msgstr "" + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "" + +msgid "Not required" +msgstr "" + +msgid "Not supported format!" +msgstr "" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "" + +msgid "OFF" +msgstr "" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "" + +msgid "Official Site:" +msgstr "" + +msgid "Offset" +msgstr "" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "" + +msgid "Only for Install" +msgstr "" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "" + +msgid "Partial" +msgstr "" + +msgid "Partition" +msgstr "" + +msgid "Password" +msgstr "" + +msgid "Password Changed" +msgstr "" + +msgid "Password has been changed" +msgstr "" + +msgid "Patch Country Strings" +msgstr "" + +msgid "Path Changed" +msgstr "" + +msgid "Permission denied." +msgstr "" + +msgid "Pick from a list" +msgstr "" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "" + +msgid "Play Next" +msgstr "" + +msgid "Play Once" +msgstr "" + +msgid "Play Previous" +msgstr "" + +msgid "Playing Music:" +msgstr "" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "" + +msgid "Power off the Wii" +msgstr "" + +msgid "Prev" +msgstr "" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "" + +msgid "Published by" +msgstr "" + +msgid "Quick Boot" +msgstr "" + +msgid "Random Directory Music" +msgstr "" + +msgid "Real Nand" +msgstr "" + +msgid "Receiving file from:" +msgstr "" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "" + +msgid "Released" +msgstr "" + +msgid "Reload SD" +msgstr "" + +msgid "Reloading game list now, please wait..." +msgstr "" + +msgid "Remember Unlock" +msgstr "" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "" + +msgid "Rename Game Title" +msgstr "" + +msgid "Rename category" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Reset BG Music" +msgstr "" + +msgid "Reset Playcounter" +msgstr "" + +msgid "Reset to default BGM?" +msgstr "" + +msgid "Restarting..." +msgstr "" + +msgid "Return" +msgstr "" + +msgid "Return To" +msgstr "" + +msgid "Return to Wii Menu" +msgstr "" + +msgid "Right" +msgstr "" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "" + +msgid "SChinese" +msgstr "" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "" + +msgid "Save" +msgstr "" + +msgid "Save Failed. No device inserted?" +msgstr "" + +msgid "Save Game List to" +msgstr "" + +msgid "Save List" +msgstr "" + +msgid "Saved" +msgstr "" + +msgid "Savegame might not exist for this game." +msgstr "" + +msgid "Screensaver" +msgstr "" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "" + +msgid "Select DOL Offset" +msgstr "" + +msgid "Select a DOL" +msgstr "" + +msgid "Select a DOL from Game" +msgstr "" + +msgid "Select game categories" +msgstr "" + +msgid "Select loader mode" +msgstr "" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "" + +msgid "Sept" +msgstr "" + +msgid "Set Search-Filter" +msgstr "" + +msgid "Settings" +msgstr "" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "" + +msgid "Show Play Count" +msgstr "" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "" + +msgid "Shutdown Wii" +msgstr "" + +msgid "Skip Errors" +msgstr "" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "" + +msgid "Sort by number of players" +msgstr "" + +msgid "Sort by rank" +msgstr "" + +msgid "Sort order by most played" +msgstr "" + +msgid "Sound" +msgstr "" + +msgid "Sound Settings" +msgstr "" + +msgid "Sound+BGM" +msgstr "" + +msgid "Sound+Quiet" +msgstr "" + +msgid "Spanish" +msgstr "" + +msgid "Special thanks to:" +msgstr "" + +msgid "Split each 2GB" +msgstr "" + +msgid "Split each 4GB" +msgstr "" + +msgid "Standby" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "" + +msgid "Success." +msgstr "" + +msgid "Success:" +msgstr "" + +msgid "Successfully Saved" +msgstr "" + +msgid "Successfully Updated" +msgstr "" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "" + +msgid "Successfully extracted theme." +msgstr "" + +msgid "Successfully installed:" +msgstr "" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "" + +msgid "Sync FAT32 FS Info" +msgstr "" + +msgid "Synchronizing..." +msgstr "" + +msgid "System Default" +msgstr "" + +msgid "TChinese" +msgstr "" + +msgid "TXT Cheatcodes Path" +msgstr "" + +msgid "The .them file was not found in the zip." +msgstr "" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "" + +msgid "Theme Downloader" +msgstr "" + +msgid "Theme Menu" +msgstr "" + +msgid "Theme Path" +msgstr "" + +msgid "Theme Title:" +msgstr "" + +msgid "Themes by www.spiffy360.com" +msgstr "" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "" + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "" + +msgid "Transfer failed" +msgstr "" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "" + +msgid "USB Port" +msgstr "" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "" + +msgid "Uninstall Game" +msgstr "" + +msgid "Uninstall Menu" +msgstr "" + +msgid "Uninstall all" +msgstr "" + +msgid "Unknown" +msgstr "" + +msgid "Unlock USB Loader GX" +msgstr "" + +msgid "Unlocked" +msgstr "" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "" + +msgid "Update" +msgstr "" + +msgid "Update All" +msgstr "" + +msgid "Update DOL" +msgstr "" + +msgid "Update Files" +msgstr "" + +msgid "Update Path" +msgstr "" + +msgid "Update all Language Files" +msgstr "" + +msgid "Update failed" +msgstr "" + +msgid "Update successfull" +msgstr "" + +msgid "Updating Language Files:" +msgstr "" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "" + +msgid "Use System Font" +msgstr "" + +msgid "Use global" +msgstr "" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "" + +msgid "Version:" +msgstr "" + +#, c-format +msgid "Version: %s" +msgstr "" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "" + +msgid "WDM Files Path" +msgstr "" + +msgid "WIP Patches Path" +msgstr "" + +msgid "Waiting..." +msgstr "" + +msgid "Warning" +msgstr "" + +msgid "Warning:" +msgstr "" + +msgid "What do you want to do?" +msgstr "" + +msgid "What do you want to update?" +msgstr "" + +msgid "What should be deleted for this game title:" +msgstr "" + +msgid "What to extract from NAND?" +msgstr "" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "" + +msgid "Widescreen Factor" +msgstr "" + +msgid "Widescreen Fix" +msgstr "" + +msgid "Wii Games" +msgstr "" + +msgid "Wii Menu" +msgstr "" + +msgid "Wii Settings" +msgstr "" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "" + +msgid "Wiird Debugger" +msgstr "" + +#, c-format +msgid "Write error on file: %s" +msgstr "" + +msgid "Writing GXGameCategories.xml" +msgstr "" + +msgid "Wrong Password" +msgstr "" + +msgid "Yes" +msgstr "" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "" + +msgid "You cannot delete this category." +msgstr "" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "" + +msgid "available" +msgstr "" + +msgid "does not exist!" +msgstr "" + +msgid "does not exist! Loading game without cheats." +msgstr "" + +msgid "files left" +msgstr "" + +msgid "for FAT/NTFS support" +msgstr "" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "" + +msgid "for Ocarina" +msgstr "" + +msgid "for diverse patches" +msgstr "" + +msgid "for his awesome tool LibWiiGui" +msgstr "" + +msgid "for hosting the themes" +msgstr "" + +msgid "for the USB Loader source" +msgstr "" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "" + +msgid "free" +msgstr "" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "" + +msgid "of" +msgstr "" + +msgid "seconds left" +msgstr "" diff --git a/Languages/finnish.lang b/Languages/finnish.lang new file mode 100644 index 0000000..19afce8 --- /dev/null +++ b/Languages/finnish.lang @@ -0,0 +1,2820 @@ +# USB Loader GX language source file. +# finnish.lang - r740 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:02+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: c64rmx\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr "Latausta ei voitu suorittaa" + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr "" + +msgid " is not on the server." +msgstr "Tiedostoa ei löydy serveriltä" + +#, c-format +msgid "%i files not found on the server!" +msgstr "" + +#, c-format +msgid "%i missing files" +msgstr "" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Kaikille)" + +msgid "1 (Child 7+)" +msgstr "1 (Lapset 7+)" + +msgid "1 hour" +msgstr " 1 tunti" + +msgid "10 min" +msgstr "" + +msgid "2 (Teen 12+)" +msgstr "2 (Teinit 12+)" + +msgid "20 min" +msgstr "" + +msgid "2D Cover Path" +msgstr "2D Kansien polku" + +msgid "3 (Mature 16+)" +msgstr "3 (Teinit 16+)" + +msgid "3 min" +msgstr "" + +msgid "30 min" +msgstr "" + +msgid "3D Cover Path" +msgstr "3D Kansien polku" + +msgid "3D Covers" +msgstr "3D Kannet" + +msgid "4 (Adults Only 18+)" +msgstr "4 (K18)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "" + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "" + +msgid "All Partitions" +msgstr "" + +msgid "All files extracted." +msgstr "" + +msgid "All images downloaded successfully." +msgstr "" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Kaikki asetukset on nyt käytettävissä." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Vaihtoehto DOL" + +msgid "An example file was created here:" +msgstr "" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "Ohjelman kieli" + +msgid "Apply" +msgstr "" + +msgid "Apr" +msgstr "huhti" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "" + +msgid "Are you sure?" +msgstr "Oletko varma?" + +msgid "Aspect Ratio" +msgstr "" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "elo" + +msgid "Author(s):" +msgstr "" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "Autom. verkon käynnistys" + +msgid "BCA Codes Path" +msgstr "" + +msgid "Back" +msgstr "Takaisin" + +msgid "Back to HBC or Wii Menu" +msgstr "Takaisin HBC:hen tai Wii Menuun" + +msgid "Backgroundmusic" +msgstr "Taustamusiikki" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "Isot kiitokset:" + +msgid "Block Categories Menu" +msgstr "" + +msgid "Block Categories Modify" +msgstr "" + +msgid "Block Cover Downloads" +msgstr "" + +msgid "Block Custom Paths" +msgstr "" + +msgid "Block Feature Settings" +msgstr "" + +msgid "Block Game Install" +msgstr "" + +msgid "Block Game Settings" +msgstr "" + +msgid "Block GameID Change" +msgstr "" + +msgid "Block Global Settings" +msgstr "" + +msgid "Block Gui Settings" +msgstr "" + +msgid "Block HBC Menu" +msgstr "" + +msgid "Block Hard Drive Settings" +msgstr "" + +msgid "Block IOS Reload" +msgstr "Blokkaa IOS:in uudelleenlataus" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "" + +msgid "Block Parental Settings" +msgstr "" + +msgid "Block Priiloader Override" +msgstr "" + +msgid "Block Reset Settings" +msgstr "" + +msgid "Block SD Reload Button" +msgstr "" + +msgid "Block Sound Settings" +msgstr "" + +msgid "Block Theme Downloader" +msgstr "" + +msgid "Block Theme Menu" +msgstr "" + +msgid "Block Title Launcher" +msgstr "" + +msgid "Block Updates" +msgstr "" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "Boottaa?" + +msgid "Both" +msgstr "Molemmat" + +msgid "Both Ports" +msgstr "" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "" + +msgid "Can't be formatted" +msgstr "Ei voida formatoida" + +msgid "Can't create directory" +msgstr "Ei voi luoda kansiota" + +#, c-format +msgid "Can't create file: %s" +msgstr "" + +#, c-format +msgid "Can't create path: %s" +msgstr "" + +msgid "Can't delete:" +msgstr "Ei voida poistaa:" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "" + +#, c-format +msgid "Can't read file: %s" +msgstr "" + +msgid "Cancel" +msgstr "Peruuta" + +msgid "Cannot write to destination." +msgstr "" + +msgid "Categories" +msgstr "" + +msgid "Categories:" +msgstr "" + +msgid "Change Play Path" +msgstr "" + +msgid "Channel Launcher" +msgstr "" + +msgid "Channels" +msgstr "" + +msgid "Cheatfile is blank" +msgstr "Kooditiedosto tyhjä" + +msgid "Clear" +msgstr "" + +msgid "Click to Download Covers" +msgstr "Klikkaa ladataksesi kansia" + +msgid "Click to change game ID" +msgstr "Klikkaa vaihtaaksesi pelin ID" + +msgid "Clock" +msgstr "Kello" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "Sulje" + +msgid "Code Download" +msgstr "Koodin lataus" + +#, c-format +msgid "Coded by: %s" +msgstr "Koodaus: %s" + +msgid "Coding:" +msgstr "Koodaus" + +msgid "Connection to server timed out." +msgstr "" + +msgid "Console" +msgstr "Konsoli" + +msgid "Console Default" +msgstr "Konsolin oletus" + +msgid "Console Locked" +msgstr "Konsoli lukittu" + +msgid "Console must be unlocked for this option." +msgstr "" + +msgid "Console must be unlocked to be able to use this." +msgstr "" + +msgid "Console should be unlocked to modify it." +msgstr "Avaa konsolin lukitus muokataksesi asetuksia." + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "Jatka pelin asennusta?" + +msgid "Continue?" +msgstr "" + +msgid "Controllevel" +msgstr "Hallinta-aste" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "Oikea salasana" + +msgid "Could not connect to the server." +msgstr "" + +msgid "Could not create GCT file" +msgstr "GCT tiedostoa ei voitu luoda" + +#, c-format +msgid "Could not create path: %s" +msgstr "" + +msgid "Could not extract files for:" +msgstr "" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "" + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "DIP Moduulia ei voitu alustaa!" + +msgid "Could not initialize network!" +msgstr "Verkkoon ei voitu yhdistää!" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "Levyä ei voitu avata" + +msgid "Could not open the WiiTDB.xml file." +msgstr "" + +msgid "Could not open wiitdb.xml." +msgstr "" + +msgid "Could not save." +msgstr "" + +msgid "Could not write file." +msgstr "" + +msgid "Could not write to:" +msgstr "" + +msgid "Cover Download" +msgstr "Kansien lataus" + +msgid "Create" +msgstr "Luo" + +msgid "Credits" +msgstr "Tekijät" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "Omat polut" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "Omat/Alkuperäiset" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "DOL:in polku" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "joulu" + +msgid "Default" +msgstr "Oletus" + +msgid "Default Gamesettings" +msgstr "Oletus peliasetukset" + +msgid "Default Settings" +msgstr "Oletusasetukset" + +msgid "Delete" +msgstr "Tuhoa" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "Tuhoa Koodi GCT" + +msgid "Delete Cheat TXT" +msgstr "Tuhoa Koodi TXT" + +msgid "Delete Cover Artwork" +msgstr "Tuhoa kannet" + +msgid "Delete Disc Artwork" +msgstr "Tuhoa levykuvat" + +msgid "Delete category" +msgstr "" + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "Suunnittelu" + +msgid "Details" +msgstr "" + +msgid "Developed by" +msgstr "Kehitys" + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "Levykuvien lataus" + +msgid "Disc Artwork Path" +msgstr "Levykuvien polku" + +msgid "Disc Default" +msgstr "Pelin oletus" + +msgid "Disc Insert Detected" +msgstr "" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "Levynvaihto" + +msgid "Display" +msgstr "Näyttö" + +msgid "Display as a carousel" +msgstr "Näytä karusellina" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "Näytä taulukkona" + +msgid "Display as a list" +msgstr "Näytä listana" + +msgid "Display favorites only" +msgstr "" + +msgid "Do you want to apply it now?" +msgstr "" + +msgid "Do you want to apply this theme?" +msgstr "" + +msgid "Do you want to change language?" +msgstr "Haluatko vaihtaa kielen?" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "" + +msgid "Do you want to extract all the save games?" +msgstr "" + +msgid "Do you want to extract the save game?" +msgstr "" + +msgid "Do you want to format:" +msgstr "Haluatko formatoida:" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "" + +msgid "Do you wish to update/download all language files?" +msgstr "Haluatko päivittää/ladata kaikki kielitiedostot?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "" + +msgid "Download Now" +msgstr "Lataa nyt" + +msgid "Download finished" +msgstr "Lataus valmistunut" + +msgid "Downloading 3D Covers" +msgstr "" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "" + +msgid "Downloading Full HQ Covers" +msgstr "" + +msgid "Downloading Full LQ Covers" +msgstr "" + +msgid "Downloading custom Discarts" +msgstr "" + +msgid "Downloading file..." +msgstr "" + +msgid "Downloading image:" +msgstr "" + +msgid "Downloading original Discarts" +msgstr "" + +msgid "Downloading pagelist:" +msgstr "" + +msgid "Dump NAND to EmuNand" +msgstr "" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "Hollanti" + +msgid "ERROR" +msgstr "VIRHE" + +msgid "ERROR:" +msgstr "VIRHE:" + +msgid "ERROR: Can't set up theme." +msgstr "" + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "" + +msgid "Emulated Nand" +msgstr "" + +msgid "English" +msgstr "Englanti" + +msgid "Enter Path" +msgstr "" + +msgid "Error" +msgstr "Virhe" + +msgid "Error !" +msgstr "Virhe !" + +#, c-format +msgid "Error creating path: %s" +msgstr "" + +msgid "Error opening downloaded file" +msgstr "" + +msgid "Error reading Disc" +msgstr "Virhe luettaessa levyä" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "" + +msgid "Error while downloding file" +msgstr "" + +msgid "Error while opening the zip." +msgstr "" + +msgid "Error while transfering data." +msgstr "Virhe siirrettäessä dataa." + +msgid "Error while updating USB Loader GX." +msgstr "" + +msgid "Error writing the data." +msgstr "" + +msgid "Error:" +msgstr "Virhe:" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "" + +msgid "Everything" +msgstr "" + +msgid "Exit" +msgstr "" + +msgid "Exit to where?" +msgstr "" + +msgid "Export All Saves to EmuNand" +msgstr "" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "" + +msgid "Extracting file:" +msgstr "" + +msgid "Extracting files..." +msgstr "" + +msgid "Extracting files:" +msgstr "" + +msgid "Extracting nand files:" +msgstr "" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "Formatointi ei onnistunut" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "" + +msgid "Failed to extract." +msgstr "" + +msgid "Failed to initialize the USB storage device." +msgstr "" + +msgid "Failed to open partition" +msgstr "Osion avaus epäonnistui" + +msgid "Failed to read ticket." +msgstr "" + +msgid "Failed to read tmd file." +msgstr "" + +msgid "Failed to read wad header." +msgstr "" + +msgid "Failed updating" +msgstr "" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "" + +msgid "Features Settings" +msgstr "" + +msgid "Feb" +msgstr "helmi" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Tiedostoa ei löytynyt" + +msgid "File read/write error." +msgstr "" + +msgid "Files extracted successfully." +msgstr "" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "" + +msgid "Filesize is 0 Byte." +msgstr "" + +msgid "Flat Covers" +msgstr "" + +msgid "Flip-X" +msgstr "Käännä-X" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "" + +msgid "Force NTSC480p" +msgstr "" + +msgid "Force PAL480p" +msgstr "" + +msgid "Force PAL50" +msgstr "" + +msgid "Force PAL60" +msgstr "" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Formatoi" + +msgid "Formatting, please wait..." +msgstr "Formatoi, odota..." + +msgid "Found missing images." +msgstr "" + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "Vapaata tilaa" + +msgid "French" +msgstr "Ranska" + +msgid "Full" +msgstr "" + +msgid "Full Cover Path" +msgstr "" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "" + +msgid "GAMEID_Gamename" +msgstr "" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "GCT Koodien polku" + +msgid "GCT File created" +msgstr "Gct tiedosto luotu" + +msgid "GUI Settings" +msgstr "GUI asetukset" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "Peli ID" + +msgid "Game IOS" +msgstr "" + +msgid "Game Language" +msgstr "Kieli" + +msgid "Game Load" +msgstr "Pelin lataus" + +msgid "Game Lock" +msgstr "" + +msgid "Game Only" +msgstr "" + +msgid "Game Region" +msgstr "Alue" + +msgid "Game Size" +msgstr "Pelin koko" + +msgid "Game Sound Mode" +msgstr "" + +msgid "Game Sound Volume" +msgstr "" + +msgid "Game Split Size" +msgstr "" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "Peli on jo asennettu:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "" + +msgid "Games" +msgstr "Pelejä" + +msgid "Generating GXGameCategories.xml" +msgstr "" + +msgid "Genre:" +msgstr "" + +msgid "German" +msgstr "Saksa" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "" + +msgid "Hard Drive Settings" +msgstr "" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "Homebrew Apps polku" + +msgid "Homebrew Channel" +msgstr "" + +msgid "Homebrew Launcher" +msgstr "" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "Tunti" + +msgid "How do you want to update?" +msgstr "Kuinka haluat päivittää?" + +msgid "How to Shutdown?" +msgstr "Miten sammutetaan?" + +msgid "Import Categories" +msgstr "" + +msgid "Import operation successfully completed." +msgstr "" + +msgid "Importing categories" +msgstr "" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "Yhdistää verkkoon" + +msgid "Insert Disk" +msgstr "Aseta levy Wiihin" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "Asenna" + +msgid "Install Canceled" +msgstr "" + +msgid "Install Directories" +msgstr "" + +msgid "Install Error!" +msgstr "Asennusvirhe!" + +msgid "Install Partitions" +msgstr "" + +msgid "Install a game" +msgstr "Asenna peli" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "" + +msgid "Installing game:" +msgstr "Asentaa peliä:" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Näyttää että sinulla on tietoa joka on hyödyllistä meille. Ole ystävällinen ja välitä se kehitystiimille." + +msgid "Italian" +msgstr "Italia" + +msgid "Jan" +msgstr "tammi" + +msgid "Japanese" +msgstr "Japani" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "heinä" + +msgid "June" +msgstr "kesä" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Näppäimistö" + +msgid "Korean" +msgstr "Korea" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "" + +msgid "Language change:" +msgstr "Kielen vaihto" + +msgid "Languagefiles Path" +msgstr "" + +msgid "Languagepath changed." +msgstr "Kielen polku vaihdettu" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Left" +msgstr "Vasen" + +msgid "Like SysMenu" +msgstr "Kuin wii-menu" + +msgid "List on Gamelaunch" +msgstr "" + +msgid "Load" +msgstr "Lataa" + +msgid "Load From SD/USB" +msgstr "Lataa SD:ltä/USB:ltä" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Lataa tiedosto: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Lataa tämä vaihtoehtoisesti tämä dol?" + +msgid "Loader Settings" +msgstr "" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "Ladataan standardia kieltä" + +msgid "Loading standard music." +msgstr "Ladataan standardia musiikkia" + +msgid "Lock Console" +msgstr "Lukitse konsoli" + +msgid "Lock USB Loader GX" +msgstr "" + +msgid "Locked" +msgstr "Lukittu" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "" + +msgid "Loop Music" +msgstr "" + +msgid "Loop Sound" +msgstr "" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "maalis" + +msgid "Mark new games" +msgstr "" + +msgid "May" +msgstr "touko" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "" + +msgid "Motion+ Video" +msgstr "" + +msgid "Mount DVD drive" +msgstr "" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "" + +msgid "Music Loop Mode" +msgstr "" + +msgid "Music Volume" +msgstr "Voimakkuus" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "" + +msgid "Nand Channels" +msgstr "" + +msgid "Nand Emu Channel Path" +msgstr "" + +msgid "Nand Emu Path" +msgstr "" + +msgid "Nand Emulation" +msgstr "" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Ei kumpikaan" + +msgid "Network is not initiated." +msgstr "" + +msgid "Next" +msgstr "Seuraava" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "Ei" + +msgid "No Cheatfile found" +msgstr "Kooditiedostoa ei löydy" + +msgid "No DOL file found on disc." +msgstr "Levyltä ei löydy dol tiedostoa" + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "" + +msgid "No URL or Path specified." +msgstr "" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "Tietoa ei voitu lukea" + +msgid "No disc inserted." +msgstr "" + +msgid "No favorites selected." +msgstr "" + +msgid "No file missing!" +msgstr "Ei tiedostoja kadoksissa!" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "" + +msgid "No new updates." +msgstr "Ei uusia päivityksiä" + +msgid "No themes found on the site." +msgstr "" + +msgid "No themes found." +msgstr "" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "" + +msgid "Normal" +msgstr "Normaali" + +msgid "Not Initialized" +msgstr "" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "" + +msgid "Not a valid URL path" +msgstr "" + +msgid "Not a valid domain" +msgstr "" + +msgid "Not enough free memory." +msgstr "Ei tarpeeksi muistia." + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "Ei tarpeeksi tilaa!" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "" + +msgid "Not required" +msgstr "" + +msgid "Not supported format!" +msgstr "Ei tuettu formaatti!" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "marras" + +msgid "OFF" +msgstr "Pois" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "Päälle" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "loka" + +msgid "Official Site:" +msgstr "Virallinen sivusto:" + +msgid "Offset" +msgstr "" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "" + +msgid "Only for Install" +msgstr "Ainoastaan asennusta varten" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Alkuperäinen/Omatekoinen" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Valvonta" + +msgid "Partial" +msgstr "" + +msgid "Partition" +msgstr "Osio" + +msgid "Password" +msgstr "Salasana" + +msgid "Password Changed" +msgstr "Salasana muutettu" + +msgid "Password has been changed" +msgstr "Salasana on muutettu" + +msgid "Patch Country Strings" +msgstr "Patchaa maa merkkijonot" + +msgid "Path Changed" +msgstr "" + +msgid "Permission denied." +msgstr "" + +msgid "Pick from a list" +msgstr "Valitse listasta" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Pelauksen määrä" + +msgid "Play Next" +msgstr "" + +msgid "Play Once" +msgstr "" + +msgid "Play Previous" +msgstr "" + +msgid "Playing Music:" +msgstr "" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "" + +msgid "Power off the Wii" +msgstr "Sammuta Wii" + +msgid "Prev" +msgstr "Edellinen" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Napit" + +msgid "Published by" +msgstr "Julkaisu:" + +msgid "Quick Boot" +msgstr "" + +msgid "Random Directory Music" +msgstr "" + +msgid "Real Nand" +msgstr "" + +msgid "Receiving file from:" +msgstr "Ladataan tiedostoa:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "" + +msgid "Released" +msgstr "Julkaistu" + +msgid "Reload SD" +msgstr "Uudelleenlataa SD" + +msgid "Reloading game list now, please wait..." +msgstr "" + +msgid "Remember Unlock" +msgstr "" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "" + +msgid "Rename Game Title" +msgstr "Uudelleennimeä peli" + +msgid "Rename category" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Reset BG Music" +msgstr "" + +msgid "Reset Playcounter" +msgstr "Resetoi pelauksen määrä" + +msgid "Reset to default BGM?" +msgstr "" + +msgid "Restarting..." +msgstr "Boottaa..." + +msgid "Return" +msgstr "Palaa" + +msgid "Return To" +msgstr "" + +msgid "Return to Wii Menu" +msgstr "Palaa Wii menuun" + +msgid "Right" +msgstr "Oikea" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Värinä" + +msgid "SChinese" +msgstr "SKiina" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "Ääniefektien voimakkuus" + +msgid "Save" +msgstr "Tallenna" + +msgid "Save Failed. No device inserted?" +msgstr "" + +msgid "Save Game List to" +msgstr "" + +msgid "Save List" +msgstr "" + +msgid "Saved" +msgstr "" + +msgid "Savegame might not exist for this game." +msgstr "" + +msgid "Screensaver" +msgstr "Näytönsäästäjä" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "" + +msgid "Select DOL Offset" +msgstr "" + +msgid "Select a DOL" +msgstr "Valitse DOL" + +msgid "Select a DOL from Game" +msgstr "" + +msgid "Select game categories" +msgstr "" + +msgid "Select loader mode" +msgstr "" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "" + +msgid "Sept" +msgstr "syys" + +msgid "Set Search-Filter" +msgstr "" + +msgid "Settings" +msgstr "Asetukset" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "" + +msgid "Show Play Count" +msgstr "" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "Sammuta järjestelmä" + +msgid "Shutdown Wii" +msgstr "" + +msgid "Skip Errors" +msgstr "" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Järjestä aakkosittain" + +msgid "Sort by number of players" +msgstr "" + +msgid "Sort by rank" +msgstr "" + +msgid "Sort order by most played" +msgstr "Aseta 'pelattu eniten' järjestykseen" + +msgid "Sound" +msgstr "Ääni" + +msgid "Sound Settings" +msgstr "" + +msgid "Sound+BGM" +msgstr "" + +msgid "Sound+Quiet" +msgstr "" + +msgid "Spanish" +msgstr "Espanja" + +msgid "Special thanks to:" +msgstr "Erityiskiitokset" + +msgid "Split each 2GB" +msgstr "" + +msgid "Split each 4GB" +msgstr "" + +msgid "Standby" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "Onnistui" + +msgid "Success." +msgstr "" + +msgid "Success:" +msgstr "Onnistui:" + +msgid "Successfully Saved" +msgstr "Tallennettu onnistuneesti" + +msgid "Successfully Updated" +msgstr "Päivitetty onnistuneesti" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "Poistettu onnistuneesti:" + +msgid "Successfully extracted theme." +msgstr "" + +msgid "Successfully installed:" +msgstr "Asennettu onnistuneesti:" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "" + +msgid "Sync FAT32 FS Info" +msgstr "" + +msgid "Synchronizing..." +msgstr "" + +msgid "System Default" +msgstr "Wiin oletus" + +msgid "TChinese" +msgstr "TKiina" + +msgid "TXT Cheatcodes Path" +msgstr "TXT koodien polku" + +msgid "The .them file was not found in the zip." +msgstr "" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "" + +msgid "Theme Downloader" +msgstr "" + +msgid "Theme Menu" +msgstr "" + +msgid "Theme Path" +msgstr "Teeman sijainti" + +msgid "Theme Title:" +msgstr "" + +msgid "Themes by www.spiffy360.com" +msgstr "" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "" + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "Aikaa jäljellä:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Nimilaukaisin" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "Vinkit" + +msgid "Transfer failed" +msgstr "" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX on suojattu." + +msgid "USB Port" +msgstr "" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "Poista" + +msgid "Uninstall Game" +msgstr "Poista peli" + +msgid "Uninstall Menu" +msgstr "Poistomenu" + +msgid "Uninstall all" +msgstr "" + +msgid "Unknown" +msgstr "" + +msgid "Unlock USB Loader GX" +msgstr "" + +msgid "Unlocked" +msgstr "Avattu" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "" + +msgid "Update" +msgstr "Päivitä" + +msgid "Update All" +msgstr "Päivitä kaikki" + +msgid "Update DOL" +msgstr "Päivitä DOL" + +msgid "Update Files" +msgstr "Päivitä tiedostot" + +msgid "Update Path" +msgstr "Päivityspolku" + +msgid "Update all Language Files" +msgstr "Päivitä kaikki kielitiedostot" + +msgid "Update failed" +msgstr "Päivitys epäonnistui" + +msgid "Update successfull" +msgstr "" + +msgid "Updating Language Files:" +msgstr "Päivittää kielitiedostoja:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "" + +msgid "Use System Font" +msgstr "" + +msgid "Use global" +msgstr "" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "VIDTV korjaus" + +msgid "Version:" +msgstr "" + +#, c-format +msgid "Version: %s" +msgstr "Versio: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Videotila" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "" + +msgid "WDM Files Path" +msgstr "" + +msgid "WIP Patches Path" +msgstr "" + +msgid "Waiting..." +msgstr "Odottaa..." + +msgid "Warning" +msgstr "" + +msgid "Warning:" +msgstr "" + +msgid "What do you want to do?" +msgstr "" + +msgid "What do you want to update?" +msgstr "Mitä haluat päivittää?" + +msgid "What should be deleted for this game title:" +msgstr "" + +msgid "What to extract from NAND?" +msgstr "" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "WiFi ominaisuudet" + +msgid "Widescreen Factor" +msgstr "" + +msgid "Widescreen Fix" +msgstr "Laajakuva korjaus" + +msgid "Wii Games" +msgstr "" + +msgid "Wii Menu" +msgstr "Wii Menu" + +msgid "Wii Settings" +msgstr "Wii asetukset" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "" + +msgid "Wiird Debugger" +msgstr "" + +#, c-format +msgid "Write error on file: %s" +msgstr "" + +msgid "Writing GXGameCategories.xml" +msgstr "" + +msgid "Wrong Password" +msgstr "Väärä salasana" + +msgid "Yes" +msgstr "Kyllä" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "" + +msgid "You cannot delete this category." +msgstr "" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "" + +msgid "available" +msgstr "Saatavilla" + +msgid "does not exist!" +msgstr "Ei löydy!" + +msgid "does not exist! Loading game without cheats." +msgstr "Ei löydy! Ladataan peli ilman koodeja." + +msgid "files left" +msgstr "Tiedostoja jäljellä" + +msgid "for FAT/NTFS support" +msgstr "" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "" + +msgid "for Ocarina" +msgstr "" + +msgid "for diverse patches" +msgstr "Erinäisistä patcheista" + +msgid "for his awesome tool LibWiiGui" +msgstr "Hänen hienosta ohjelmasta LibWiiGui" + +msgid "for hosting the themes" +msgstr "" + +msgid "for the USB Loader source" +msgstr "lähdekoodin julkaisemisesta" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "formatoitu!" + +msgid "free" +msgstr "vapaana" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "ei asetettu" + +msgid "of" +msgstr "josta" + +msgid "seconds left" +msgstr "sekuntia jäljellä" + +#~ msgid "Error 002 fix" +#~ msgstr "Virhe 002 fix" + +#~ msgid "Boot/Standard" +#~ msgstr "Käynnistys/Standardi" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "Uudelleennimeä peli" + +#~ msgid "for hosting the update files" +#~ msgstr "Tiedostojen hostauksesta" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Aseta Wii-levy!" + +#~ msgid "Not a Wii Disc" +#~ msgstr "Ei Wii-levy" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> Tuhotaan lipukkeita..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> Tuhotaan lipukkeita...VIRHE!" + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> Tuhotaan lipukkeita...Ok!" + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> Tuhotaan nimikettä...VIRHE!" + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> Tuhotaan nimikettä...Ok!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> Tuhotaan nimikkeen sisältöä..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> Tuhotaan nimikkeen sisältöä...VIRHE!" + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr "Tuhotaan nimikkeen sisältöä...Ok!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> Tuhotaan nimikettä..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> Viimeistellään asennusta..." + +#~ msgid ">> Installing content #" +#~ msgstr ">> Asennetaan sisältöä #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> Asennetaan lipuketta..." + +#~ msgid ">> Installing title..." +#~ msgstr ">> Asennetaan nimikettä..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> Luetaan WAD:ia..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> Luetaan WAD:ia...VIRHE!" + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> Luetaan WAD:ia...Ok!" + +#~ msgid "Done!" +#~ msgstr "Valmis!" + +#~ msgid "Error..." +#~ msgstr "Virhe..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "Viimeistelee asennusta... Ok!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "Asennetaan sisältöä... Ok!" + +#~ msgid "Installing wad" +#~ msgstr "Asennetaan wadia" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "Luetaan WAD:ia... Ok!" + +#~ msgid "Uninstalling wad" +#~ msgstr "Poistetaan wad:ia" + +#~ msgid "USB Device not found" +#~ msgstr "USB-laitetta ei löytynyt" + +#~ msgid "Language File" +#~ msgstr "KieliTiedosto" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Nimet WiiTDB:stä" + +#~ msgid "WiiTDB Files" +#~ msgstr "WiiTDB tiedostot" + +#~ msgid "WiiTDB Path" +#~ msgstr "WiiTDB polku" + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "WiiTDB:stä ja kansien hostauksesta" + +#~ msgid " Wad Saved as:" +#~ msgstr "Wad Tallennettu nimellä:" + +#~ msgid "Delete ?" +#~ msgstr "Tuhoa ?" + +#~ msgid "Keep" +#~ msgstr "Pidä" + +#~ msgid "Download Boxart image?" +#~ msgstr "Lataa kansikuva?" + +#~ msgid "Download Discart image?" +#~ msgstr "Lataa levykuva?" + +#~ msgid "Downloading file" +#~ msgstr "Lataa tiedostoa:" + +#~ msgid "Missing files" +#~ msgstr "tiedostoja puuttuu" + +#~ msgid "files not found on the server!" +#~ msgstr "tiedostoja ei löytynyt serveriltä!" + +#~ msgid "Disc Images" +#~ msgstr "Levykuvat" + +#~ msgid "Only Customs" +#~ msgstr "Vain omatekoiset" + +#~ msgid "Only Original" +#~ msgstr "Vain alkuperäinen" + +#~ msgid "Do you really want to delete:" +#~ msgstr "Haluatko varmasti formatoida:" + +#~ msgid "Do you want to use the alternate DOL that is known to be correct?" +#~ msgstr "Haluatko käyttää vaihtoehtoista DOL tiedostoa jonka tiedetään toimivan?" + +#~ msgid "Unlock console to use this option." +#~ msgstr "Avaa konsoli käyttääksesi tätä vaihtoehtoa" + +#~ msgid "Full Shutdown" +#~ msgstr "Täysi sammutus" + +#~ msgid "If you don't have WiFi, press 1 to get an URL to get your WiiTDB.zip" +#~ msgstr "Jos sinulla ei ole WiFi:ä, paina 1 saadaksesi URL josta voi ladata WiiTDB.zip" + +#~ msgid "Paste it into your browser to get your WiiTDB.zip." +#~ msgstr "Liitä se nettiselaimeesi saadaksesi WiiTDB.zip" + +#~ msgid "Shutdown to Idle" +#~ msgstr "Valmiustila" + +#~ msgid "Your URL has been saved in %sWiiTDB_URL.txt." +#~ msgstr "URL:si on tallennettu %WiiTDB_URL.txt." + +#~ msgid "Insert an SD-Card to save." +#~ msgstr "Aseta SD-kortti tallentaaksesi asetuksia." + +#~ msgid "Insert an SD-Card to use this option." +#~ msgstr "Aseta SD-kortti käyttääksesi tätä vaihtoehtoa" + +#~ msgid "No SD-Card inserted!" +#~ msgstr "SD-korttia ei ole asetettu wiihin!" + +#~ msgid "Waiting for USB Device" +#~ msgstr "Odottaa USB-laitetta..." + +#~ msgid "Back to Loader" +#~ msgstr "HBC" + +#~ msgid "An Error occured" +#~ msgstr "Tapahtui virhe" + +#~ msgid "Checking for Updates" +#~ msgstr "Tarkastetaan päivityksiä" + +#~ msgid "Downloading" +#~ msgstr "Lataa" + +#~ msgid "The wad file was installed. But It could not be deleted from the SD card." +#~ msgstr "Wad tiedostoa ei asennettu mutta sitä ei voitu tuhota SD-kortilta" + +#~ msgid "The wad installation failed with error %ld" +#~ msgstr "Wad asennus epäonnistui: %ld" + +#~ msgid "Unable to open the wad that was just downloaded (%s)." +#~ msgstr "Wadia (%s) jonka juuri latasit ei voitu avata." + +#~ msgid "Update to" +#~ msgstr "Päivitä:" + +#~ msgid "Updating" +#~ msgstr "Päivittää" + +#~ msgid "Updating Language Files..." +#~ msgstr "Päivittää kielitiedostoja..." + +#~ msgid "Updating WiiTDB.zip" +#~ msgstr "Päivittää WiiTDB.zip" + +#~ msgid "Back to Wii Menu" +#~ msgstr "Takaisin Wii Menuun" + +#~ msgid "Checking existing artwork" +#~ msgstr "Tutkitaan olemassa olevia kansia" + +#~ msgid "Confirm" +#~ msgstr "Varmista" + +#~ msgid "Could not find a WBFS partition." +#~ msgstr "WBFS osiota ei löytynyt." + +#~ msgid "Could not open WBFS partition" +#~ msgstr "WBFS osiota ei voitu avata" + +#~ msgid "Could not read the disc." +#~ msgstr "Levyä ei voitu lukea" + +#~ msgid "Could not set USB." +#~ msgstr "USB:tä ei voitu asettaa" + +#~ msgid "Cover Path Changed" +#~ msgstr "Kansien polku muutettu" + +#~ msgid "DOL path changed" +#~ msgstr "DOL:in polku muutettu" + +#~ msgid "Disc Path Changed" +#~ msgstr "Levykuvien polku muutettu" + +#~ msgid "Display favorites" +#~ msgstr "Näytä suosikit" + +#~ msgid "Do you want to retry for 30 secs?" +#~ msgstr "Haluatko odottaa 30 sekuntia?" + +#~ msgid "Force" +#~ msgstr "Pakota" + +#~ msgid "GCT Cheatcodes Path changed" +#~ msgstr "GCT Koodien polku muutettu" + +#~ msgid "Homebrew Appspath changed" +#~ msgstr "Homebrew Apps polku vaihdettu" + +#~ msgid "Insert an SD-Card to download images." +#~ msgstr "Aseta SD-kortti ladataksesi kansia." + +#~ msgid "Most likely it has dimensions that are not evenly divisible by 4." +#~ msgstr "Todennäköisesti sisältää ulottuvuuksia jotka eivät ole jaollisia neljällä" + +#~ msgid "Network init error" +#~ msgstr "Verkon alustusvirhe" + +#~ msgid "No .dol or .elf files found." +#~ msgstr ".dol tai .elf tiedostoja ei löydy" + +#~ msgid "No Favorites" +#~ msgstr "Ei suosikkeja" + +#~ msgid "No USB Device" +#~ msgstr "Ei USB-laitetta" + +#~ msgid "No USB Device found." +#~ msgstr "USB-laitetta ei löytynyt." + +#~ msgid "Normal Covers" +#~ msgstr "Normaalit kannet" + +#~ msgid "Not Found" +#~ msgstr "Ei löytynyt" + +#~ msgid "Not a DOL/ELF file." +#~ msgstr "Tiedosto ei ole DOL/ELF." + +#~ msgid "Save Failed" +#~ msgstr "Tallennus ei onnistunut" + +#~ msgid "Selected DOL" +#~ msgstr "Valittu DOL" + +#~ msgid "Standard" +#~ msgstr "Standardi" + +#~ msgid "TXT Cheatcodes Path changed" +#~ msgstr "TXT koodien polku muutettu" + +#~ msgid "Theme Path Changed" +#~ msgstr "Teeman sijainti muutettu" + +#~ msgid "Update Path changed." +#~ msgstr "Päivityspolku muutettu" + +#~ msgid "WiiTDB Path changed." +#~ msgstr "WiiTDB polku muutettu" + +#~ msgid "You are about to delete " +#~ msgstr "Olet tuhoamassa " + +#~ msgid "You are choosing to display favorites and you do not have any selected." +#~ msgstr "Olet valinnut näyttääksesi suosikit mutta sinulla ei ole valittuna yhtään." + +#~ msgid "You have attempted to load a bad image" +#~ msgstr "Yritit ladata huonoa levykuvaa" + +#~ msgid "does not exist! You Messed something up, Idiot." +#~ msgstr "Ei löydy! Kusit jotain, Typerys!" + +#~ msgid "file left" +#~ msgstr "Tiedosto jäljellä" diff --git a/Languages/french.lang b/Languages/french.lang new file mode 100644 index 0000000..ab0f09b --- /dev/null +++ b/Languages/french.lang @@ -0,0 +1,2820 @@ +# USB Loader GX language source file. +# French.lang - r1272 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:02+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: Cyan\n" +"Language-Team: Badablek, Amour, ikya, Cyan & Kin8\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " ne peut pas être téléchargé." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " sauvegardé. Certains codes ne peuvent fonctionner conjointement. En cas de mauvais résultats, ouvrez-le avec un éditeur de texte pour obtenir plus d'informations." + +msgid " is not on the server." +msgstr " indisponible sur le serveur." + +#, c-format +msgid "%i files not found on the server!" +msgstr "%i fichier(s) introuvable(s) sur le serveur !" + +#, c-format +msgid "%i missing files" +msgstr "%i fichier(s) manquant(s)" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "%i fichier(s) wad non traité(s)!" + +#, c-format +msgid "%i wad found." +msgstr "%i wad trouvé(s)." + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "%s n'accepte que les jeux GameCube au format ISO." + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "%s nécessite l'accès AHB ! Veuillez lancer USBLoaderGX à partir du HBC ou mettre à jour votre chaîne." + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Tous 3+)" + +msgid "1 (Child 7+)" +msgstr "1 (Enfants 7+)" + +msgid "1 hour" +msgstr "1 heure" + +msgid "10 min" +msgstr "10 min." + +msgid "2 (Teen 12+)" +msgstr "2 (Adolescents 12+)" + +msgid "20 min" +msgstr "20 min." + +msgid "2D Cover Path" +msgstr "Dossier jaquettes 2D" + +msgid "3 (Mature 16+)" +msgstr "3 (Matures 16+)" + +msgid "3 min" +msgstr "3 min." + +msgid "30 min" +msgstr "30 min." + +msgid "3D Cover Path" +msgstr "Dossier jaquettes 3D" + +msgid "3D Covers" +msgstr "Jaquettes 3D" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Adultes 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 min." + +msgid "=== GameCube Settings" +msgstr "===== Param. GameCube" + +msgid "AUTO" +msgstr "" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "Nouv. catégorie" + +msgid "Adjust Overscan X" +msgstr "Ajuster l'overscan X" + +msgid "Adjust Overscan Y" +msgstr "Ajuster l'overscan Y" + +msgid "After zoom" +msgstr "Après le zoom" + +msgid "All" +msgstr "Toutes" + +msgid "All Partitions" +msgstr "Toutes les partitions" + +msgid "All files extracted." +msgstr "Extraction des fichiers terminée." + +msgid "All images downloaded successfully." +msgstr "Images correctement téléchargées" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Toutes les fonctionnalités sont déverrouillées." + +msgid "All wad files processed successfully." +msgstr "Tous les fichiers wad ont été traités avec succès." + +msgid "Alternate DOL" +msgstr "DOL alternatif" + +msgid "An example file was created here:" +msgstr "Un fichier d'exemple a été créé ici :" + +msgid "Animation Start" +msgstr "Démarrer l'animation" + +msgid "App Language" +msgstr "Langue d'interface" + +msgid "Apply" +msgstr "Appliquer" + +msgid "Apr" +msgstr "Avr" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "Voulez-vous vraiment supprimer tous les jeux sélectionnés de la carte SD ?" + +msgid "Are you sure you want to delete this category?" +msgstr "Voulez-vous vraiment supprimer cette catégorie ?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "Voulez-vous vraiment importer les catégories de jeux à partir de WiiTDB.xml ?" + +msgid "Are you sure you want to install on SD?" +msgstr "Voulez-vous vraiment installer sur SD ?" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "Voulez-vous vraiment verrouiller USB loader GX ?" + +msgid "Are you sure you want to remount SD?" +msgstr "Voulez-vous recharger la carte SD ?" + +msgid "Are you sure you want to reset?" +msgstr "Voulez-vous vraiment réinitialiser ?" + +msgid "Are you sure?" +msgstr "Êtes-vous sûr ?" + +msgid "Aspect Ratio" +msgstr "Format d'image" + +msgid "Attention!" +msgstr "Attention !" + +msgid "Attention: All savegames will be deleted." +msgstr "Attention : Toutes les sauvegardes seront supprimées." + +msgid "Aug" +msgstr "Août" + +msgid "Author(s):" +msgstr "Auteur(s):" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "Démarrage automatique" + +msgid "AutoInit Network" +msgstr "Connexion réseau automatique" + +msgid "BCA Codes Path" +msgstr "Dossier codes BCA" + +msgid "Back" +msgstr "Retour" + +msgid "Back to HBC or Wii Menu" +msgstr "Retour HBC / Menu Wii" + +msgid "Backgroundmusic" +msgstr "Fond sonore" + +msgid "Banner Animation" +msgstr "Bannière animée" + +msgid "Banner Animation Settings" +msgstr "Paramètres des Bannières" + +msgid "Banner On Channels" +msgstr "Bannière sur Chaînes" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "Le mode Chaînes nécessite AHBPROT! Pensez à mettre à jour votre Homebrew Channel." + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "L'affichage des bannières nécessite AHBPROT! Pensez à mettre à jour votre Homebrew Channel." + +msgid "Big thanks to:" +msgstr "Grand merci à:" + +msgid "Block Categories Menu" +msgstr "Bloquer Menu catégories" + +msgid "Block Categories Modify" +msgstr "Bloquer Modif. catégories" + +msgid "Block Cover Downloads" +msgstr "Bloquer Téléch. jaquettes" + +msgid "Block Custom Paths" +msgstr "Bloquer Person. dossiers" + +msgid "Block Feature Settings" +msgstr "Bloquer Fonctionnalités" + +msgid "Block Game Install" +msgstr "Bloquer Installation jeu" + +msgid "Block Game Settings" +msgstr "Bloquer Paramètres jeu" + +msgid "Block GameID Change" +msgstr "Bloquer Modif. IDJEU" + +msgid "Block Global Settings" +msgstr "Bloquer Paramètres" + +msgid "Block Gui Settings" +msgstr "Bloquer Config. GUI" + +msgid "Block HBC Menu" +msgstr "Bloquer Menu HBC" + +msgid "Block Hard Drive Settings" +msgstr "Bloquer Param. Disques durs" + +msgid "Block IOS Reload" +msgstr "Bloquer IOS reload" + +msgid "Block Loader Layout Button" +msgstr "Bloquer Chang. d'interface" + +msgid "Block Loader Mode Button" +msgstr "Bloquer Mode du Loader" + +msgid "Block Loader Settings" +msgstr "Bloquer Param. du Loader" + +msgid "Block Parental Settings" +msgstr "Bloquer Contrôle parental" + +msgid "Block Priiloader Override" +msgstr "Annuler contournement Priiloader" + +msgid "Block Reset Settings" +msgstr "Bloquer Réinit. paramètres" + +msgid "Block SD Reload Button" +msgstr "Bloquer Bouton recharge SD" + +msgid "Block Sound Settings" +msgstr "Bloquer Sons" + +msgid "Block Theme Downloader" +msgstr "Bloquer Téléch. thèmes" + +msgid "Block Theme Menu" +msgstr "Bloquer Thèmes" + +msgid "Block Title Launcher" +msgstr "Bloquer Menu Chaînes" + +msgid "Block Updates" +msgstr "Bloquer Mise à jour" + +msgid "Boot Content" +msgstr "Lancement normal" + +msgid "Boot Neek System Menu" +msgstr "Démarrer le Menu système Neek" + +msgid "Boot?" +msgstr "Lancer ?" + +msgid "Both" +msgstr "Les deux" + +msgid "Both Ports" +msgstr "Les deux ports" + +msgid "CC Rumble" +msgstr "Vibration manette cl." + +msgid "Cache BNR Files" +msgstr "Fichiers BNR en cache" + +msgid "Cache BNR Files Path" +msgstr "Dossier de cache BNR" + +msgid "Cache Titles" +msgstr "Titres en cache" + +msgid "Can't be formatted" +msgstr "Formatage impossible" + +msgid "Can't create directory" +msgstr "Création du répertoire impossible" + +#, c-format +msgid "Can't create file: %s" +msgstr "Impossible de créer le fichier: %s" + +#, c-format +msgid "Can't create path: %s" +msgstr "Impossible de créer: %s" + +msgid "Can't delete:" +msgstr "Impossible de supprimer:" + +msgid "Can't mount or unknown disc format." +msgstr "Impossible de lire le format du disque." + +#, c-format +msgid "Can't open file for write: %s" +msgstr "Impossible d'ouvrir le fichier en mode écriture: %s" + +#, c-format +msgid "Can't open file: %s" +msgstr "Impossible d'ouvrir le fichier: %s" + +#, c-format +msgid "Can't read file: %s" +msgstr "Impossible de lire le fichier: %s" + +msgid "Cancel" +msgstr "Annuler" + +msgid "Cannot write to destination." +msgstr "Écriture impossible." + +msgid "Categories" +msgstr "Catégories" + +msgid "Categories:" +msgstr "Catégories:" + +msgid "Change Play Path" +msgstr "Changer dossier" + +msgid "Channel Launcher" +msgstr "Lancement des Chaînes" + +msgid "Channels" +msgstr "Chaînes" + +msgid "Cheatfile is blank" +msgstr "Fichier de triche vide" + +msgid "Clear" +msgstr "Effacer" + +msgid "Click to Download Covers" +msgstr "Téléchargement des jaquettes" + +msgid "Click to change game ID" +msgstr "Changer l'ID du jeu" + +msgid "Clock" +msgstr "Horloge" + +msgid "Clock Scale Factor" +msgstr "Échelle de l'horloge" + +msgid "Close" +msgstr "Fermer" + +msgid "Code Download" +msgstr "Téléchargement des codes" + +#, c-format +msgid "Coded by: %s" +msgstr "Développé par: %s" + +msgid "Coding:" +msgstr "Développement:" + +msgid "Connection to server timed out." +msgstr "Temps limite de connexion au serveur dépassé." + +msgid "Console" +msgstr "" + +msgid "Console Default" +msgstr "Console par défaut" + +msgid "Console Locked" +msgstr "Console verrouillée" + +msgid "Console must be unlocked for this option." +msgstr "La console doit être déverrouillée." + +msgid "Console must be unlocked to be able to use this." +msgstr "La console doit être déverrouillée." + +msgid "Console should be unlocked to modify it." +msgstr "La console doit être déverrouillée." + +msgid "Continue" +msgstr "Continuer" + +msgid "Continue to install game?" +msgstr "Continuer l'installation ?" + +msgid "Continue?" +msgstr "Continuer ?" + +msgid "Controllevel" +msgstr "Niveau moral" + +msgid "Copy" +msgstr "Copier" + +msgid "Copying Canceled" +msgstr "Copie annulée" + +msgid "Copying GC game..." +msgstr "Copie du jeu GameCube..." + +msgid "Copying files..." +msgstr "Copie du fichier..." + +msgid "Correct Password" +msgstr "Mot de passe accepté" + +msgid "Could not connect to the server." +msgstr "Connexion au serveur impossible" + +msgid "Could not create GCT file" +msgstr "Impossible de créer le fichier GCT" + +#, c-format +msgid "Could not create path: %s" +msgstr "Impossible de créer: %s" + +msgid "Could not extract files for:" +msgstr "L'extraction des fichiers a échoué pour :" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "Pas d'information pour ce jeu dans wiitdb.xml." + +msgid "Could not get free device space for game." +msgstr "Pas assez d'espace libre pour le jeu." + +msgid "Could not initialize DIP module!" +msgstr "Initialisation du module DIP impossible !" + +msgid "Could not initialize network!" +msgstr "Initialisation réseau impossible !" + +msgid "Could not initialize network, time out!" +msgstr "Initialisation réseau impossible, délai dépassé !" + +msgid "Could not open Disc" +msgstr "l'ouverture du DVD à échouée." + +msgid "Could not open the WiiTDB.xml file." +msgstr "Impossible d'ouvrir wiitdb.xml." + +msgid "Could not open wiitdb.xml." +msgstr "Impossible d'ouvrir wiitdb.xml." + +msgid "Could not save." +msgstr "Sauvegarde impossible." + +msgid "Could not write file." +msgstr "Écriture du fichier impossible." + +msgid "Could not write to:" +msgstr "Écriture impossible vers:" + +msgid "Cover Download" +msgstr "Téléchargement des jaquettes" + +msgid "Create" +msgstr "Créer" + +msgid "Credits" +msgstr "Crédits" + +msgid "Crop Overscan" +msgstr "Réduire l'overscan" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "Le fichier neek actuel n'est pas neek2o. Démarrage automatique désactivé." + +msgid "Custom Banners" +msgstr "Bannières persos" + +msgid "Custom Paths" +msgstr "Personnalisation des dossiers" + +msgid "Customs" +msgstr "Persos" + +msgid "Customs/Original" +msgstr "Persos/Originaux" + +msgid "D Buttons" +msgstr "Boutons directs" + +msgid "DOL Path" +msgstr "Dossier DOL alternatif" + +msgid "Debug" +msgstr "Débug" + +msgid "Debug Wait" +msgstr "Actif (en mode pause)" + +msgid "Debugger Paused Start" +msgstr "Démarrer WiiRd en pause" + +msgid "Dec" +msgstr "Déc" + +msgid "Default" +msgstr "Par défaut" + +msgid "Default Gamesettings" +msgstr "Réinitialiser les paramètres du jeu" + +msgid "Default Settings" +msgstr "Réinitialiser les paramètres" + +msgid "Delete" +msgstr "Supprimer" + +msgid "Delete Cached Banner" +msgstr "Supprimer bannière en cache" + +msgid "Delete Cheat GCT" +msgstr "Supprimer GCT de triche" + +msgid "Delete Cheat TXT" +msgstr "Supprimer TXT de triche" + +msgid "Delete Cover Artwork" +msgstr "Supprimer la jaquette" + +msgid "Delete Disc Artwork" +msgstr "Supprimer le label DVD" + +msgid "Delete category" +msgstr "Suppr. catégorie" + +msgid "Deleting directories..." +msgstr "Suppression du dossier...." + +msgid "Deleting files..." +msgstr "Suppression du fichier..." + +msgid "Design:" +msgstr "Graphisme:" + +msgid "Details" +msgstr "Détails" + +msgid "Developed by" +msgstr "Développé par" + +msgid "Developer:" +msgstr "Développeur:" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "Dossier Loader Devolution" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "Le fichier loader.bin de Devolution n'a pu être chargé." + +msgid "Directory does not exist!" +msgstr "Répertoire inexistant!" + +msgid "Disc 1" +msgstr "Disque 1" + +msgid "Disc 2" +msgstr "Disque 2" + +msgid "Disc Artwork Download" +msgstr "Téléch. des labels DVD" + +msgid "Disc Artwork Path" +msgstr "Dossier labels DVD" + +msgid "Disc Default" +msgstr "Disque par défaut" + +msgid "Disc Insert Detected" +msgstr "Insertion de disque détectée" + +msgid "Disc Read Delay" +msgstr "Temporiser l'accès disque" + +msgid "Disc read error." +msgstr "Erreur de lecture du disque." + +msgid "Disc-Select Prompt" +msgstr "Demander choix du disque" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "Le disque 2 doit être installé dans un format non compressé pour fonctionner avec DM(L) v2.6+, voulez-vous vraiment l'installer compressé ?" + +msgid "Discarts" +msgstr "Labels DVD" + +msgid "DiskFlip" +msgstr "Disque uniquement" + +msgid "Display" +msgstr "Affichage" + +msgid "Display as a carousel" +msgstr "Carrousel" + +msgid "Display as a channel grid" +msgstr "Chaînes" + +msgid "Display as a grid" +msgstr "Grille" + +msgid "Display as a list" +msgstr "Liste" + +msgid "Display favorites only" +msgstr "Seulement les favoris" + +msgid "Do you want to apply it now?" +msgstr "L'appliquer maintenant ?" + +msgid "Do you want to apply this theme?" +msgstr "Voulez-vous appliquer ce thème ?" + +msgid "Do you want to change language?" +msgstr "Changer de langue ?" + +msgid "Do you want to continue with next game?" +msgstr "Voulez-vous continuer avec le jeu suivant ?" + +msgid "Do you want to copy now?" +msgstr "Voulez-vous copier maintenant ?" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "Vous devez copier le jeu sur la carte SD." + +msgid "Do you want to delete a game on SD?" +msgstr "Voulez-vous supprimer un jeu de la carte SD ?" + +msgid "Do you want to discard changes?" +msgstr "Voulez-vous annuler les changements ?" + +msgid "Do you want to download this theme?" +msgstr "Voulez-vous télécharger ce thème ?" + +msgid "Do you want to extract all the save games?" +msgstr "Extraire toutes les sauvegardes ?" + +msgid "Do you want to extract the save game?" +msgstr "Voulez-vous extraire la sauvegarde ?" + +msgid "Do you want to format:" +msgstr "Voulez-vous formater:" + +msgid "Do you want to install selected games?" +msgstr "Voulez-vous installer les jeux sélectionnés ?" + +msgid "Do you want to load the default theme?" +msgstr "Voulez-vous charger le thème par défaut ?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "Voulez-vous déplacer le(s) fichier(s) ? Tout fichier existant sera supprimé !" + +msgid "Do you want to re-init network?" +msgstr "Voulez-vous réinitialiser la connexion ?" + +msgid "Do you want to start the game now?" +msgstr "Voulez-vous démarrer le jeu maintenant ?" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "Voulez-vous synchroniser l'information d'espace libre disponible sur toutes les partitions FAT32 ?" + +msgid "Do you wish to update/download all language files?" +msgstr "Voulez-vous actualiser/télécharger tous les fichiers langue ?" + +msgid "Dol Video Patch" +msgstr "Patch vidéo Dol" + +msgid "Download" +msgstr "Télécharger" + +msgid "Download Now" +msgstr "Télécharger" + +msgid "Download finished" +msgstr "Téléchargement terminé" + +msgid "Downloading 3D Covers" +msgstr "Téléchargement des jaquettes 3D" + +msgid "Downloading Custom Banners" +msgstr "Téléch. des bannières persos" + +msgid "Downloading Flat Covers" +msgstr "Téléchargement des jaquettes 2D" + +msgid "Downloading Full HQ Covers" +msgstr "Téléch. des jaquettes complètes HD" + +msgid "Downloading Full LQ Covers" +msgstr "Téléch. des jaquettes complètes SD" + +msgid "Downloading custom Discarts" +msgstr "Téléch. des labels DVD persos" + +msgid "Downloading file..." +msgstr "Téléchargement du fichier..." + +msgid "Downloading image:" +msgstr "Téléchargement de l'image:" + +msgid "Downloading original Discarts" +msgstr "Téléch. des labels DVD originaux" + +msgid "Downloading pagelist:" +msgstr "Téléch. liste des thèmes :" + +msgid "Dump NAND to EmuNand" +msgstr "Extraire NAND vers ÉmuNand" + +msgid "During zoom" +msgstr "Pendant le zoom" + +msgid "Dutch" +msgstr "Néerlandais" + +msgid "ERROR" +msgstr "ERREUR" + +msgid "ERROR:" +msgstr "ERREUR:" + +msgid "ERROR: Can't set up theme." +msgstr "ERREUR: Configuration thème impossible." + +msgid "EmuNAND Wad Manager" +msgstr "ÉmuNand Wad Manager" + +msgid "EmuNand Channels" +msgstr "Chaînes sur ÉmuNand" + +msgid "Emulated Nand" +msgstr "Nand émulée" + +msgid "English" +msgstr "Anglais" + +msgid "Enter Path" +msgstr "Entrer un chemin" + +msgid "Error" +msgstr "Erreur" + +msgid "Error !" +msgstr "Erreur !" + +#, c-format +msgid "Error creating path: %s" +msgstr "Erreur lors de la création du chemin: %s" + +msgid "Error opening downloaded file" +msgstr "Erreur à l'ouverture du fichier téléchargé" + +msgid "Error reading Disc" +msgstr "Erreur à la lecture du disque" + +msgid "Error reading disc" +msgstr "Erreur à la lecture du disque" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "Erreur lors du téléchargement de: %i" + +msgid "Error while downloding file" +msgstr "Erreur lors du téléchargement du fichier" + +msgid "Error while opening the zip." +msgstr "Erreur à l'ouverture du fichier zip." + +msgid "Error while transfering data." +msgstr "Erreur durant le transfert de données." + +msgid "Error while updating USB Loader GX." +msgstr "Erreur lors de la MàJ de USB Loader GX." + +msgid "Error writing the data." +msgstr "Erreur d'écriture des données" + +msgid "Error:" +msgstr "Erreur:" + +msgid "Error: Not enough space on SD." +msgstr "Erreur: Espace insuffisant sur la carte SD." + +msgid "Errors occured." +msgstr "Des erreurs sont survenues." + +msgid "Everything" +msgstr "Tout" + +msgid "Exit" +msgstr "Quitter" + +msgid "Exit to where?" +msgstr "Quitter vers où ?" + +msgid "Export All Saves to EmuNand" +msgstr "Extraire toutes les sauvegardes" + +msgid "Export Miis to EmuNand" +msgstr "Extraire les Miis vers ÉmuNand" + +msgid "Export SYSCONF to EmuNand" +msgstr "Extraire SYSCONF vers ÉmuNand" + +msgid "Extract Miis to the Emu NAND?" +msgstr "Extraire les Miis vers ÉmuNand ?" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "Extraire SYSCONF vers ÉmuNand ?" + +msgid "Extract Save to EmuNand" +msgstr "Extraire la sauvegarde vers Émulation Nand" + +msgid "Extracting file:" +msgstr "Extraction du fichier :" + +msgid "Extracting files..." +msgstr "Extraction des fichiers..." + +msgid "Extracting files:" +msgstr "Extraction des fichiers :" + +msgid "Extracting nand files:" +msgstr "Extraction du fichier Nand :" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "Échec" + +msgid "Failed copying file" +msgstr "Échec lors de la copie du fichier" + +msgid "Failed formating" +msgstr "Échec du formatage" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "Échec lors de l'extraction des fichiers. La sauvegarde est peut-être inexistante." + +msgid "Failed to extract." +msgstr "Échec de l'extraction" + +msgid "Failed to initialize the USB storage device." +msgstr "Échec de l'initialisation du périphérique USB." + +msgid "Failed to open partition" +msgstr "Échec accès partition" + +msgid "Failed to read ticket." +msgstr "Échec de lecture du ticket." + +msgid "Failed to read tmd file." +msgstr "Échec de lecture du fichier tmd." + +msgid "Failed to read wad header." +msgstr "Échec de lecture de l'entête wad." + +msgid "Failed updating" +msgstr "Échec de la mise à jour" + +msgid "Favorite Level" +msgstr "Niveau de favoris" + +msgid "Features" +msgstr "Fonctionnalités" + +msgid "Features Settings" +msgstr "Fonctionnalités" + +msgid "Feb" +msgstr "Fév" + +msgid "File" +msgstr "Fichier" + +msgid "File not found." +msgstr "Fichier introuvable." + +msgid "File read/write error." +msgstr "Erreur de lecture/écriture du fichier." + +msgid "Files extracted successfully." +msgstr "Fichiers extraits avec succès." + +#, c-format +msgid "Filesize is %i Byte." +msgstr "Taille du ficher: %i Octets." + +msgid "Filesize is 0 Byte." +msgstr "Fichier de taille 0 Octet." + +msgid "Flat Covers" +msgstr "Jaquettes 2D" + +msgid "Flip-X" +msgstr "Anim. jeu suivant" + +msgid "Folder" +msgstr "Dossier" + +msgid "Font Scale Factor" +msgstr "Échelle de la police" + +msgid "Force 16:9" +msgstr "Forcer 16:9" + +msgid "Force 4:3" +msgstr "Forcer 4:3" + +msgid "Force NTSC" +msgstr "Forcer NTSC" + +msgid "Force NTSC480p" +msgstr "Forcer NTSC480p" + +msgid "Force PAL480p" +msgstr "Forcer PAL480p" + +msgid "Force PAL50" +msgstr "Forcer PAL50" + +msgid "Force PAL60" +msgstr "Forcer PAL60" + +msgid "Force Titles from Disc" +msgstr "Forcer charg. titres du disque" + +msgid "Force Widescreen" +msgstr "Forcer 16:9" + +msgid "Format" +msgstr "Formater" + +msgid "Formatting, please wait..." +msgstr "Formatage en cours, veuillez patienter..." + +msgid "Found missing images." +msgstr "Images manquantes trouvées." + +msgid "Frame" +msgstr "image" + +msgid "Frame Projection Height" +msgstr "Projection image Hauteur" + +msgid "Frame Projection Width" +msgstr "Projection image Largeur" + +msgid "Frame Projection X-Offset" +msgstr "Projection image pos. X" + +msgid "Frame Projection Y-Offset" +msgstr "Projection image pos. Y" + +msgid "Frames" +msgstr "images" + +msgid "Free Space" +msgstr "Espace libre" + +msgid "French" +msgstr "Français" + +msgid "Full" +msgstr "Complète" + +msgid "Full Cover Path" +msgstr "Dossier jaqu. complètes" + +msgid "Full Covers" +msgstr "Jaquettes complètes" + +msgid "Full Menu" +msgstr "Menu complet" + +msgid "Full covers Download" +msgstr "Téléch. Jaqu. complètes" + +msgid "Full shutdown" +msgstr "Éteindre" + +msgid "GAMEID_Gamename" +msgstr "IDJEU_NomJeu" + +msgid "GC Banner Scale" +msgstr "Échelle des bannières GC" + +msgid "GC Games" +msgstr "Jeux GameCube" + +msgid "GC Install 32K Aligned" +msgstr "Instal. jeux GC alignés 32K" + +msgid "GC Install Compressed" +msgstr "Instal. jeux GC compressés" + +msgid "GCT Cheatcodes Path" +msgstr "Dossier GCT de triches" + +msgid "GCT File created" +msgstr "Fichier GCT créé" + +msgid "GUI Settings" +msgstr "Configuration GUI" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "Menu de suppression GameCube" + +msgid "Game Cube Install Menu" +msgstr "Menu d'installation GameCube" + +msgid "Game ID" +msgstr "ID du jeu" + +msgid "Game IOS" +msgstr "IOS du jeu" + +msgid "Game Language" +msgstr "Langue du jeu" + +msgid "Game Load" +msgstr "Paramètres du jeu" + +msgid "Game Lock" +msgstr "Verrouiller le jeu" + +msgid "Game Only" +msgstr "Seulement le jeu" + +msgid "Game Region" +msgstr "Région" + +msgid "Game Size" +msgstr "Taille du jeu" + +msgid "Game Sound Mode" +msgstr "Mode d'intro des jeux" + +msgid "Game Sound Volume" +msgstr "Volume des intros" + +msgid "Game Split Size" +msgstr "Découpage des jeux" + +msgid "Game Window Mode" +msgstr "Type de fenêtre de jeu" + +msgid "Game is already installed:" +msgstr "Le jeu est déjà installé:" + +msgid "Game's IOS" +msgstr "IOS des jeux" + +msgid "Game/Install Partition" +msgstr "Partition jeu/install." + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "Manette GameCube" + +msgid "GameCube Mode" +msgstr "Mode GameCube" + +msgid "GameCube Source" +msgstr "Source GameCube" + +msgid "Gamename [GAMEID]" +msgstr "NomJeu [IDJEU]" + +msgid "Games" +msgstr "Jeux" + +msgid "Generating GXGameCategories.xml" +msgstr "Génération GXGameCategories.xml" + +msgid "Genre:" +msgstr "" + +msgid "German" +msgstr "Allemand" + +msgid "Getting file list..." +msgstr "Lecture de la liste des fichiers..." + +msgid "Getting game folder size..." +msgstr "Calcul de la taille du dossier de jeu..." + +msgid "Global Settings" +msgstr "Paramètres" + +msgid "Grid Scroll Speed" +msgstr "Vitesse chang. pages" + +msgid "HOME Menu" +msgstr "Menu HOME" + +msgid "Hard Drive Settings" +msgstr "Paramètres des Disques durs" + +msgid "High Quality" +msgstr "Hautes qualités" + +msgid "High/Low" +msgstr "Hautes/Basses" + +msgid "Homebrew Apps Path" +msgstr "Dossier Apps Homebrew" + +msgid "Homebrew Channel" +msgstr "Chaîne Homebrew" + +msgid "Homebrew Launcher" +msgstr "Menu Homebrew" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "heures" + +msgid "How do you want to update?" +msgstr "Comment effectuer la mise à jour ?" + +msgid "How to Shutdown?" +msgstr "Arrêt de la Wii ?" + +msgid "Import Categories" +msgstr "Importer les catégories" + +msgid "Import operation successfully completed." +msgstr "Catégories importées avec succès." + +msgid "Importing categories" +msgstr "Import des catégories..." + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Fichier entrant %0.2fKo" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Fichier entrant %0.2fMo" + +msgid "Individual" +msgstr "Individuelle" + +msgid "Initializing Network" +msgstr "Initialisation du réseau" + +msgid "Insert Disk" +msgstr "Insérez un disque" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "Insérez un disque Wii ou GameCube !" + +msgid "Install" +msgstr "Installer" + +msgid "Install Canceled" +msgstr "Installation annulée" + +msgid "Install Directories" +msgstr "Dossiers d'installation" + +msgid "Install Error!" +msgstr "Erreur à l'installation !" + +msgid "Install Partitions" +msgstr "Partitions jeu Wii à installer" + +msgid "Install a game" +msgstr "Installer un jeu" + +msgid "Install error - Cleaning incomplete data." +msgstr "Erreur lors de l'installation ! Suppression des données incomplètes." + +msgid "Install finished" +msgstr "Installation terminée" + +msgid "Installing Game Cube Game..." +msgstr "Installation du jeu GameCube..." + +msgid "Installing content" +msgstr "Installation du contenu" + +msgid "Installing game:" +msgstr "Installation du jeu:" + +msgid "Installing title..." +msgstr "Installation du titre..." + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "Numéro d'IOS non valide. Le numéro doit être -1 pour l'IOS par défaut ou compris entre 200 et 255" + +msgid "Invalid wad file." +msgstr "Fichier wad non valide." + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "SVP, faîtes passer cette information qui serait très utile à la Team USB Loader GX." + +msgid "Italian" +msgstr "Italien" + +msgid "Jan" +msgstr "" + +msgid "Japanese" +msgstr "Japonais" + +msgid "Japanese Patch" +msgstr "Patch japonais" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "Juil" + +msgid "June" +msgstr "Juin" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Clavier" + +msgid "Korean" +msgstr "Coréen" + +msgid "LED Activity" +msgstr "LED détection d'activité" + +msgid "Language Files" +msgstr "Fichiers de langue" + +msgid "Language change:" +msgstr "Changement de langue:" + +msgid "Languagefiles Path" +msgstr "Dossier langue" + +msgid "Languagepath changed." +msgstr "Dossier langue changé" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Le lancement des jeux Wii avec ÉmuNand ne fonctionne qu'avec un cIOS d2x! Modifiez l'IOS dans les paramètres de ce jeu." + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Le lancement de chaînes sur ÉmuNand ne fonctionne qu'avec un cIOS d2x! Modifiez l'IOS dans les paramètres de ce jeu." + +msgid "Left" +msgstr "Gauche" + +msgid "Like SysMenu" +msgstr "Menu système" + +msgid "List on Gamelaunch" +msgstr "Proposer au démarrage" + +msgid "Load" +msgstr "Charger" + +msgid "Load From SD/USB" +msgstr "Charger depuis SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Charger le fichier de: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Charger comme DOL alternatif ?" + +msgid "Loader Settings" +msgstr "Paramètres du Loader" + +msgid "Loader's IOS" +msgstr "IOS du Loader" + +msgid "Loading standard language." +msgstr "Chargement langue par défaut." + +msgid "Loading standard music." +msgstr "Chargement musique standard." + +msgid "Lock Console" +msgstr "Verrouiller la console" + +msgid "Lock USB Loader GX" +msgstr "Verrouiller USB Loader GX" + +msgid "Locked" +msgstr "Clic pour déverrouiller" + +msgid "Log to file" +msgstr "Fichier de logs" + +msgid "Loop Directory" +msgstr "Répéter dossier" + +msgid "Loop Music" +msgstr "Répéter musique" + +msgid "Loop Sound" +msgstr "Intro en boucle" + +msgid "Low Quality" +msgstr "Basses qualités" + +msgid "Low/High" +msgstr "Basses/Hautes" + +msgid "MIOS (Default & Customs)" +msgstr "MIOS (Défaut & Customs)" + +msgid "Main DOL" +msgstr "Lancer main.dol" + +msgid "Main GameCube Games Path" +msgstr "Dossier principal des jeux GameCube (USB)" + +msgid "Main GameCube Path" +msgstr "Dossier GameCube principal" + +msgid "Main Path" +msgstr "Dossier principal" + +msgid "Manual (40~120)" +msgstr "Manuelle (40~120)" + +msgid "Mar" +msgstr "Mars" + +msgid "Mark new games" +msgstr "Marquer les nouveaux jeux" + +msgid "May" +msgstr "Mai" + +msgid "Memory Card Blocks Size" +msgstr "Taille carte mémoire (Blocs)" + +msgid "Memory Card Emulation" +msgstr "Emulation carte mémoire" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "Les cartes mémoires de 2043 blocs peuvent poser des problèmes avec Nintendont. Utilisez cette taille à vos propres risques." + +msgid "Messageboard Update" +msgstr "Mise à jour carnet Wii" + +msgid "Motion+ Video" +msgstr "Vidéo Motion+" + +msgid "Mount DVD drive" +msgstr "Charger le DVD" + +msgid "Mount USB at launch" +msgstr "Charger USB au démarrage" + +msgid "Move File" +msgstr "Déplacement de fichier" + +msgid "Multiple Partitions" +msgstr "Partitions multiples" + +msgid "Music Loop Mode" +msgstr "Type de boucle" + +msgid "Music Volume" +msgstr "Volume musique" + +msgid "NMM Mode" +msgstr "Mode NMM" + +msgid "Nand Chan. Emulation" +msgstr "Émulation Nand Chaînes" + +msgid "Nand Channels" +msgstr "Chaînes sur Wii" + +msgid "Nand Emu Channel Path" +msgstr "Dossier ÉmuNand Chaînes" + +msgid "Nand Emu Path" +msgstr "Dossier Émulation Nand" + +msgid "Nand Emulation" +msgstr "Émulation Nand" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "L'Émulation Nand n'est disponible qu'avec le cIOS D2X!" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "L'Émulation Nand ne fonctionne qu'avec une partition FAT/FAT32!" + +msgid "Nand Saves Emulation" +msgstr "Émul. Nand Sauvegardes" + +msgid "Native Controller" +msgstr "Port manettes natif" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "La sélection du dossier NAND pour Neek a échoué." + +msgid "Neek kernel file not found." +msgstr "Fichier kernel de Neek non trouvé." + +msgid "Neek kernel loading failed." +msgstr "Echec de chargement du kernel de Neek." + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "Neek2o n'est pas compatible avec le dossier emuNAND sur carte SD. Veuillez plutôt utiliser Uneek2o." + +msgid "Neither" +msgstr "Aucun" + +msgid "Network is not initiated." +msgstr "Réseau non initialisé" + +msgid "Next" +msgstr "Suivant" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "Dossier Loader Nintendont" + +msgid "No" +msgstr "Non" + +msgid "No Cheatfile found" +msgstr "Aucun fichier de triche trouvé" + +msgid "No DOL file found on disc." +msgstr "Aucun DOL trouvé dans ce jeu." + +msgid "No Disc+" +msgstr "No Disc+" + +msgid "No Splitting" +msgstr "Aucun" + +msgid "No URL or Path specified." +msgstr "Pas d'adresse ou de chemin spécifié" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "Partition WBFS ou FAT/NTFS/EXT non trouvée" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "Fichier Wiinnertag.xml non trouvé. Voulez-vous créer un fichier d'exemple ?" + +msgid "No change" +msgstr "Aucune modification" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "Auncun code-triche sélectionné ! Voulez-vous supprimer le fichier GCT ?" + +msgid "No data could be read." +msgstr "Lecture des données impossible." + +msgid "No disc inserted." +msgstr "Aucun disque inséré." + +msgid "No favorites selected." +msgstr "Pas de favoris sélectionnés" + +msgid "No file missing!" +msgstr "Aucun fichier manquant !" + +msgid "No games found on the disc" +msgstr "Aucun jeux trouvé sur le disque" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "Aucun fichier de langage trouvé! Voulez-vous les télécharger ?" + +msgid "No new updates." +msgstr "Pas de nouvelle mise à jour." + +msgid "No themes found on the site." +msgstr "Aucun thème trouvé sur le site." + +msgid "No themes found." +msgstr "Aucun thème trouvé." + +msgid "No wad file found in this folder." +msgstr "Aucun fichier Wad trouvé dans ce dossier." + +msgid "NoSSL only" +msgstr "NoSSL seulement" + +msgid "None" +msgstr "Aucun" + +msgid "Normal" +msgstr "Normale" + +msgid "Not Initialized" +msgstr "Disque non initialisé" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "Ce disque n'est ni un jeu Wii ni un jeu GameCube" + +msgid "Not a valid URL" +msgstr "URL non valide" + +msgid "Not a valid URL path" +msgstr "Chemin URL non valide" + +msgid "Not a valid domain" +msgstr "Domaine non valide" + +msgid "Not enough free memory." +msgstr "Mémoire libre insuffisante !" + +msgid "Not enough free space on device." +msgstr "Espace insuffisant sur le périphérique sélectionné" + +msgid "Not enough free space!" +msgstr "Espace libre insuffisant !" + +msgid "Not enough memory for FST." +msgstr "Mémoire insuffisante pour FST." + +msgid "Not enough memory." +msgstr "Mémoire insuffisante." + +msgid "Not required" +msgstr "Non requis" + +msgid "Not supported format!" +msgstr "Format non supporté !" + +msgid "Nothing selected to delete." +msgstr "Il n'y a rien à supprimer." + +msgid "Nothing selected to install." +msgstr "Il n'y a rien à installer." + +msgid "Nov" +msgstr "" + +msgid "OFF" +msgstr "Inactif" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "Actif" + +msgid "ON (Multi)" +msgstr "Actif (Multi)" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "Ocarina ne fonctionne pas encore avec Neek2o. Voulez-vous quand même le lancer le jeu ?" + +msgid "Oct" +msgstr "" + +msgid "Official Site:" +msgstr "Site officiel:" + +msgid "Offset" +msgstr "" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "Une ligne A" + +msgid "One Line B" +msgstr "Une ligne B" + +msgid "Only Game Partition" +msgstr "Uniquement la partition de jeu" + +msgid "Only for Install" +msgstr "Uniquement à l'installation" + +msgid "Original" +msgstr "Originaux" + +msgid "Original/Customs" +msgstr "Originaux/Persos" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "Patch PAL50" + +msgid "Parental Control" +msgstr "Contrôle parental" + +msgid "Partial" +msgstr "Partielle" + +msgid "Partition" +msgstr "" + +msgid "Password" +msgstr "Mot de passe" + +msgid "Password Changed" +msgstr "Mot de passe modifié" + +msgid "Password has been changed" +msgstr "Mot de passe modifié" + +msgid "Patch Country Strings" +msgstr "Patch jeux import" + +msgid "Path Changed" +msgstr "Chemin changé" + +msgid "Permission denied." +msgstr "Permission refusée." + +msgid "Pick from a list" +msgstr "Sélectionner" + +msgid "Pixels" +msgstr "pixels" + +msgid "Play Count" +msgstr "Utilisations" + +msgid "Play Next" +msgstr "Jouer suiv." + +msgid "Play Once" +msgstr "Jouer 1 fois" + +msgid "Play Previous" +msgstr "Jouer précéd." + +msgid "Playing Music:" +msgstr "Musique actuelle:" + +msgid "Please wait" +msgstr "Veuillez patienter" + +msgid "Please wait..." +msgstr "Veuillez patienter..." + +msgid "Power off the Wii" +msgstr "Éteindre la Wii" + +msgid "Prev" +msgstr "Précédent" + +msgid "Private Server" +msgstr "Serveur privé" + +msgid "Process finished." +msgstr "Opération terminée." + +msgid "Progressive Patch" +msgstr "Patch progressif" + +msgid "Prompts Buttons" +msgstr "Largeur de l'interface" + +msgid "Published by" +msgstr "Publié par" + +msgid "Quick Boot" +msgstr "Démarrage rapide" + +msgid "Random Directory Music" +msgstr "Aléatoire" + +msgid "Real Nand" +msgstr "Nand réelle" + +msgid "Receiving file from:" +msgstr "Réception du fichier de:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "Patch Région" + +msgid "Released" +msgstr "Date de sortie" + +msgid "Reload SD" +msgstr "Recharger la SD" + +msgid "Reloading game list now, please wait..." +msgstr "Rechargement de la liste des jeux, veuillez patienter..." + +msgid "Remember Unlock" +msgstr "Mémoriser le verrouillage" + +msgid "Remove Read Speed Limit" +msgstr "Débrider la vitesse de lecture" + +msgid "Remove update" +msgstr "Supprimer MàJ" + +msgid "Rename Game Title" +msgstr "Renommer le jeu" + +msgid "Rename category" +msgstr "Renom. catégorie" + +msgid "Reset" +msgstr "Réinitialisation" + +msgid "Reset BG Music" +msgstr "Fond sonore par defaut" + +msgid "Reset Playcounter" +msgstr "Remise à zéro du compteur d'utilisations" + +msgid "Reset to default BGM?" +msgstr "Remettre le fond sonore par defaut ?" + +msgid "Restarting..." +msgstr "Redémarrage..." + +msgid "Return" +msgstr "Retour" + +msgid "Return To" +msgstr "Retourner vers" + +msgid "Return to Wii Menu" +msgstr "Retourner au menu Wii" + +msgid "Right" +msgstr "Droite" + +msgid "Rotating Disc" +msgstr "Disque rotatif" + +msgid "Round" +msgstr "Arrondi" + +msgid "Rumble" +msgstr "Vibrations" + +msgid "SChinese" +msgstr "Chinois simplifié" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "Impossible d'accéder à la carte SD." + +msgid "SD GameCube Games Path" +msgstr "Dossier GameCube sur la carte SD" + +msgid "SD GameCube Path" +msgstr "Dossier GameCube SD" + +msgid "SD Path" +msgstr "Dossier carte SD" + +msgid "SFX Volume" +msgstr "Volume SFX" + +msgid "Save" +msgstr "Enregistrer" + +msgid "Save Failed. No device inserted?" +msgstr "Echec de la sauvegarde. Aucun périphérique inséré ?" + +msgid "Save Game List to" +msgstr "Sauvegarder la liste des jeux sous" + +msgid "Save List" +msgstr "Exporter la liste" + +msgid "Saved" +msgstr "Sauvegardé" + +msgid "Savegame might not exist for this game." +msgstr "La sauvegarde de ce jeu est peut-être inexistante." + +msgid "Screensaver" +msgstr "Économiseur d'écran" + +msgid "Screenshot" +msgstr "Capture d'écran" + +msgid "Select" +msgstr "Choisir" + +msgid "Select DOL Offset" +msgstr "Offset du DOL alt." + +msgid "Select a DOL" +msgstr "Choisir un DOL" + +msgid "Select a DOL from Game" +msgstr "Sélectionner un DOL à partir du jeu" + +msgid "Select game categories" +msgstr "Filtrer par catégories de jeux" + +msgid "Select loader mode" +msgstr "Mode du Loader" + +msgid "Select the NAND Emu Path to use." +msgstr "Sélectionnez le dossier EmuNAND à utiliser." + +msgid "Select titles sources." +msgstr "Choisissez les titres à afficher :" + +msgid "Sept" +msgstr "" + +msgid "Set Search-Filter" +msgstr "Filtre de Recherche" + +msgid "Settings" +msgstr "Paramètres" + +msgid "Settings File" +msgstr "Fichier de configs" + +msgid "Show Categories" +msgstr "Afficher les catégories" + +msgid "Show Favorite on banner" +msgstr "Afficher les fav. sur bannières" + +msgid "Show Free Space" +msgstr "Afficher l'espace libre" + +msgid "Show Play Count" +msgstr "Afficher le compteur d'utilis." + +msgid "Show SD" +msgstr "Voir la carte SD" + +msgid "Shutdown System" +msgstr "Arrêt" + +msgid "Shutdown Wii" +msgstr "Éteindre la Wii" + +msgid "Skip Errors" +msgstr "Omettre les erreurs" + +msgid "Skip IPL" +msgstr "Omettre le BIOS" + +msgid "Sneek Video Patch" +msgstr "Patch vidéo Sneek" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "Désolé, le menu de téléchargement des thèmes ne fonctionne plus, le site http://wii.spiffy360.com nécessite désormais un compte utilisateur. " + +msgid "Sort alphabetically" +msgstr "Ordre alphabétique" + +msgid "Sort by number of players" +msgstr "Nombre de joueurs" + +msgid "Sort by rank" +msgstr "Classement favoris" + +msgid "Sort order by most played" +msgstr "Les plus joués" + +msgid "Sound" +msgstr "Sons" + +msgid "Sound Settings" +msgstr "Réglages du son" + +msgid "Sound+BGM" +msgstr "Intro + fond sonore" + +msgid "Sound+Quiet" +msgstr "Intro officielle" + +msgid "Spanish" +msgstr "Espagnol" + +msgid "Special thanks to:" +msgstr "Remerciements spéciaux à:" + +msgid "Split each 2GB" +msgstr "2Go" + +msgid "Split each 4GB" +msgstr "4Go" + +msgid "Standby" +msgstr "Veille" + +msgid "Start" +msgstr "Démarrer" + +msgid "Success" +msgstr "Succès" + +msgid "Success." +msgstr "Succès" + +msgid "Success:" +msgstr "Succès:" + +msgid "Successfully Saved" +msgstr "Enregistré avec succès" + +msgid "Successfully Updated" +msgstr "Mise à jour terminée" + +msgid "Successfully copied" +msgstr "Copié avec succès" + +msgid "Successfully deleted:" +msgstr "Supprimé avec succès:" + +msgid "Successfully extracted theme." +msgstr "Succès de l'extraction du thème." + +msgid "Successfully installed:" +msgstr "Installé avec succès:" + +msgid "Successfully updated." +msgstr "Mise à jour terminée." + +msgid "Switching to channel list mode." +msgstr "Passage du loader en mode Chaînes." + +msgid "Sync FAT32 FS Info" +msgstr "Synch. info FAT32" + +msgid "Synchronizing..." +msgstr "Synchronisation..." + +msgid "System Default" +msgstr "Console par défaut" + +msgid "TChinese" +msgstr "Chinois traditionnel" + +msgid "TXT Cheatcodes Path" +msgstr "Dossier TXT de triches" + +msgid "The .them file was not found in the zip." +msgstr "Fichier .them non trouvé dans le zip." + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "Le paramètre DML Forcer 16:9 nécessite DIOS MIOS v2.1 ou supérieure. Ce paramètre sera ignoré." + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Les Miis seront extraits vers vos dossiers d'Émulation Nand et d'Émulation Nand Chaînes. Attention: Tous les fichiers existants seront remplacés." + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "L'option No Disc+ nécessite DIOS MIOS 2.2 update2. Ce paramètre sera ignoré." + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Le fichier SYSCONF sera extrait vers vos dossiers d'Émulation Nand et d'Émulation Nand Chaînes. Attention: Le fichier existant sera remplacé." + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "L'application pourrait planter s'il y a actuellement des accès en lecture/écriture sur la carte SD !" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "Répertoire indiqué inexistant. Souhaitez-vous le créer ?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "Les fichiers seront extraits vers vos dossiers d'ÉmuNand et d'ÉmuNand Chaînes. Attention: Tous les fichiers existants seront remplacés." + +msgid "The game is on SD Card." +msgstr "Le jeu est sur la carte SD." + +msgid "The game is on USB." +msgstr "Le jeu est sur USB" + +msgid "The save game will be extracted to your emu nand path." +msgstr "La sauvegarde du jeu sera extraite vers votre dossier d'Émulation Nand." + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "Les sauvegardes des jeux seront extraites vers vos dossiers d'Émulation Nand et d'Émulation Nand Chaînes. Attention: Tous les fichiers existants seront remplacés." + +msgid "The wad file was installed" +msgstr "Le fichier wad a été installé" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "L'installation du wad a échoué avec l'erreur %i" + +msgid "Theme Downloader" +msgstr "Téléchargement des thèmes" + +msgid "Theme Menu" +msgstr "Thèmes" + +msgid "Theme Path" +msgstr "Dossier thème" + +msgid "Theme Title:" +msgstr "Titre du thème:" + +msgid "Themes by www.spiffy360.com" +msgstr "Thèmes par www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "Cet IOS est l'IOS de BootMii. Si vous étes certain que ce n'est pas BootMii, ignorez cet avertissement." + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "Cet IOS n'a pas été trouvé dans la liste des titres. Si vous êtes certain de l'avoir installé, ignorez cet avertissement." + +msgid "This Nintendont version does not support games on USB." +msgstr "Cette version de Nintendont n'est pas compatible avec les jeux sur USB." + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "Cette version de Nintendont n'est pas correctement supportée. Démarrage automatique désactivé." + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "Ce jeu a plusieurs disques, choisissez celui que vous souhaitez lancer." + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "Ce patch pourrait ne pas fonctionner avec tous les jeux. Si un jeu ne démarre pas, désactivez le dans le menu des options individuelles du jeu." + +msgid "This path must be on SD!" +msgstr "Ce chemin doit être situé sur la carte SD !" + +msgid "Time left:" +msgstr "Fini dans:" + +msgid "Timer Fix" +msgstr "Correction du timing" + +msgid "Title Launcher" +msgstr "Menu Chaînes" + +msgid "Titles Path" +msgstr "Dossier titres" + +msgid "Titles from GameTDB" +msgstr "Titres de GameTDB" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "Pour lancer les jeux GameCube à partir du disque vous devez placer le Mode GameCube sur MIOS dans les paramètres du jeu." + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "Pour lancer les jeux GameCube avec %s vous devez les copier sur une partition USB FAT32." + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "Pour lancer les jeux GameCube avec %s vouz devez placer votre 'Dossier GameCube principal' sur la premiere partition principale FAT32." + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "Pour lancer les jeux GameCube avec %s vous devez placer votre 'Dossier GameCube principal' sur la 1ère partition principale du disque dur." + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "Pour lancer les jeux GameCube avec %s vous devez placer votre 'Dossier GameCube principal' sur une partition USB FAT32." + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "Pour lancer les jeux GameCube avec %s vous devez utiliser un disque dur avec 512 octets par secteur." + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "Pour lancer les jeux GameCube avec %s vous devez utiliser une partition avec une taille de cluster de 32Ko maximum." + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "Pour lancer les jeux GameCube avec Devolution vous devez placer le fichier loader.bin dans le Dossier Loader Devolution." + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "Pour lancer les jeux GameCube avec Nintendont vous devez placer le fichier boot.dol dans le Dossier Loader Nintendont." + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "Pour utiliser HID avec %s vous avez besoin du fichier %s." + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "Pour utiliser Neek vous devez placer votre 'Dossier ÉmuNand Chaînes' sur la premiere partition principale FAT32." + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "Pour utiliser Neek vous devez placer votre 'Dossier ÉmuNand Chaînes' sur une partition FAT32." + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "Pour utiliser Neek vous devez utiliser un disque dur avec 512 octets par secteur." + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "Pour utiliser Ocarina avec %s vous avez besoin du fichier %s." + +msgid "Tooltip Delay" +msgstr "Délai des Info-bulles" + +msgid "Tooltips" +msgstr "Info-bulles" + +msgid "Transfer failed" +msgstr "Échec du transfert" + +msgid "Triforce Arcade Mode" +msgstr "Triforce Mode arcade" + +msgid "Two Lines" +msgstr "Deux lignes" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "Périphérique USB non initialisé." + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX est verrouillé" + +msgid "USB Port" +msgstr "Port USB" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "Le changement de port USB n'est supporté qu'avec les cIOS d'Hermes." + +msgid "USB-HID Controller" +msgstr "Manette USB-HID" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "USBLoaderGX n'a pas pu vérifier le fichier boot.dol de nintendont. Voulez-vous quand même le lancer ?" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "USBLoaderGX n'a pas pu créer le fichier de configuration de Nintendont. Voulez-vous quand même lancer Nintendont ?" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "Nintendont Alpha v0.1 ne fonctionne qu'avec USBLoaderGX r1218. Veuillez mettre à jour votre version de Nintendont." + +msgid "Uninstall" +msgstr "Désinstaller" + +msgid "Uninstall Game" +msgstr "Désinstaller le jeu" + +msgid "Uninstall Menu" +msgstr "Menu suppression" + +msgid "Uninstall all" +msgstr "Tout supprimer" + +msgid "Unknown" +msgstr "Inconnu" + +msgid "Unlock USB Loader GX" +msgstr "Déverrouiller USB Loader GX" + +msgid "Unlocked" +msgstr "Clic pour verrouiller" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "Format non supporté, essayez d'extraire manuellement TempTheme.zip." + +msgid "Update" +msgstr "Mise à jour" + +msgid "Update All" +msgstr "Totale" + +msgid "Update DOL" +msgstr "DOL seul" + +msgid "Update Files" +msgstr "MàJ Fichiers" + +msgid "Update Path" +msgstr "Dossier de mise à jour" + +msgid "Update all Language Files" +msgstr "Mise à jour des fichiers de langue" + +msgid "Update failed" +msgstr "Échec de la mise à jour" + +msgid "Update successfull" +msgstr "Mise à jour réussie" + +msgid "Updating Language Files:" +msgstr "Mise à jour du fichier de langue:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Fichier ZIP envoyé et installé dans le répertoire homebrew." + +msgid "Use System Font" +msgstr "Police d'écriture système" + +msgid "Use global" +msgstr "Paramètre du loader" + +msgid "VBI (Default)" +msgstr "VBI (Défaut)" + +msgid "VIDTV Patch" +msgstr "Patch VIDTV" + +msgid "Version:" +msgstr "" + +#, c-format +msgid "Version: %s" +msgstr "" + +msgid "Video Deflicker" +msgstr "Vidéo Deflicker" + +msgid "Video Mode" +msgstr "Mode vidéo" + +msgid "Video Scale Value" +msgstr "Valeur d'échelle" + +msgid "Video offset" +msgstr "Position de l'image" + +msgid "Video scale" +msgstr "Échelle de l'image" + +msgid "Virtual Pointer Speed" +msgstr "Vitesse du pointeur virtuel" + +msgid "WDM Files Path" +msgstr "Dossier fichiers WDM" + +msgid "WIP Patches Path" +msgstr "Dossier patchs WIP" + +msgid "Waiting..." +msgstr "En attente..." + +msgid "Warning" +msgstr "Attention" + +msgid "Warning:" +msgstr "Attention:" + +msgid "What do you want to do?" +msgstr "Que voulez-vous faire ?" + +msgid "What do you want to update?" +msgstr "Choix de la mise à jour" + +msgid "What should be deleted for this game title:" +msgstr "Que voulez-vous supprimer pour ce titre?" + +msgid "What to extract from NAND?" +msgstr "Que voulez-vous extraire de la NAND ?" + +msgid "Where should the game be installed to?" +msgstr "Où installer ce jeu ?" + +msgid "Where to dump NAND?" +msgstr "Où voulez-vous extraire votre NAND ?" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "Quel périphérique voulez-vous utiliser pour les fichiers de Nintendont ?" + +msgid "Which mode do you want to use?" +msgstr "Quel mode voulez-vous utiliser ?" + +msgid "WiFi Features" +msgstr "Connexion WiFi" + +msgid "Widescreen Factor" +msgstr "Échelle de l'interface" + +msgid "Widescreen Fix" +msgstr "Utiliser un taux d'échelle" + +msgid "Wii Games" +msgstr "Jeux Wii" + +msgid "Wii Menu" +msgstr "Menu Wii" + +msgid "Wii Settings" +msgstr "Paramètres Wii" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "WiiTDB.xml est à jour." + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "Illumination Wii" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "Dossier Wiinnertag" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Wiinnertag nécessite une connexion automatique au réseau au lancement de l'application. Voulez-vous l'activer ?" + +msgid "Wiird Debugger" +msgstr "Débugger WiiRd" + +#, c-format +msgid "Write error on file: %s" +msgstr "Erreur d'écriture sur le fichier: %s" + +msgid "Writing GXGameCategories.xml" +msgstr "Ecriture GXGameCategories.xml" + +msgid "Wrong Password" +msgstr "Mot de passe incorrect" + +msgid "Yes" +msgstr "Oui" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "Vous essayez de sélectionner une partition FAT32/NTFS/EXT avec un cIOS 249 Rev < 18 (non supporté). Continuez à vos risques." + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "Vous pouvez choisir ou formater une partition, ou passer le loader en mode Chaînes." + +msgid "You cannot delete this category." +msgstr "Vous ne pouvez pas supprimer cette catégorie." + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "Neek2o est nécessaire si le dossier EmuNAND est dans un sous-dossier." + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "Vous devez installer DIOS MIOS Lite v1.2 ou une version plus récente." + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "Vous devez installer un Loader de jeu GameCube additionnel ou sélectionner un mode GameCube différent pour lancer les jeux GameCube sur USB ou carte SD." + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "Votre partition actuelle pour les jeux GameCube n'est pas compatible. Veuillez mettre à jour Nintendont." + +msgid "Zoom Duration (Speed)" +msgstr "Durée du zoom (Vitesse)" + +msgid "and translators for language files updates" +msgstr "et les traducteurs pour la MàJ des fichiers langue" + +msgid "available" +msgstr "disponible" + +msgid "does not exist!" +msgstr "inexistant!" + +msgid "does not exist! Loading game without cheats." +msgstr "inexistant! Chargement du jeu sans tricheries." + +msgid "files left" +msgstr "fichiers restants" + +msgid "for FAT/NTFS support" +msgstr "pour le support FAT/NTFS" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "pour GameTDB et l'hébergement des jaquettes" + +msgid "for Ocarina" +msgstr "pour Ocarina" + +msgid "for diverse patches" +msgstr "pour les divers patchs" + +msgid "for his awesome tool LibWiiGui" +msgstr "pour son outil impressionnant LibWiiGui" + +msgid "for hosting the themes" +msgstr "pour l'hébergement des thèmes" + +msgid "for the USB Loader source" +msgstr "pour les sources USBLoader" + +msgid "for their work on the wiki page" +msgstr "pour leur travail sur les pages wiki" + +msgid "formatted!" +msgstr "formaté !" + +msgid "free" +msgstr "libre" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "non défini" + +msgid "of" +msgstr "sur" + +msgid "seconds left" +msgstr "secondes restantes" + +#~ msgid "Do you want to update this file?" +#~ msgstr "Voulez-vous mettre à jour ce fichier ?" + +#~ msgid "Install WAD to EmuNand" +#~ msgstr "Installer WAD sur ÉmuNand" + +#~ msgid "Update Nintendont" +#~ msgstr "Mettre Nintendont à jour" + +#~ msgid "WAD Installation" +#~ msgstr "Installation WAD" + +#~ msgid "GameTDB Path" +#~ msgstr "Dossier GameTDB" + +#~ msgid "Where do you want MCEmu to be located?" +#~ msgstr "Quel emplacement utiliser pour la sauvegarde ?" + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on a primary partition." +#~ msgstr "Pour lancer les jeux GameCube avec %s vouz devez placer votre 'Dossier GameCube principal' sur une partition principale." + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first partition of the Hard Drive." +#~ msgstr "Pour lancer les jeux GameCube avec %s vouz devez placer votre 'Dossier GameCube principal' sur la 1ère partition du disque dur." + +#~ msgid "Error 002 fix" +#~ msgstr "Correctif Erreur 002" + +#~ msgid "Use Game Settings" +#~ msgstr "Utiliser paramètres du jeu" + +#~ msgid "Main tester:" +#~ msgstr "Testeur:" + +#~ msgid "Nintendont currently only supports GameCube games on SD card." +#~ msgstr "Nintendont n'est actuellement compatible qu'avec les cartes SD." + +#~ msgid "USB Device not found." +#~ msgstr "Périphérique USB introuvable." + +#~ msgid "Boot/Standard" +#~ msgstr "IOS par défaut" + +#~ msgid "DEVO D Buttons" +#~ msgstr "DEVO Boutons directs" + +#~ msgid "DEVO Force Widescreen" +#~ msgstr "DEVO Forcer 16:9" + +#~ msgid "DEVO LED Activity" +#~ msgstr "DEVO LED detect. activité" + +#~ msgid "DEVO MemCard Emulation" +#~ msgstr "DEVO MemCard Émulation" + +#~ msgid "DEVO Timer Fix" +#~ msgstr "DEVO Correction timing" + +#~ msgid "DML Auto" +#~ msgstr "Auto" + +#~ msgid "DML Debug" +#~ msgstr "DML Débug" + +#~ msgid "DML Force Widescreen" +#~ msgstr "DML Forcer 16:9" + +#~ msgid "DML Japanese Patch" +#~ msgstr "DML Patch japonais" + +#~ msgid "DML LED Activity" +#~ msgstr "DML LED detect. activité" + +#~ msgid "DML NMM Mode" +#~ msgstr "DML Mode NMM" + +#~ msgid "DML No Disc+" +#~ msgstr "DML NoDisc+" + +#~ msgid "DML None" +#~ msgstr "Aucun" + +#~ msgid "DML Progressive Patch" +#~ msgstr "DML Patch Progressif" + +#~ msgid "DML Screenshot" +#~ msgstr "DML Capture d'écran" + +#~ msgid "DML Video Mode" +#~ msgstr "DML Mode vidéo" + +#~ msgid "Devolution requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +#~ msgstr "Devolution nécessite l'accès AHB ! Veuillez lancer USBLoaderGX à partir du HBC ou mettre à jour votre chaîne." + +#~ msgid "To run GameCube games with DIOS MIOS you need to place them on an USB FAT32 partition." +#~ msgstr "Pour lancer les jeux GameCube avec DIOS MIOS vouz devez les copier sur une partition USB FAT32." + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' on a primary partition." +#~ msgstr "Pour lancer les jeux GameCube avec DIOS MIOS vouz devez placer votre 'Dossier GameCube principal' sur une partition principale." + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' on the first partition of the Hard Drive." +#~ msgstr "Pour lancer les jeux GameCube avec DIOS MIOS vouz devez placer votre 'Dossier GameCube principal' sur la 1ère partition du disque dur." + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' to an USB FAT32 partition." +#~ msgstr "Pour lancer les jeux GameCube avec DIOS MIOS vouz devez placer votre 'Dossier GameCube principal' sur une partition USB FAT32." + +#~ msgid "To run GameCube games with DIOS MIOS you need to use a 512 bytes/sector Hard Drive." +#~ msgstr "Pour lancer les jeux GameCube avec DIOS MIOS vouz devez utiliser un disque dur avec 512 octets par secteur." + +#~ msgid "To run GameCube games with DIOS MIOS you need to use a partition with 32k bytes/cluster or less." +#~ msgstr "Pour lancer les jeux GameCube avec DIOS MIOS vous devez utiliser une partition avec une taille de cluster de 32Ko maximum." + +#~ msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Path." +#~ msgstr "Pour lancer les jeux GameCube avec Devolution vous devez placer le fichier loader.bin dans le Dossier Loader Devolution." + +#~ msgid "To run GameCube games with Devolution you need to use a FAT32 partition." +#~ msgstr "Pour lancer les jeux GameCube avec Devolution vous devez utiliser une partition FAT32." + +#~ msgid "You need to install Devolution or DIOS MIOS (Lite) to launch GameCube games from USB or SD card" +#~ msgstr "Vous devez installer Devolution ou DIOS MIOS (Lite) pour lancer les jeux GameCube sur USB ou carte SD." + +#~ msgid "You need to set GameCube Mode to Devolution to launch GameCube games from USB or SD card" +#~ msgstr "Vous devez placer le Mode GameCube sur Devolution dans les paramètres du jeu pour lancer les jeux GameCube sur USB ou carte SD." + +#~ msgid "DML No Disc" +#~ msgstr "DML NoDisc" + +#~ msgid "The No Disc setting is not used anymore by DIOS MIOS (Lite). Now you need to place a disc in your drive." +#~ msgstr "L'option No Disc n'est plus utilisée par DIOS MIOS (Lite). Vous devez désormais placer un disque dans votre lecteur." + +#~ msgid "The GCT Cheatcodes Path and this game are not on the same partition. Run the game without Ocarina?" +#~ msgstr "The dossier GCT de triche et ce jeu ne sont pas sur la même partition. Lancer le jeu sans Ocarina ?" + +#~ msgid "The GCT Cheatcodes Path must be on SD card. Run the game without Ocarina?" +#~ msgstr "The dossier GCT de triche doit se trouver sur la carte SD. Lancer le jeu sans Ocarina ?" + +#~ msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2 or a newer version. This setting will be ignored." +#~ msgstr "L'option No Disc+ nécessite DIOS MIOS 2.2 update2 ou une version plus récente. Ce paramètre sera ignoré." + +#~ msgid "DML Installed Version" +#~ msgstr "DML Version installée" + +#~ msgid "The Force Widescreen setting requires DIOS MIOS v2.2 or more. This setting will be ignored." +#~ msgstr "Le paramètre DML Forcer 16:9 nécessite DIOS MIOS v2.2 ou supérieure. Ce paramètre sera ignoré." + +#~ msgid "You need to install DIOS MIOS to run GameCube games from USB or DIOS MIOS Lite to run them from SD card" +#~ msgstr "Vous devez installer DIOS MIOS pour lancer les jeux GameCube sur USB ou DIOS MIOS Lite pour ceux sur carte SD." + +#~ msgid "Custom Discarts" +#~ msgstr "Labels DVD persos" + +#~ msgid "Full HQ Covers" +#~ msgstr "Jaqu. complètes HD" + +#~ msgid "Full LQ Covers" +#~ msgstr "Jaqu. complètes SD" + +#~ msgid "Original Discarts" +#~ msgstr "Labels DVD originaux" + +#~ msgid "GC Force Interlace" +#~ msgstr "Entrelacement GameCube" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "Renommer le jeu" + +#~ msgid "Beginning" +#~ msgstr "Début" + +#~ msgid "Content" +#~ msgstr "Contenu" + +#~ msgid "Loader Mode" +#~ msgstr "Mode du Loader" + +#~ msgid "Mixed" +#~ msgstr "Multiples origines" + +#~ msgid "Search Mode" +#~ msgstr "Mode de recherche" + +#~ msgid "Successfully Updated thanks to www.techjawa.com" +#~ msgstr "Mise à jour terminée. Merci à www.techjawa.com" + +#~ msgid "for hosting the update files" +#~ msgstr "pour l'hébergement des Mises à Jour" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Insérez un disque Wii !" + +#~ msgid "Issue manager /" +#~ msgstr "Gestion des erreurs/" + +#~ msgid "No cheats were selected" +#~ msgstr "Aucune sélection de triches" + +#~ msgid "Not a Wii Disc" +#~ msgstr "Disque non Wii" + +#~ msgid "The files will be extracted to your emu nand path. Attention: All existing files will be overwritten." +#~ msgstr "Les fichiers seront extraits vers votre dossier d'Émulation Nand. Attention: Tous les fichiers existants seront remplacés." + +#~ msgid "The save games will be extracted to your emu nand path. Attention: All existing saves will be overwritten." +#~ msgstr "Les sauvegardes des jeux seront extraites vers votre dossier d'Émulation Nand. Attention: Toutes les sauvegardes existantes seront remplacées." + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> Suppression tickets..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> Suppression tickets...ERREUR!" + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> Suppression tickets...OK!" + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> Suppression titre...ERREUR!" + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> Suppression titre...OK!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> Suppression contenus titre..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> Suppression contenus titre...ERREUR!" + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> Suppression contenus titre...OK!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> Suppression titre..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> Finalisation de l'installation..." + +#~ msgid ">> Installing content #" +#~ msgstr ">> Installation contenu #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> Installation ticket..." + +#~ msgid ">> Installing title..." +#~ msgstr ">> Installation titre..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> Lecture données WAD..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> Lecture données WAD...ERREUR!" + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> Lecture données WAD...OK!" + +#~ msgid "Done!" +#~ msgstr "Terminé!" + +#~ msgid "Error..." +#~ msgstr "Erreur..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "Finalisation de l'installation... OK!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "Installation contenu... OK!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "Installation ticket... OK!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "Installation titre... OK!" + +#~ msgid "Installing wad" +#~ msgstr "Installation WAD" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "Lecture données WAD... OK!" + +#~ msgid "Uninstalling wad" +#~ msgstr "Désinstallation wad" + +#~ msgid "The game installation is disabled under this IOS because of instability in usb write." +#~ msgstr "L'installation d'un jeu est désactivée en utilisant cet IOS pour cause d'instabilité en écriture sur l'USB." + +#~ msgid "You are currently using IOS" +#~ msgstr "Vous utilisez actuellement l'IOS" + +#~ msgid "Nand Channel Emulation" +#~ msgstr "Émulation Nand Chaînes" + +#~ msgid "New Disc Detected" +#~ msgstr "Nouveau DVD détecté" + +#~ msgid "USB Device not found" +#~ msgstr "Périphérique USB introuvable" + +#~ msgid "You need to select or format a partition" +#~ msgstr "Vous devez choisir ou formater une partition" + +#~ msgid "Language File" +#~ msgstr "Fichier de langue" + +#~ msgid "Are you sure you want to import game categories from WiiTDB?" +#~ msgstr "Voulez-vous vraiment importer les catégories de jeux à partir de WiiTDB ?" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Titres de WiiTDB" + +#~ msgid "WiiTDB Files" +#~ msgstr "Fichier WiiTDB" + +#~ msgid "WiiTDB Path" +#~ msgstr "Dossier WiiTDB" + +#~ msgid "WiiTDB is up to date." +#~ msgstr "WiiTDB est à jour." + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "pour WiiTDB et l'hébergement des jaquettes" diff --git a/Languages/german.lang b/Languages/german.lang new file mode 100644 index 0000000..7699709 --- /dev/null +++ b/Languages/german.lang @@ -0,0 +1,2802 @@ +# USB Loader GX +# german.lang - r1231 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:02+0200\n" +"PO-Revision-Date: 2010-07-03 17:35-0800\n" +"Last-Translator: Sabykos\n" +"Language-Team: Bertilax, Snoozer, wishmasterf, ZEN.13, TheRealVisitor\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: German\n" + +msgid " could not be downloaded." +msgstr " konnte nicht heruntergeladen werden." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " wurde gespeichert. Möglicherweise funktionieren einige der Codes nicht richtig miteinander. Wenn du Probleme hast, öffne den Text in einem Texteditor um mehr Informationen zu erhalten." + +msgid " is not on the server." +msgstr " ist nicht auf dem Server." + +#, c-format +msgid "%i files not found on the server!" +msgstr "%i Dateien auf dem Server nicht gefunden!" + +#, c-format +msgid "%i missing files" +msgstr "%i fehlende Dateien" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "%s benötigt GameCube Backups im ISO Format." + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "%s benötigt AHB Zugriff! Bitte starte USBLoaderGX vom HBC, einem geupdateten Channel oder Forwarder aus." + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Jeder)" + +msgid "1 (Child 7+)" +msgstr "1 (Kinder 6+) " + +msgid "1 hour" +msgstr "1 Stunde" + +msgid "10 min" +msgstr "10 Minuten" + +msgid "2 (Teen 12+)" +msgstr "2 (Jugendliche 12+)" + +msgid "20 min" +msgstr "20 Minuten" + +msgid "2D Cover Path" +msgstr "2D Cover" + +msgid "3 (Mature 16+)" +msgstr "3 (Erwachsene 16+)" + +msgid "3 min" +msgstr "3 Minuten" + +msgid "30 min" +msgstr "30 Minuten" + +msgid "3D Cover Path" +msgstr "3D Cover" + +msgid "3D Covers" +msgstr "3D Cover" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Erwachsene 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 Minuten" + +msgid "=== GameCube Settings" +msgstr "=== GameCube Einstellungen" + +msgid "AUTO" +msgstr "AUTO" + +msgid "AXNextFrame" +msgstr "AXNextFrame" + +msgid "Add category" +msgstr "Kategorie hinzuf." + +msgid "Adjust Overscan X" +msgstr "Overscan X anpassen" + +msgid "Adjust Overscan Y" +msgstr "Overscan Y anpassen" + +msgid "After zoom" +msgstr "Nach dem Zoom" + +msgid "All" +msgstr "Alle" + +msgid "All Partitions" +msgstr "Alle Partitionen" + +msgid "All files extracted." +msgstr "Alle Dateien entpackt." + +msgid "All images downloaded successfully." +msgstr "Alle Bilder erfolgreich heruntergeladen" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Alle Funktionen des USB Loader GX sind jetzt freigeschaltet." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Alternative DOL" + +msgid "An example file was created here:" +msgstr "Eine Beispieldatei wurde hier erstellt:" + +msgid "Animation Start" +msgstr "Animationsstart" + +msgid "App Language" +msgstr "Sprache" + +msgid "Apply" +msgstr "Übernehmen" + +msgid "Apr" +msgstr "April" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "Wollen Sie wirklich alle gewählten Spiele von der SD Karte löschen?" + +msgid "Are you sure you want to delete this category?" +msgstr "Soll diese Kategorie gelöscht werden?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "Sollen die Spiele-Kategorien aus der WiiTDB importiert werden?" + +msgid "Are you sure you want to install on SD?" +msgstr "Soll auf die SD-Karte installiert werden?" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "Bist du sicher, dass du USB Loader GX sperren willst?" + +msgid "Are you sure you want to remount SD?" +msgstr "Soll die SD erneut gemountet werden?" + +msgid "Are you sure you want to reset?" +msgstr "Bist du sicher, dass du resetten willst?" + +msgid "Are you sure?" +msgstr "Bist du sicher?" + +msgid "Aspect Ratio" +msgstr "Seitenverhältnis" + +msgid "Attention!" +msgstr "Achtung!" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "August" + +msgid "Author(s):" +msgstr "Autor(en)" + +msgid "Auto" +msgstr "Auto" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "Autoinit. Netzwerk" + +msgid "BCA Codes Path" +msgstr "BCA Codes" + +msgid "Back" +msgstr "Zurück" + +msgid "Back to HBC or Wii Menu" +msgstr "Zurück zum Homebrewkanal oder Wii Menü" + +msgid "Backgroundmusic" +msgstr "Hintergrundmusik" + +msgid "Banner Animation" +msgstr "Banner Animation" + +msgid "Banner Animation Settings" +msgstr "Banner Animationen" + +msgid "Banner On Channels" +msgstr "Banner auf Kanälen" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "Banner Raster-Layout ist nur verfügbar mit AHBPROT! Bitte installiere die aktuelle HBC-Version." + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "Banner-Fenster ist nur verfügbar mit AHBPROT! Bitte installiere die aktuelle HBC-Version." + +msgid "Big thanks to:" +msgstr "Vielen Dank an:" + +msgid "Block Categories Menu" +msgstr "Sperre Kategorie-Menü" + +msgid "Block Categories Modify" +msgstr "Sperre Kategorie-Änderung" + +msgid "Block Cover Downloads" +msgstr "Blocke Cover-Downloads" + +msgid "Block Custom Paths" +msgstr "Blocke eigene Pfade" + +msgid "Block Feature Settings" +msgstr "Blocke Feature Optionen" + +msgid "Block Game Install" +msgstr "Blocke Spieleinstallation" + +msgid "Block Game Settings" +msgstr "Blocke Spieleoptionen" + +msgid "Block GameID Change" +msgstr "Blocke GameID-Änderung" + +msgid "Block Global Settings" +msgstr "Sperre alle Einstellungen" + +msgid "Block Gui Settings" +msgstr "Blocke GUI-Optionen" + +msgid "Block HBC Menu" +msgstr "Blocke HBC Menü" + +msgid "Block Hard Drive Settings" +msgstr "Blocke Festpl. Optionen" + +msgid "Block IOS Reload" +msgstr "Blocke IOS-Neuladen" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "Blocke Loader-Modus Button" + +msgid "Block Loader Settings" +msgstr "Blocke Loaderoptionen" + +msgid "Block Parental Settings" +msgstr "Blocke Altersoptionen" + +msgid "Block Priiloader Override" +msgstr "Blocke Priiloader Override" + +msgid "Block Reset Settings" +msgstr "Blocke Resetoptionen" + +msgid "Block SD Reload Button" +msgstr "Blocke SD Reload Button" + +msgid "Block Sound Settings" +msgstr "Blocke Soundoptionen" + +msgid "Block Theme Downloader" +msgstr "Blocke Theme Downloader" + +msgid "Block Theme Menu" +msgstr "Blocke Theme Menü" + +msgid "Block Title Launcher" +msgstr "Blocke Title Launcher" + +msgid "Block Updates" +msgstr "Blocke Updates" + +msgid "Boot Content" +msgstr "Boote Inhalt" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "Kanal starten?" + +msgid "Both" +msgstr "ID und Region" + +msgid "Both Ports" +msgstr "Beide Ports" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "BNR-Cache" + +msgid "Cache BNR Files Path" +msgstr "Cache BNR Dateien" + +msgid "Cache Titles" +msgstr "Titel cachen" + +msgid "Can't be formatted" +msgstr "Kann nicht formatiert werden." + +msgid "Can't create directory" +msgstr "Verzeichnis kann nicht erstellt werden." + +#, c-format +msgid "Can't create file: %s" +msgstr "Datei kann nicht erstellt werden: %s" + +#, c-format +msgid "Can't create path: %s" +msgstr "Kann Pfad nicht erstellen: %s" + +msgid "Can't delete:" +msgstr "Löschen fehlgeschlagen:" + +msgid "Can't mount or unknown disc format." +msgstr "Kann nicht gemountet werden oder unbekanntes Discformat" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "Datei kann zum Schreiben nicht geöffnet werden: %s" + +#, c-format +msgid "Can't open file: %s" +msgstr "Datei kann nicht geöffnet werden: %s" + +#, c-format +msgid "Can't read file: %s" +msgstr "Datei kann nicht gelesen werden: %s" + +msgid "Cancel" +msgstr "Abbrechen" + +msgid "Cannot write to destination." +msgstr "Ziel kann nicht beschrieben werden." + +msgid "Categories" +msgstr "Kategorien" + +msgid "Categories:" +msgstr "Kategorien:" + +msgid "Change Play Path" +msgstr "Pfad ändern" + +msgid "Channel Launcher" +msgstr "Kanal Starter" + +msgid "Channels" +msgstr "Kanäle" + +msgid "Cheatfile is blank" +msgstr "Cheatdatei ist leer" + +msgid "Clear" +msgstr "Freigeben" + +msgid "Click to Download Covers" +msgstr "Cover herunterladen" + +msgid "Click to change game ID" +msgstr "Spiel ID ändern" + +msgid "Clock" +msgstr "Uhr" + +msgid "Clock Scale Factor" +msgstr "Uhr-Skalierwert" + +msgid "Close" +msgstr "Schließen" + +msgid "Code Download" +msgstr "Cheatcodes werden heruntergeladen" + +#, c-format +msgid "Coded by: %s" +msgstr "Programmiert von: %s" + +msgid "Coding:" +msgstr "Programmierung:" + +msgid "Connection to server timed out." +msgstr "Zeitüberschreitung bei Serververbindung." + +msgid "Console" +msgstr "Konsolenstatus" + +msgid "Console Default" +msgstr "Konsolenstandard" + +msgid "Console Locked" +msgstr "Konsole gesperrt" + +msgid "Console must be unlocked for this option." +msgstr "Gerät muss für diese Option entsperrt werden." + +msgid "Console must be unlocked to be able to use this." +msgstr "Gerät muss für diese Nutzung entsperrt werden." + +msgid "Console should be unlocked to modify it." +msgstr "Konsole muss zum Bearbeiten entsperrt werden." + +msgid "Continue" +msgstr "Weiter" + +msgid "Continue to install game?" +msgstr "Fortfahren um Spiel zu installieren?" + +msgid "Continue?" +msgstr "Weiter?" + +msgid "Controllevel" +msgstr "Alterseinstufung" + +msgid "Copy" +msgstr "Kopie" + +msgid "Copying Canceled" +msgstr "Kopieren abgebrochen" + +msgid "Copying GC game..." +msgstr "Kopiere GC Spiele" + +msgid "Copying files..." +msgstr "Kopiere Dateien..." + +msgid "Correct Password" +msgstr "Richtiges Passwort" + +msgid "Could not connect to the server." +msgstr "Konnte mit Server nicht verbinden." + +msgid "Could not create GCT file" +msgstr "GCT Datei konnte nicht erstellt werden." + +#, c-format +msgid "Could not create path: %s" +msgstr "Konnte Pfad nicht erstellen: %s" + +msgid "Could not extract files for:" +msgstr "Konnte Dateien nicht entpacken für:" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "Konnte keine Info für das Spiel in der wiitdb.xml finden." + +msgid "Could not get free device space for game." +msgstr "Es konnte kein freier Speicher für das Spiel reserviert werden." + +msgid "Could not initialize DIP module!" +msgstr "DIP Modul konnte nicht initialisiert werden!" + +msgid "Could not initialize network!" +msgstr "Netzwerk konnte nicht initialisiert werden!" + +msgid "Could not initialize network, time out!" +msgstr "Netzwerk konnte nicht initialisiert werden, Zeit abgelaufen!" + +msgid "Could not open Disc" +msgstr "Disk konnte nicht geöffnet werden." + +msgid "Could not open the WiiTDB.xml file." +msgstr "WiiTDB.xml konnte nicht geöffnet werden." + +msgid "Could not open wiitdb.xml." +msgstr "Konnte wiitdb.xml nicht öffnen." + +msgid "Could not save." +msgstr "Es konnte nicht gespeichert werden." + +msgid "Could not write file." +msgstr "Konnte Datei nicht erstellen." + +msgid "Could not write to:" +msgstr "Konnte nicht schreiben zu:" + +msgid "Cover Download" +msgstr "Welche Cover herunterladen?" + +msgid "Create" +msgstr "Erstelle GCT" + +msgid "Credits" +msgstr "Danksagungen" + +msgid "Crop Overscan" +msgstr "Overscan abschneiden" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "Community Banner" + +msgid "Custom Paths" +msgstr "Community Pfade" + +msgid "Customs" +msgstr "Community" + +msgid "Customs/Original" +msgstr "Community/Original" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "Alternative DOL" + +msgid "Debug" +msgstr "Debug" + +msgid "Debug Wait" +msgstr "Debug Warten" + +msgid "Debugger Paused Start" +msgstr "Debugger paus. Start" + +msgid "Dec" +msgstr "Dezember" + +msgid "Default" +msgstr "Standard" + +msgid "Default Gamesettings" +msgstr "Spieleinstellungen zurücksetzen" + +msgid "Default Settings" +msgstr "Einstellungen zurücksetzen" + +msgid "Delete" +msgstr "Löschen" + +msgid "Delete Cached Banner" +msgstr "Lösche gecachte Banner" + +msgid "Delete Cheat GCT" +msgstr "Lösche GCT Cheatdatei" + +msgid "Delete Cheat TXT" +msgstr "Lösche TXT Cheatdatei" + +msgid "Delete Cover Artwork" +msgstr "Lösche Cover" + +msgid "Delete Disc Artwork" +msgstr "Lösche Disc Cover" + +msgid "Delete category" +msgstr "Lösche Kategorie" + +msgid "Deleting directories..." +msgstr "Lösche Verzeichnisse..." + +msgid "Deleting files..." +msgstr "Lösche Dateien..." + +msgid "Design:" +msgstr "Design:" + +msgid "Details" +msgstr "Details" + +msgid "Developed by" +msgstr "Entwickelt von" + +msgid "Developer:" +msgstr "Entwickler:" + +msgid "Devolution" +msgstr "Devolution" + +msgid "Devolution Loader Path" +msgstr "Devolution Loader" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "Devolution's loader.bin Datei kann nicht geladen werden." + +msgid "Directory does not exist!" +msgstr "Verzeichnis existiert nicht!" + +msgid "Disc 1" +msgstr "Disk 1" + +msgid "Disc 2" +msgstr "Disk 2" + +msgid "Disc Artwork Download" +msgstr "Disk Cover Download" + +msgid "Disc Artwork Path" +msgstr "Disk Cover" + +msgid "Disc Default" +msgstr "Diskstandard" + +msgid "Disc Insert Detected" +msgstr "Disk erkannt" + +msgid "Disc Read Delay" +msgstr "Disc Leseverzögerung" + +msgid "Disc read error." +msgstr "Disk Lesefehler" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "Disk 2 muss unkomprimiert sein, um mit DM(L) 2.6+ zu funktionieren. Sicher, dass du die Disk komprimiert installieren möchtest?" + +msgid "Discarts" +msgstr "Diskbilder" + +msgid "DiskFlip" +msgstr "DiskFlip" + +msgid "Display" +msgstr "Spielinfos anzeigen" + +msgid "Display as a carousel" +msgstr "Karussell-Ansicht" + +msgid "Display as a channel grid" +msgstr "Raster-Kanal-Ansicht" + +msgid "Display as a grid" +msgstr "Raster-Ansicht" + +msgid "Display as a list" +msgstr "Listen-Ansicht" + +msgid "Display favorites only" +msgstr "Zeige nur Favoriten" + +msgid "Do you want to apply it now?" +msgstr "Jetzt übernehmen?" + +msgid "Do you want to apply this theme?" +msgstr "Dieses Theme angewenden?" + +msgid "Do you want to change language?" +msgstr "Sprache ändern?" + +msgid "Do you want to continue with next game?" +msgstr "Mit nächstem Spiel weitermachen?" + +msgid "Do you want to copy now?" +msgstr "Soll jetzt kopiert werden?" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "Soll ein Spiel auf die SD kopiert oder davon gelöscht werden?" + +msgid "Do you want to delete a game on SD?" +msgstr "Soll ein Spiel von der SD gelöscht werden?" + +msgid "Do you want to discard changes?" +msgstr "Änderungen verwerfen?" + +msgid "Do you want to download this theme?" +msgstr "Dieses Theme herunterladen?" + +msgid "Do you want to extract all the save games?" +msgstr "Sollen alle Spielstände entpackt werden?" + +msgid "Do you want to extract the save game?" +msgstr "Soll der Spielstand entpackt werden?" + +msgid "Do you want to format:" +msgstr "Formatieren:" + +msgid "Do you want to install selected games?" +msgstr "Sollen gewählte Spiele instelliert werden?" + +msgid "Do you want to load the default theme?" +msgstr "Soll das DEFAULT Theme geladen werden?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "Netzwerk re-initialisieren?" + +msgid "Do you want to start the game now?" +msgstr "Soll ein neues Spiel gestartet werden?" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "Soll die freier Speicher Info auf allen Partitionen synchronisiert werden?" + +msgid "Do you wish to update/download all language files?" +msgstr "Alle Sprachdateien aktualisieren?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "Herunterladen" + +msgid "Download Now" +msgstr "Herunterladen" + +msgid "Download finished" +msgstr "Download abgeschlossen" + +msgid "Downloading 3D Covers" +msgstr "Lade 3D Cover herunter" + +msgid "Downloading Custom Banners" +msgstr "Lade Community Banner herunter" + +msgid "Downloading Flat Covers" +msgstr "Lade 2D Cover herunter" + +msgid "Downloading Full HQ Covers" +msgstr "Lade Box HQ Cover herunter" + +msgid "Downloading Full LQ Covers" +msgstr "Lade Box LQ Cover herunter" + +msgid "Downloading custom Discarts" +msgstr "Lade Community Diskcover herunter" + +msgid "Downloading file..." +msgstr "Lade Datei herunter..." + +msgid "Downloading image:" +msgstr "Lade Bilder herunter:" + +msgid "Downloading original Discarts" +msgstr "Lade Diskcover herunter" + +msgid "Downloading pagelist:" +msgstr "Lade Seitenliste herunter:" + +msgid "Dump NAND to EmuNand" +msgstr "Nand zu EmuNand dumpen" + +msgid "During zoom" +msgstr "Während des Zoomens" + +msgid "Dutch" +msgstr "Niederländisch" + +msgid "ERROR" +msgstr "FEHLER" + +msgid "ERROR:" +msgstr "FEHLER:" + +msgid "ERROR: Can't set up theme." +msgstr "FEHLER: Theme kann nicht eingerichtet werden." + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "EmuNand Kanäle" + +msgid "Emulated Nand" +msgstr "Emulierstes Nand" + +msgid "English" +msgstr "Englisch" + +msgid "Enter Path" +msgstr "Pfad eintragen" + +msgid "Error" +msgstr "Fehler" + +msgid "Error !" +msgstr "Fehler !" + +#, c-format +msgid "Error creating path: %s" +msgstr "Fehler Pfad anlegen: %s" + +msgid "Error opening downloaded file" +msgstr "Fehler beim Öffnen der heruntergeladenen Datei" + +msgid "Error reading Disc" +msgstr "Fehler beim Lesen der Disk" + +msgid "Error reading disc" +msgstr "Fehler beim Lesen der Disk" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "Fehler beim Dateidownload: %i" + +msgid "Error while downloding file" +msgstr "Fehler beim Dateidownload" + +msgid "Error while opening the zip." +msgstr "Fehler beim Öffnen der zip" + +msgid "Error while transfering data." +msgstr "Fehler während der Datenübertragung." + +msgid "Error while updating USB Loader GX." +msgstr "Fehler beim Update vom USB Loader GX" + +msgid "Error writing the data." +msgstr "Fehler beim Schreiben der Daten" + +msgid "Error:" +msgstr "Fehler:" + +msgid "Error: Not enough space on SD." +msgstr "Fehler: Nicht genug Speicher auf der SD." + +msgid "Errors occured." +msgstr "Fehler aufgetreten." + +msgid "Everything" +msgstr "Alles" + +msgid "Exit" +msgstr "Beenden" + +msgid "Exit to where?" +msgstr "Beenden zum..." + +msgid "Export All Saves to EmuNand" +msgstr "Export. Spielst. in EmuNand" + +msgid "Export Miis to EmuNand" +msgstr "Export. Miis in EmuNand" + +msgid "Export SYSCONF to EmuNand" +msgstr "Export. SYSCONF in EmuNand" + +msgid "Extract Miis to the Emu NAND?" +msgstr "Miis ins Emu NAND enpacken?" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "SYSCONF ins Emu NAND enpacken?" + +msgid "Extract Save to EmuNand" +msgstr "Spielstand in EmuNand kopieren" + +msgid "Extracting file:" +msgstr "Entpacke Datei:" + +msgid "Extracting files..." +msgstr "Entpacke Dateien..." + +msgid "Extracting files:" +msgstr "Entpacke Dateien:" + +msgid "Extracting nand files:" +msgstr "Extrahiere Nand Dateien:" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "Fehlgeschlagen" + +msgid "Failed copying file" +msgstr "Dateikopieren misslungen" + +msgid "Failed formating" +msgstr "Formatieren fehlgeschlagen" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "Fehler! Nicht alle Dateien entpackt. Spielstände existieren möglicherweise nicht." + +msgid "Failed to extract." +msgstr "Entpacken fehlgeschlagen." + +msgid "Failed to initialize the USB storage device." +msgstr "Fehler beim Initialisieren des USB-Gerätes." + +msgid "Failed to open partition" +msgstr "Öffnen der Partition fehlgeschlagen" + +msgid "Failed to read ticket." +msgstr "Fehler beim Lesen des Tickets." + +msgid "Failed to read tmd file." +msgstr "Fehler beim Lesen der tmd-Datei." + +msgid "Failed to read wad header." +msgstr "Fehler beim Lesen des Wad-Header Bereiches." + +msgid "Failed updating" +msgstr "Updaten fehlgeschlagen" + +msgid "Favorite Level" +msgstr "Favoriten Level" + +msgid "Features" +msgstr "Features" + +msgid "Features Settings" +msgstr "Features Optionen" + +msgid "Feb" +msgstr "Februar" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Datei nicht gefunden." + +msgid "File read/write error." +msgstr "Fehler beim Lesen/Schreiben der Datei." + +msgid "Files extracted successfully." +msgstr "Dateien erfolgreich entpackt." + +#, c-format +msgid "Filesize is %i Byte." +msgstr "Dateigröße ist %i Byte" + +msgid "Filesize is 0 Byte." +msgstr "Dateigröße ist 0 Byte" + +msgid "Flat Covers" +msgstr "2D Cover" + +msgid "Flip-X" +msgstr "Flip-X" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "Schrift-Skalierwert" + +msgid "Force 16:9" +msgstr "Erzw. 16:9" + +msgid "Force 4:3" +msgstr "Erzw. 4:3" + +msgid "Force NTSC" +msgstr "NTSC erzw." + +msgid "Force NTSC480p" +msgstr "NTSC480p erzw." + +msgid "Force PAL480p" +msgstr "PAL480p erzw." + +msgid "Force PAL50" +msgstr "PAL50 erzw." + +msgid "Force PAL60" +msgstr "PAL60 erzw." + +msgid "Force Titles from Disc" +msgstr "Erzwinge DVD-Titel" + +msgid "Force Widescreen" +msgstr "Erzwinge Widescreen" + +msgid "Format" +msgstr "Formatieren" + +msgid "Formatting, please wait..." +msgstr "Formatiere, bitte warten..." + +msgid "Found missing images." +msgstr "Fehlende Bilder gefunden." + +msgid "Frame" +msgstr "Frame" + +msgid "Frame Projection Height" +msgstr "Frame Projektionshöhe" + +msgid "Frame Projection Width" +msgstr "Frame Projektionsbreite" + +msgid "Frame Projection X-Offset" +msgstr "Frame Projektions-X-Offset" + +msgid "Frame Projection Y-Offset" +msgstr "Frame Projektions-Y-Offset" + +msgid "Frames" +msgstr "Frames" + +msgid "Free Space" +msgstr "Freier Speicher" + +msgid "French" +msgstr "Französisch" + +msgid "Full" +msgstr "Vollständig" + +msgid "Full Cover Path" +msgstr "Box Cover" + +msgid "Full Covers" +msgstr "Box Cover" + +msgid "Full Menu" +msgstr "Ganzes Menü" + +msgid "Full covers Download" +msgstr "Box Cover Download" + +msgid "Full shutdown" +msgstr "Ausschalten" + +msgid "GAMEID_Gamename" +msgstr "SPIELID_Spielname" + +msgid "GC Banner Scale" +msgstr "GC Banner Skalierung" + +msgid "GC Games" +msgstr "GC Spiele" + +msgid "GC Install 32K Aligned" +msgstr "GC Inst. 32K-aligned" + +msgid "GC Install Compressed" +msgstr "GC Installiere gepackt" + +msgid "GCT Cheatcodes Path" +msgstr "GCT Cheatdateien" + +msgid "GCT File created" +msgstr "GCT Datei erstellt" + +msgid "GUI Settings" +msgstr "GUI Einstellungen" + +msgid "GXDraw" +msgstr "GXDraw" + +msgid "GXFlush" +msgstr "GXFlush" + +msgid "Game Cube Games Delete" +msgstr "Game Cube Spiele Löschen" + +msgid "Game Cube Install Menu" +msgstr "Game Cube Installationsmenü" + +msgid "Game ID" +msgstr "Spiel ID" + +msgid "Game IOS" +msgstr "Spiel IOS" + +msgid "Game Language" +msgstr "Sprache" + +msgid "Game Load" +msgstr "Spieleinstellungen" + +msgid "Game Lock" +msgstr "Spielsprerre" + +msgid "Game Only" +msgstr "Nur Spiel" + +msgid "Game Region" +msgstr "Region" + +msgid "Game Size" +msgstr "Größe" + +msgid "Game Sound Mode" +msgstr "Banner Modus" + +msgid "Game Sound Volume" +msgstr "Banner Lautstärke" + +msgid "Game Split Size" +msgstr "Spiel Split Größe" + +msgid "Game Window Mode" +msgstr "Spiele Fenstermodus" + +msgid "Game is already installed:" +msgstr "Spiel ist bereits installiert:" + +msgid "Game's IOS" +msgstr "Spiel IOS" + +msgid "Game/Install Partition" +msgstr "Spiel/Instal. Partition" + +msgid "GameCube" +msgstr "GameCube" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "GameCube Modus" + +msgid "GameCube Source" +msgstr "GameCube Quelle" + +msgid "Gamename [GAMEID]" +msgstr "Spielname [SPIELID]" + +msgid "Games" +msgstr "Spiele" + +msgid "Generating GXGameCategories.xml" +msgstr "Generiere GXGameCategories.xml" + +msgid "Genre:" +msgstr "Genre:" + +msgid "German" +msgstr "Deutsch" + +msgid "Getting file list..." +msgstr "Ermittle Dateiliste..." + +msgid "Getting game folder size..." +msgstr "Ermittle Spielordnergröße" + +msgid "Global Settings" +msgstr "Globale Einstellungen" + +msgid "Grid Scroll Speed" +msgstr "Raster Scrollgeschwindigkeit" + +msgid "HOME Menu" +msgstr "HOME Menü" + +msgid "Hard Drive Settings" +msgstr "Festplatten Optionen" + +msgid "High Quality" +msgstr "Hohe Qualität" + +msgid "High/Low" +msgstr "Hoch/Niedrig" + +msgid "Homebrew Apps Path" +msgstr "Homebrew Apps" + +msgid "Homebrew Channel" +msgstr "Homebrew Kanal" + +msgid "Homebrew Launcher" +msgstr "Homebrew Starter" + +msgid "Hooktype" +msgstr "Hooktype" + +msgid "Hour" +msgstr "Stunden" + +msgid "How do you want to update?" +msgstr "Was soll aktualisiert werden?" + +msgid "How to Shutdown?" +msgstr "Wie soll ausgeschaltet werden?" + +msgid "Import Categories" +msgstr "Importiere Kategorien" + +msgid "Import operation successfully completed." +msgstr "Import erfolgreich." + +msgid "Importing categories" +msgstr "Importiere Kategorien" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Eingehende Datei %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Eingehende Datei %0.2fMB" + +msgid "Individual" +msgstr "Individuell" + +msgid "Initializing Network" +msgstr "Initialisiere Netzwerk" + +msgid "Insert Disk" +msgstr "Disk einlegen" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "Eine Wii oder GameCube Disk einlegen!" + +msgid "Install" +msgstr "Installieren" + +msgid "Install Canceled" +msgstr "Installation abgebrochen" + +msgid "Install Directories" +msgstr "Installationsart" + +msgid "Install Error!" +msgstr "Installationsfehler!" + +msgid "Install Partitions" +msgstr "Inst. Partitionen" + +msgid "Install a game" +msgstr "Spiel installieren" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "Installation beendet" + +msgid "Installing Game Cube Game..." +msgstr "Installiere Game Cube Spiel..." + +msgid "Installing content" +msgstr "Installiere Inhalt" + +msgid "Installing game:" +msgstr "Installiere Spiel:" + +msgid "Installing title..." +msgstr "Installiere Titel..." + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "Üngültige IOS Nummer eingetragen. Nummer muss -1 zum Erben oder 200 - 255 sein." + +msgid "Invalid wad file." +msgstr "Ungültige Wad-Datei." + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Es scheint als ob du Informationen hast, die hilfreich für uns sein könnten. Bitte sende diese Information ans DEV Team." + +msgid "Italian" +msgstr "Italienisch" + +msgid "Jan" +msgstr "Januar" + +msgid "Japanese" +msgstr "Japanisch" + +msgid "Japanese Patch" +msgstr "Japanisch Patch" + +msgid "Joypad" +msgstr "Gamepad" + +msgid "July" +msgstr "Juli" + +msgid "June" +msgstr "Juni" + +msgid "KPAD Read" +msgstr "KPAD Lesen" + +msgid "Keyboard" +msgstr "Tastatur" + +msgid "Korean" +msgstr "Koreanisch" + +msgid "LED Activity" +msgstr "Laufwerk LED" + +msgid "Language Files" +msgstr "Sprachdateien" + +msgid "Language change:" +msgstr "Sprache ändern:" + +msgid "Languagefiles Path" +msgstr "Sprachdateien" + +msgid "Languagepath changed." +msgstr "Pfad geändert" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Wii Spiele im emulierten NAND funktionieren nur mit d2x cIOS! Ändere das Spiel IOS zu einem d2x cIOS." + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Das Aufrufen von EmuNand-Kanälen funktioniert nur mit dem d2x cIOS! Wechsele dein Spiele-IOS zu einem d2x cIOS zuerst." + +msgid "Left" +msgstr "Links" + +msgid "Like SysMenu" +msgstr "System Menü" + +msgid "List on Gamelaunch" +msgstr "Auflisten beim Spielstart" + +msgid "Load" +msgstr "Laden" + +msgid "Load From SD/USB" +msgstr "Von SD/USB laden" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Datei von %s laden?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Diese DOL als Alternative DOL laden?" + +msgid "Loader Settings" +msgstr "Loader Einstellungen" + +msgid "Loader's IOS" +msgstr "Loader IOS" + +msgid "Loading standard language." +msgstr "Lade Standardsprache." + +msgid "Loading standard music." +msgstr "Lade Standardmusik." + +msgid "Lock Console" +msgstr "Konsole sperren" + +msgid "Lock USB Loader GX" +msgstr "Sperre USB Loader GX" + +msgid "Locked" +msgstr "Gesperrt" + +msgid "Log to file" +msgstr "Debug Log" + +msgid "Loop Directory" +msgstr "Verzeichnis wiederholen" + +msgid "Loop Music" +msgstr "Wiederholung" + +msgid "Loop Sound" +msgstr "Wiederholung" + +msgid "Low Quality" +msgstr "Niedrige Qualität" + +msgid "Low/High" +msgstr "Niedrig/Hoch" + +msgid "MIOS (Default & Customs)" +msgstr "MIOS (Standard & Angepasste)" + +msgid "Main DOL" +msgstr "Haupt-DOL" + +msgid "Main GameCube Games Path" +msgstr "GameCube Spiele" + +msgid "Main GameCube Path" +msgstr "GameCube" + +msgid "Main Path" +msgstr "Haupt Pfad" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "März" + +msgid "Mark new games" +msgstr "Neue Spiele mark." + +msgid "May" +msgstr "Mai" + +msgid "Memory Card Blocks Size" +msgstr "Memory Card Blockgröße" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "Forum Update" + +msgid "Motion+ Video" +msgstr "Motion+ Video" + +msgid "Mount DVD drive" +msgstr "Spiel starten" + +msgid "Mount USB at launch" +msgstr "USB beim Start mounten" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "Mehrere Partitionen" + +msgid "Music Loop Mode" +msgstr "HGM Wiederholung" + +msgid "Music Volume" +msgstr "Musik Lautstärke" + +msgid "NMM Mode" +msgstr "NMM Modus" + +msgid "Nand Chan. Emulation" +msgstr "Nand Kan. Emulation" + +msgid "Nand Channels" +msgstr "Nand Kanäle" + +msgid "Nand Emu Channel Path" +msgstr "Nand Emu-Kanal" + +msgid "Nand Emu Path" +msgstr "Nand Emu" + +msgid "Nand Emulation" +msgstr "Nand Emulation" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "Nand Emulation ist nur für D2X cIOS verfügbar!" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "Nand Emulation funktionier nut mit FAT/FAT32 Partitionen!" + +msgid "Nand Saves Emulation" +msgstr "Nand Save-Emulation" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Keine" + +msgid "Network is not initiated." +msgstr "Netzwerk wurde nicht initialisiert." + +msgid "Next" +msgstr "Weiter" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "Nintendont Loader Pfad" + +msgid "No" +msgstr "Nein" + +msgid "No Cheatfile found" +msgstr "Keine Cheatdatei gefunden." + +msgid "No DOL file found on disc." +msgstr "Keine DOL auf der Disk gefunden." + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "Nicht teilen" + +msgid "No URL or Path specified." +msgstr "Keine URL oder kein Pfad spezifiziert" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "Keine WBFS oder FAT/NTFS/EXT Partition vorhanden" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "Es wurde keine Wiinnertag.xml im Konfigurationspfad gefunden. Soll eine Beispieldatei angelegt werden?" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "Es wurden keine Cheats ausgewählt. Soll die GCT Datei gelöscht werden?" + +msgid "No data could be read." +msgstr "Daten konnten nicht gelesen werden." + +msgid "No disc inserted." +msgstr "Keine DVD eingelegt" + +msgid "No favorites selected." +msgstr "Keine Favoriten ausgewählt" + +msgid "No file missing!" +msgstr "Keine Datei fehlt!" + +msgid "No games found on the disc" +msgstr "Keine Spiele auf der Disk gefunden" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "Auf den Geräten wurden keine Sprachdateien zum Aktualisieren gefunden! Sollen neue Sprachdateien heruntergeladen werden?" + +msgid "No new updates." +msgstr "Keine Updates verfügbar." + +msgid "No themes found on the site." +msgstr "Keine Themes auf der Seite gefunden." + +msgid "No themes found." +msgstr "Keine Themes gefunden." + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "Nur NoSSL" + +msgid "None" +msgstr "Keine" + +msgid "Normal" +msgstr "Normal (4:3)" + +msgid "Not Initialized" +msgstr "Nicht initialisiert" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "Keine Wii oder GameCube Disk." + +msgid "Not a valid URL" +msgstr "Keine gültige URL" + +msgid "Not a valid URL path" +msgstr "Kein gültiger URL Pfad" + +msgid "Not a valid domain" +msgstr "Keine gültige Domain" + +msgid "Not enough free memory." +msgstr "Nicht genügend freier Speicher." + +msgid "Not enough free space on device." +msgstr "Nicht genug Freier Speicher auf dem Gerät." + +msgid "Not enough free space!" +msgstr "Nicht genügend freier Speicher!" + +msgid "Not enough memory for FST." +msgstr "Nicht genug freier Speicher für FST." + +msgid "Not enough memory." +msgstr "Nicht genug Speicher." + +msgid "Not required" +msgstr "Nicht benötigt" + +msgid "Not supported format!" +msgstr "Nicht unterstütztes Format!" + +msgid "Nothing selected to delete." +msgstr "Nichts gewählt zum Löschen." + +msgid "Nothing selected to install." +msgstr "Nichts gewählt zum Installieren." + +msgid "Nov" +msgstr "November" + +msgid "OFF" +msgstr "AUS" + +msgid "OK" +msgstr "OK" + +msgid "ON" +msgstr "AN" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "OSSleepThread" + +msgid "Ocarina" +msgstr "Ocarina (Cheats)" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Oktober" + +msgid "Official Site:" +msgstr "Offizielle Seite:" + +msgid "Offset" +msgstr "Offset" + +msgid "Ok" +msgstr "OK" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "Nur Spiele Partition" + +msgid "Only for Install" +msgstr "Nur beim Installieren" + +msgid "Original" +msgstr "Original" + +msgid "Original/Customs" +msgstr "Original/Community" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Altersbeschränkung" + +msgid "Partial" +msgstr "Teilweise" + +msgid "Partition" +msgstr "Partition" + +msgid "Password" +msgstr "Passwort" + +msgid "Password Changed" +msgstr "Passwort geändert" + +msgid "Password has been changed" +msgstr "Passwort wurde geändert" + +msgid "Patch Country Strings" +msgstr "Ländercode patchen" + +msgid "Path Changed" +msgstr "Pfad geändert" + +msgid "Permission denied." +msgstr "Erlaubnis verweigert" + +msgid "Pick from a list" +msgstr "Wähle aus der Liste" + +msgid "Pixels" +msgstr "Pixel" + +msgid "Play Count" +msgstr "Spielzähler" + +msgid "Play Next" +msgstr "Nächster Titel" + +msgid "Play Once" +msgstr "Einmal abspielen" + +msgid "Play Previous" +msgstr "Vorheriger Titel" + +msgid "Playing Music:" +msgstr "Aktuelle Musik:" + +msgid "Please wait" +msgstr "Bitte warten" + +msgid "Please wait..." +msgstr "Bitte warten..." + +msgid "Power off the Wii" +msgstr "Wii ausschalten" + +msgid "Prev" +msgstr "Zurück" + +msgid "Private Server" +msgstr "Privater Server" + +msgid "Process finished." +msgstr "Vorgang abgeschlossen." + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Anzeige" + +msgid "Published by" +msgstr "Veröffentlicht von" + +msgid "Quick Boot" +msgstr "Schnelles Laden" + +msgid "Random Directory Music" +msgstr "Zufällig" + +msgid "Real Nand" +msgstr "Echtes Nand" + +msgid "Receiving file from:" +msgstr "Empfange Datei von:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "Region Patch" + +msgid "Released" +msgstr "Erschienen am" + +msgid "Reload SD" +msgstr "SD Karte neuladen" + +msgid "Reloading game list now, please wait..." +msgstr "Aktualisiere Spieleliste, bitte warten..." + +msgid "Remember Unlock" +msgstr "Entsperrung behalten" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "Update entfernen" + +msgid "Rename Game Title" +msgstr "Spiel umbenennen" + +msgid "Rename category" +msgstr "Kategorie umbenennen" + +msgid "Reset" +msgstr "Zurücksetzen" + +msgid "Reset BG Music" +msgstr "Musik zurücksetzen" + +msgid "Reset Playcounter" +msgstr "Spielzähler zurücksetzen" + +msgid "Reset to default BGM?" +msgstr "Zur standard Musik resetten?" + +msgid "Restarting..." +msgstr "Starte neu..." + +msgid "Return" +msgstr "Zurück" + +msgid "Return To" +msgstr "Zurück zu" + +msgid "Return to Wii Menu" +msgstr "Zurück zum Wii Menü" + +msgid "Right" +msgstr "Rechts" + +msgid "Rotating Disc" +msgstr "Rotierende Disk" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Rumble" + +msgid "SChinese" +msgstr "Vereinfachtes Chinesisch" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "Auf die SD konnte nicht zugegriffen werden." + +msgid "SD GameCube Games Path" +msgstr "SD GameCube Spiele" + +msgid "SD GameCube Path" +msgstr "SD GameCube" + +msgid "SD Path" +msgstr "SD" + +msgid "SFX Volume" +msgstr "SFX Lautstärke" + +msgid "Save" +msgstr "Speichern" + +msgid "Save Failed. No device inserted?" +msgstr "Speichern fehlgeschlagen. Kein Gerät eingefügt?" + +msgid "Save Game List to" +msgstr "Liste speichern unter" + +msgid "Save List" +msgstr "Speichere Liste" + +msgid "Saved" +msgstr "Gespeichert" + +msgid "Savegame might not exist for this game." +msgstr "Möglicherweise existiert kein Spielstand für dieses Spiel." + +msgid "Screensaver" +msgstr "Bildschirmschoner" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "Auswählen" + +msgid "Select DOL Offset" +msgstr "Wähle DOL Offset" + +msgid "Select a DOL" +msgstr "Wähle eine DOL" + +msgid "Select a DOL from Game" +msgstr "Wähle eine DOL vom Spiel" + +msgid "Select game categories" +msgstr "Wähle Spiele-Kategorien" + +msgid "Select loader mode" +msgstr "Wähle Loader-Modus" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "Wähle Titelquelle(n)" + +msgid "Sept" +msgstr "September" + +msgid "Set Search-Filter" +msgstr "Setze Suchfilter" + +msgid "Settings" +msgstr "Einstellungen" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "Zeige Kategorien" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "Zeige frei. Speicher" + +msgid "Show Play Count" +msgstr "Zeige Spielzähler" + +msgid "Show SD" +msgstr "Zeige SD" + +msgid "Shutdown System" +msgstr "System herunterfahren" + +msgid "Shutdown Wii" +msgstr "Wii ausschalten" + +msgid "Skip Errors" +msgstr "Fehler überspringen" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "Sneek Video Patch" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Alphabetisch ordnen" + +msgid "Sort by number of players" +msgstr "Sortiere nach Spielerzahl" + +msgid "Sort by rank" +msgstr "Nach Bewertungen ordnen" + +msgid "Sort order by most played" +msgstr "Nach Spielzähler ordnen" + +msgid "Sound" +msgstr "Ton" + +msgid "Sound Settings" +msgstr "Ton Einstellungen" + +msgid "Sound+BGM" +msgstr "mit Hintergrundmusik" + +msgid "Sound+Quiet" +msgstr "ohne Hintergrundmusik" + +msgid "Spanish" +msgstr "Spanisch" + +msgid "Special thanks to:" +msgstr "Besonderen Dank an:" + +msgid "Split each 2GB" +msgstr "Teile alle 2GB" + +msgid "Split each 4GB" +msgstr "Teile alle 4GB" + +msgid "Standby" +msgstr "Standby" + +msgid "Start" +msgstr "Start" + +msgid "Success" +msgstr "Erfolgreich" + +msgid "Success." +msgstr "Erfolg." + +msgid "Success:" +msgstr "Erfolg:" + +msgid "Successfully Saved" +msgstr "Erfolgreich gespeichert" + +msgid "Successfully Updated" +msgstr "Erfolgreich aktualisiert" + +msgid "Successfully copied" +msgstr "Erfolgreich kopiert" + +msgid "Successfully deleted:" +msgstr "Erfolgreich gelöscht:" + +msgid "Successfully extracted theme." +msgstr "Theme erfolgreich entpackt." + +msgid "Successfully installed:" +msgstr "Erfolgreich installiert:" + +msgid "Successfully updated." +msgstr "Update erfolgreich." + +msgid "Switching to channel list mode." +msgstr "Zum Kanallisten-Modus schalten." + +msgid "Sync FAT32 FS Info" +msgstr "Sync. FAT32 FS Info" + +msgid "Synchronizing..." +msgstr "Synchronisiere..." + +msgid "System Default" +msgstr "Konsolenstandard" + +msgid "TChinese" +msgstr "Traditionelles Chinesisch" + +msgid "TXT Cheatcodes Path" +msgstr "TXT Cheatdateien" + +msgid "The .them file was not found in the zip." +msgstr "Die .them Datei wurde in der zip nicht gefunden." + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "Die Einstellung -Breitbild erzw.- erforder DIOS MIOS v2.1 und neuer. Diese Einstellungen wird ignoriert." + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Die Miis werden in den EmuNand Pfad und EmuNand Kanal-Pfad kopiert. Achtung: Alle vorhandenen Dateien werden überschrieben." + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "Die -keine Disk+ Einstellung- benötigt DIOS MIOS 2.2 update2. Diese Einstellung wird ignoriert." + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Die SYSCONF wird in den EmuNand Pfad und EmuNand Kanal-Pfad kopiert. Achtung: Alle vorhandenen Dateien werden überschrieben." + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "Die Anwendung könnte Abstürzen, wenn bereits ein Lese/Schreib Prozess auf die SD Karte zugreift!" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "Das eingegebene Verzeichnis existiert nicht. Möchtest du es erstellen?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "Datein werden in den EmuNand Speicher- und Kanal-Pfad kopiert. Achtung: Alle vorhandenen Dateien werden überschrieben." + +msgid "The game is on SD Card." +msgstr "Das Spiel ist auf der SD-Karte." + +msgid "The game is on USB." +msgstr "Das Spiel befindet sich auf USB." + +msgid "The save game will be extracted to your emu nand path." +msgstr "Der Spielstand wird in den EmuNand Pfad kopiert." + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "Die Spielstände werden zum EmuNand Speicher- und Kanal-Pfad entpackt. Achtung: Alle vorhandenen Spielstände werden überschrieben." + +msgid "The wad file was installed" +msgstr "Die Wad Datei wurde installiert" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "Die Wad installation schlug fehl mit dem Fehler %i" + +msgid "Theme Downloader" +msgstr "Theme Downloader" + +msgid "Theme Menu" +msgstr "Theme Menü" + +msgid "Theme Path" +msgstr "Theme" + +msgid "Theme Title:" +msgstr "Name:" + +msgid "Themes by www.spiffy360.com" +msgstr "Themes von www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "Dieses IOS ist das BootMii IOS. Solltest du sicher sein, dass es nicht das BootMii IOS ist und du dort etwas anderes installiert hast, ignoriere diese Warnung." + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "Dieses IOS wurde nicht in der Titelliste gefunden. Wenn du sicher bist es installiert zu haben, ignoriere die Warnung." + +msgid "This Nintendont version does not support games on USB." +msgstr "Diese Nintendont Version unterstützt USB nicht." + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "Dieses Spiel hat mehrere Disks. Bitte wähle, welche Disk gestartet werden soll." + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "Dieser Pfad muss auf der SD sein!" + +msgid "Time left:" +msgstr "Noch:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Channel Launcher" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "Namen aus der WiiTDB" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "Um GameCube Spiele von DVD zu starten, muss der GameCube Modus in den Spieleinstellungen auf MIOS gesetzt werden." + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "Deine Festplatte muss auf FAT32 formatiert sein, um GameCube Spiele mit %s% starten zu können." + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "Dein GameCube Hauptpfad muss auf eine FAT32 formatierte Festplatte verweisen, um GameCube Spiele mit %s% starten zu können." + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "Dein Festplatte muss 512 Bytes Sektorgröße haben, um GameCube Spiele mit %s% starten zu können." + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "Dein Festplatte muss 32 Kilobytes Clustergröße oder weniger haben, um GameCube Spiele mit %s% starten zu können." + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "Deine loader.bin Datei muss im Devolution Loader Pfad liegen, um GameCube Spiele mit Devolution starten zu können." + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "Deine boot.dol Datei muss im Nintendont Loader Pfad liegen, um GameCube Spiele mit Nintendont starten zu können." + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "Um %s mit HID zu verwenden, wird %s benötig." + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "Um Ocarina Cheats mit %s zu verwenden, wird %s benötigt." + +msgid "Tooltip Delay" +msgstr "Tooltip Verzögerung" + +msgid "Tooltips" +msgstr "Quickinfo" + +msgid "Transfer failed" +msgstr "Transfer fehlgeschlagen" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "USB Gerät nicht initialisiert." + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX ist jetzt geschützt." + +msgid "USB Port" +msgstr "USB Port" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "USB-Portwechsel wird nur vom Hermes cIOS unterstützt." + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "USBLoaderGX konnte die Nintendont boot.dol nicht verifizieren. Trotzdem starten?" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "USBLoaderGX konnte die Nintendont config Dateien nicht ändern. Nintendont trotzdem starten?" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "USBLoaderGX r1218 wird benötigt um Nintendont Alpha v0.1 starten zu können. Bitte aktualisiere deine Nintendont Version." + +msgid "Uninstall" +msgstr "Deinstallieren" + +msgid "Uninstall Game" +msgstr "Spiel deinstallieren" + +msgid "Uninstall Menu" +msgstr "Deinstallationsmenü" + +msgid "Uninstall all" +msgstr "Alles deinstallieren" + +msgid "Unknown" +msgstr "Unbekannt" + +msgid "Unlock USB Loader GX" +msgstr "Entsperre USB Loader GX" + +msgid "Unlocked" +msgstr "Entsperrt" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "Nichtunterstütztes Format, versuche die TempTheme.zip manuell zu entpacken." + +msgid "Update" +msgstr "Update" + +msgid "Update All" +msgstr "Alles Updaten" + +msgid "Update DOL" +msgstr "Nur DOL" + +msgid "Update Files" +msgstr "Aktualisieren" + +msgid "Update Path" +msgstr "Updates" + +msgid "Update all Language Files" +msgstr "Sprachdateien aktualisieren" + +msgid "Update failed" +msgstr "Update fehlgeschlagen" + +msgid "Update successfull" +msgstr "Update erfolgreich" + +msgid "Updating Language Files:" +msgstr "Aktualisiere Sprachdateien:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Die hochgeladene ZIP Datei wurde ins Homebrew Verzeichnis installiert." + +msgid "Use System Font" +msgstr "Wii-Systemschriftart" + +msgid "Use global" +msgstr "Benutze global" + +msgid "VBI (Default)" +msgstr "VBI (Standard)" + +msgid "VIDTV Patch" +msgstr "VIDTV Patch" + +msgid "Version:" +msgstr "Version:" + +#, c-format +msgid "Version: %s" +msgstr "Version: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Videomodus" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "Pointergeschwindigkeit" + +msgid "WDM Files Path" +msgstr "WDM Dateien" + +msgid "WIP Patches Path" +msgstr "WIP Patches" + +msgid "Waiting..." +msgstr "Warte..." + +msgid "Warning" +msgstr "Warnung" + +msgid "Warning:" +msgstr "Warnung:" + +msgid "What do you want to do?" +msgstr "Was soll gemacht werden?" + +msgid "What do you want to update?" +msgstr "Was möchtest du aktualisieren?" + +msgid "What should be deleted for this game title:" +msgstr "Was sollte bei diesem Spiel gelöscht werden:" + +msgid "What to extract from NAND?" +msgstr "Was soll aus dem NAND kopiert werden?" + +msgid "Where should the game be installed to?" +msgstr "Wohin soll das Spiel installiert werden?" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "WiFi Fähigkeiten" + +msgid "Widescreen Factor" +msgstr "Breitbildwert" + +msgid "Widescreen Fix" +msgstr "Breitbild (16:9)" + +msgid "Wii Games" +msgstr "Wii Spiele" + +msgid "Wii Menu" +msgstr "Wii Menü" + +msgid "Wii Settings" +msgstr "Wii Datenverwaltung" + +msgid "WiiTDB.xml" +msgstr "WiiTDB.xml" + +msgid "WiiTDB.xml is up to date." +msgstr "WiiTDB.xml ist aktuell." + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "Wii-Laufwerkslicht" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "Wiinnertag" + +msgid "Wiinnertag Path" +msgstr "Wiinertag" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Wiinnertag braucht eine aktivierte Netzwerkverbindung beim Start der Anwendung. Soll diese jetzt aktiviert werden?" + +msgid "Wiird Debugger" +msgstr "Wiird Debugger" + +#, c-format +msgid "Write error on file: %s" +msgstr "Fehler beim Schreiben der Datei: %s" + +msgid "Writing GXGameCategories.xml" +msgstr "Schreibe GXGameCategories.xml" + +msgid "Wrong Password" +msgstr "Falsches Passwort" + +msgid "Yes" +msgstr "Ja" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "Es wird versucht eine FAT32/NTFS/EXT Partition mit dem cIOS 249 Rev < 18 auszuwählen. Das wird nicht unterstützt. Weiter auf eigene Gefahr." + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "Du kannst eine Partition auswählen oder formatieren oder den Kanal-Loader-Modus benutzen." + +msgid "You cannot delete this category." +msgstr "Kategorie kann nicht gelöscht werden." + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "Es wird DIOS MIOS Lite v1.2 oder neuer benötigt." + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "Du musst einen GameCube Loader installieren oder einen anderen GameCube Modus auswählen um GameCube Spiele von USB oder SD starten zu können." + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "Zoom Dauer" + +msgid "and translators for language files updates" +msgstr "und Übersetzer für Sprachdateien Updates" + +msgid "available" +msgstr "verfügbar" + +msgid "does not exist!" +msgstr "existiert nicht!" + +msgid "does not exist! Loading game without cheats." +msgstr "existiert nicht! Spiel wird ohne Cheats gestartet." + +msgid "files left" +msgstr "Dateien fehlen" + +msgid "for FAT/NTFS support" +msgstr "für den FAT/NTFS Support" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "für GameTDB und gehostete Cover / DVD Bilder" + +msgid "for Ocarina" +msgstr "für Ocarina" + +msgid "for diverse patches" +msgstr "für diverse Patches" + +msgid "for his awesome tool LibWiiGui" +msgstr "für sein großartiges Tool LibWiiGui" + +msgid "for hosting the themes" +msgstr "für das Hosten der Themes" + +msgid "for the USB Loader source" +msgstr "für die Veröffentlichung des USB Loader-Quellcodes" + +msgid "for their work on the wiki page" +msgstr "für ihre Arbeit an der Wiki Seite" + +msgid "formatted!" +msgstr "formatiert!" + +msgid "free" +msgstr "frei" + +msgid "ms" +msgstr "ms" + +msgid "not set" +msgstr "Nicht gesetzt" + +msgid "of" +msgstr "von" + +msgid "seconds left" +msgstr "Sekunden verbleiben" + +#~ msgid "Do you want to update this file?" +#~ msgstr "Diese Datei updaten?" + +#~ msgid "Install WAD to EmuNand" +#~ msgstr "Install. WAD in EmuNand" + +#~ msgid "Update Nintendont" +#~ msgstr "Aktualisiere Nintendont" + +#~ msgid "WAD Installation" +#~ msgstr "WAD-Installation" + +#~ msgid "GameTDB Path" +#~ msgstr "GameTDB" + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on a primary partition." +#~ msgstr "Dein GameCube Hauptpfad muss auf eine primäre Partition verweisen, um GameCube Spiele mit %s% starten zu können." + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first partition of the Hard Drive." +#~ msgstr "Dein GameCube Hauptpfad muss auf die erste Partition deiner Festplatte verweisen, um GameCube Spiele mit %s% starten zu können." + +#~ msgid "Anti" +#~ msgstr "Anti" + +#~ msgid "Error 002 fix" +#~ msgstr "Fehler 002 fix" + +#~ msgid "Use Game Settings" +#~ msgstr "Spiele Einst. ben." + +#~ msgid "Main tester:" +#~ msgstr "Haupttester:" + +#~ msgid "USB Device not found." +#~ msgstr "USB-Gerät nicht gefunden." + +#~ msgid "Boot/Standard" +#~ msgstr "Bootstandard (cIOS)" + +#~ msgid "DEVO LED Activity" +#~ msgstr "DEVO LED Aktivität" + +#~ msgid "DEVO MemCard Emulation" +#~ msgstr "DEVO MemCard Emulation" + +#~ msgid "DML Auto" +#~ msgstr "DML Auto" + +#~ msgid "DML Debug" +#~ msgstr "DML Debug" + +#~ msgid "DML Force Widescreen" +#~ msgstr "DML Breitbild erzw." + +#~ msgid "DML Japanese Patch" +#~ msgstr "DML JAP Patch" + +#~ msgid "DML LED Activity" +#~ msgstr "DML LED Aktivität" + +#~ msgid "DML NMM Mode" +#~ msgstr "DML NMM Modus" + +#~ msgid "DML No Disc+" +#~ msgstr "DML Keine Disk+" + +#~ msgid "DML None" +#~ msgstr "DML Nichts" + +#~ msgid "DML PAD Hook" +#~ msgstr "DML PAD Hook" + +#~ msgid "DML Progressive Patch" +#~ msgstr "DML Progressive Patch" + +#~ msgid "DML Video Mode" +#~ msgstr "DML Video Modus" + +#~ msgid "To run GameCube games with DIOS MIOS you need to place them on an USB FAT32 partition." +#~ msgstr "Um GameCube Spiele mit DIOS MIOS zu spielen, müssen sie sich auf einer USB FAT32 Partition befinden." + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' to an USB FAT32 partition." +#~ msgstr "Um GameCube-Spiele mit DIOS MIOS zu spielen, muss der 'GemeCube Hauptpfad' auf eine USB FAT32 Partition zeigen." + +#~ msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Path." +#~ msgstr "Um GameCube Spiele mit Devolution zu starten, muss sich die loader.bin Datei in Devolution Pfad befinden." + +#~ msgid "You need to install Devolution or DIOS MIOS (Lite) to launch GameCube games from USB or SD card" +#~ msgstr "Um GameCube Spiele von USB oder SD abzuspielen, wird Devolution oder DIOS MIOS (Lite)" + +#~ msgid "DML No Disc" +#~ msgstr "DML Keine Disk" + +#~ msgid "The No Disc setting is not used anymore by DIOS MIOS (Lite). Now you need to place a disc in your drive." +#~ msgstr "Die -keine Disk Einstellung- wird nicht mehr unterstützt von DIOS MIOS (Lite). Jetzt muss eine Disk im Laufwerk sein." + +#~ msgid "The GCT Cheatcodes Path and this game are not on the same partition. Run the game without Ocarina?" +#~ msgstr "Der GCT Cheatcodes Pfad und dieses Spiel sind nicht auf der selben Partition. Spiel ohne Ocarina starten?" + +#~ msgid "The GCT Cheatcodes Path must be on SD card. Run the game without Ocarina?" +#~ msgstr "Der GCT Cheatcodes Pfad muss auf der SD-Karte sein. Spiel ohne Ocarina starten?" + +#~ msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2 or a newer version. This setting will be ignored." +#~ msgstr "Die Keine Disk+ Einstellung benötigt DIOS MIOS 2.2 update2 oder neuer. Diese Einstellung wird ignoriert." + +#~ msgid "DML Installed Version" +#~ msgstr "Installierte DML Version" + +#~ msgid "The Force Widescreen setting requires DIOS MIOS v2.2 or more. This setting will be ignored." +#~ msgstr "Die Einstellung -Breitbild erzw.- erforder DIOS MIOS v2.2 und neuer. Diese Einstellungen wird ignoriert." + +#~ msgid "You need to install DIOS MIOS to run GameCube games from USB or DIOS MIOS Lite to run them from SD card" +#~ msgstr "Um GameCube Spiele von USB abzuspielen, wird DIOS MIOS wird benötigt. Um sie von der SD-Karte abzuspielen, wird DIOS MIOS Lite benötigt." + +#~ msgid "v1.2 -> v2.1" +#~ msgstr "v1.2 -> v2.1" + +#~ msgid "v2.2+" +#~ msgstr "v2.2+" + +#~ msgid "Custom Discarts" +#~ msgstr "Eig. Diskbilder" + +#~ msgid "Full HQ Covers" +#~ msgstr "Box HQ Cover" + +#~ msgid "Full LQ Covers" +#~ msgstr "Box LQ Cover" + +#~ msgid "Original Discarts" +#~ msgstr "Org. Diskbilder" + +#~ msgid "GC Force Interlace" +#~ msgstr "GC Interlace erzw." + +#~ msgid "Rename Game on WBFS" +#~ msgstr "Spiel umbenennen" + +#~ msgid "Do you want to discart changes?" +#~ msgstr "Änderungen verwerfen?" + +#~ msgid "Beginning" +#~ msgstr "Anfang" + +#~ msgid "Content" +#~ msgstr "Inhalt" + +#~ msgid "Loader Mode" +#~ msgstr "Loader Modus" + +#~ msgid "Mixed" +#~ msgstr "Gemischt" + +#~ msgid "Search Mode" +#~ msgstr "Such-Modus" + +#~ msgid "Successfully Updated thanks to www.techjawa.com" +#~ msgstr "Erfolgreich aktualisiert. Danke an www.techjawa.com" + +#~ msgid "for hosting the update files" +#~ msgstr "für das Hosten der Updates" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Eine Wii Disk einlegen!" + +#~ msgid "Issue manager /" +#~ msgstr "Problem Manager /" + +#~ msgid "No cheats were selected" +#~ msgstr "Es wurden keine Cheats ausgewählt." + +#~ msgid "Not a Wii Disc" +#~ msgstr "Keine Wii Disk." + +#~ msgid "The files will be extracted to your emu nand path. Attention: All existing files will be overwritten." +#~ msgstr "Datein werden in den EmuNand Pfad kopiert. Achtung: Alle vorhandenen Dateien werden überschrieben." + +#~ msgid "The save games will be extracted to your emu nand path. Attention: All existing saves will be overwritten." +#~ msgstr "Die Spielstände werden zum EmuNand-Pfad entpackt. Achtung: Alle vorhandenen Spielstände werden überschrieben." + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> Lösche Tickets..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> Lösche Tickets...FEHLER! " + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> Lösche Tickets...OK! " + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> Lösche Title...FEHLER! " + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> Lösche Titel...OK! " + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> Lösche Titel Inhalte..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> Lösche Titel Inhalte...FEHLER! " + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> Lösche Titel Inhalte...OK!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> Lösche Titel..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> Beende Installation..." + +#~ msgid ">> Installing content #" +#~ msgstr ">> Installiere Inhalt #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> Installiere Ticket..." + +#~ msgid ">> Installing title..." +#~ msgstr ">> Installiere Titel..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> Lese WAD Daten..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> Lese WAD Daten...FEHLER! " + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> Lese WAD Daten...OK!" + +#~ msgid "Done!" +#~ msgstr "Fertig!" + +#~ msgid "Error..." +#~ msgstr "Fehler..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "Beende Installation... OK!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "Installiere Inhalt... OK!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "Installiere Ticket... OK!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "Installiere Title... OK!" + +#~ msgid "Installing wad" +#~ msgstr "Installiere WAD" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "Lese WAD Daten... OK!" + +#~ msgid "Uninstalling wad" +#~ msgstr "Deinstalliere WAD" + +#~ msgid "The game installation is disabled under this IOS because of instability in usb write." +#~ msgstr "Das Installieren von Spielen ist bei Verwendung dieses IOS wegen Instabilität beim USB-Schreiben deaktiviert." + +#~ msgid "You are currently using IOS" +#~ msgstr "Zur Zeit wird ein IOS benutzt" + +#~ msgid "New Disc Detected" +#~ msgstr "Neue Disk im Laufwerk festgestellt" + +#~ msgid "USB Device not found" +#~ msgstr "USB Gerät nicht gefunden." + +#~ msgid "You need to select or format a partition" +#~ msgstr "Du musst eine Partition auswählen oder formatieren." + +#~ msgid "Language File" +#~ msgstr "Sprachdatei" + +#~ msgid "Are you sure you want to import game categories from WiiTDB?" +#~ msgstr "Sollen die Spiele-Kategorien aus der WiiTDB importiert werden?" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Namen aus WiiTDB" + +#~ msgid "WiiTDB Files" +#~ msgstr "WiiTDB Dateien" + +#~ msgid "WiiTDB Path" +#~ msgstr "WiiTDB" + +#~ msgid "WiiTDB is up to date." +#~ msgstr "WiiTDB ist aktuell." + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "für WiiTDB und dem Hosten der (Disc) Cover" + +#~ msgid "Automatic port switching is done on the fly. You need to change all custom paths to SD-Card first for this option or else it could damage a filesystem." +#~ msgstr "Automatische Portumschaltung wird jetzt direkt zur Programmlaufzeit durchgeführt. Für diese Option müssen zuerst alle eigenen Pfade auf die SD Karte verweisen, da ansonsten das Dateisystem beschädigt werden könnte." + +#~ msgid "Install directories" +#~ msgstr "Installationsart" + +#~ msgid "Install partitions" +#~ msgstr "Partitionen installier." diff --git a/Languages/greek.lang b/Languages/greek.lang new file mode 100644 index 0000000..ae0dd47 --- /dev/null +++ b/Languages/greek.lang @@ -0,0 +1,2594 @@ +# USB Loader GX language source file. +# greek.lang - r1202 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:02+0200\n" +"Last-Translator: nakata6790\n" +"Language-Team: nakata6790 (aka0107@gmail.com)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Ãëþóóá: ÅëëçíéêÜ \n" + +msgid " could not be downloaded." +msgstr " Ç ëÞøç äåí åßíáé äõíáôÞ ." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " Áðïèçêåýôçêå. Äåí å÷åé ðéóôïðïéçèåß. ÊÜðïéïé êùäéêïß ßóùò íá ìçí äïõëåýïõí ôáõôü÷ñïíá ìå Üëëïõò. Áí óõíáíôÞóåôå ðñüâëçìá, áíïßîôå ôï áñ÷åßï .txt ãéá ðåñéóóüôåñåò ðëçñïöïñßåò." + +msgid " is not on the server." +msgstr " äåí õðÜñ÷åé óôïí server." + +#, c-format +msgid "%i files not found on the server!" +msgstr "%ôá áñ÷åßá äåí âñÝèçêáí óôïí server!" + +#, c-format +msgid "%i missing files" +msgstr "%ôá ÷áìÝíá áñ÷åßá" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (¼ëïé)" + +msgid "1 (Child 7+)" +msgstr "1 (ÐáéäéÜ 7+)" + +msgid "1 hour" +msgstr "1 þñá" + +msgid "10 min" +msgstr "10 ëåðôÜ" + +msgid "2 (Teen 12+)" +msgstr "2 (ÐáéäéÜ 12+)" + +msgid "20 min" +msgstr "20 ëåðôÜ" + +msgid "2D Cover Path" +msgstr "ÌïíïðÜôé åîùöýëëùí 2D" + +msgid "3 (Mature 16+)" +msgstr "3 (¸öçâïé 16+)" + +msgid "3 min" +msgstr "3 ëåðôÜ" + +msgid "30 min" +msgstr "30 ëåðôÜ" + +msgid "3D Cover Path" +msgstr "Ôïðïèåóßá åîùöýëëùí 3D" + +msgid "3D Covers" +msgstr "Åîþöõëëá 3D" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Ìïíï ãéá åíÞëéêåò 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 ëåðôÜ" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "AÕÔÏÌÁÔÁ" + +msgid "AXNextFrame" +msgstr "AXÅðüìåíïÊáñÝ" + +msgid "Add category" +msgstr "Ðñüóèåóå êáôçãïñßá" + +msgid "Adjust Overscan X" +msgstr "Ñýèìéóå ôïí Üîïíá X" + +msgid "Adjust Overscan Y" +msgstr "Ñýèìéóå ôïí Üîïíá Y" + +msgid "After zoom" +msgstr "ÌåôÜ ôï zoom" + +msgid "All" +msgstr "üëá" + +msgid "All Partitions" +msgstr "¼ëá ôá partitions" + +msgid "All files extracted." +msgstr "üëá ôá áñ÷åßá áðïóõìðéÝóôçêáí." + +msgid "All images downloaded successfully." +msgstr "¼ëåò ïé åéêüíåò ëÞöèçóáí åðéôõ÷þò." + +msgid "All the features of USB Loader GX are unlocked." +msgstr "üëåò ïé ñõèìßóåéò ôïõ USB Loader GX åßíáé îåêëåéäùìÝíåò." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Åíáëëáêôéêü DOL" + +msgid "An example file was created here:" +msgstr "¸íá áñ÷åßï-ðáñÜäåéãìá äçìéïõñãÞèçêå åäþ" + +msgid "Animation Start" +msgstr "Áñ÷Þ animation" + +msgid "App Language" +msgstr "Ãëþóóá åöáñìïãÞò" + +msgid "Apply" +msgstr "ÅöáñìïãÞ" + +msgid "Apr" +msgstr "Áðñßëéïò" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "Åßóôå ðñáãìáôéêÜ óßãïõñïé üôé èÝëåôå íá óâÞóåôå üëá ôá åðéëåãìÝíá ðáé÷íßäéá áðü ôçí êÜñôá SD;" + +msgid "Are you sure you want to delete this category?" +msgstr "Åßóôå óßãïõñïé üôé èÝëåôå íá óâÞóåôå áõôÞí ôçí êáôçãïñßá;" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "Åßóôå óßãïõñïé üôé èÝëåôå íá åéóÜãåôå êáôçãïñßåò ôßôëùí áðü ôï WiiTDB;" + +msgid "Are you sure you want to install on SD?" +msgstr "Åßóôå óßãïõñïé üôé èÝëåôå íá åãêáôáóôÞóåôå óôçí êÜñôá SD?" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "Åßóôå óßãïõñïé üôé èÝëåôå íá êëåéäþóåôå ôï USB Loader GX?" + +msgid "Are you sure you want to remount SD?" +msgstr "Åßóôå óßãïõñïé üôé èÝëåôå íá åðáíáãíþóåôå ôçí êÜñôá SD?" + +msgid "Are you sure you want to reset?" +msgstr "Åßóôå óßãïõñïé üôé èÝëåôå íá åðáíåêêéíÞóåôå;" + +msgid "Are you sure?" +msgstr "Åßóôå âÝâáéïé;" + +msgid "Aspect Ratio" +msgstr "Áíáëïãßá ïèüíçò" + +msgid "Attention!" +msgstr "ÐÑÏÓÏ×Ç!" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "Áýãïõóôïò" + +msgid "Author(s):" +msgstr "Åêäüôçò-åò:" + +msgid "Auto" +msgstr "Aõôüìáôá" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "Áõôüìáôç óýíäåóç äéêôýïõ" + +msgid "BCA Codes Path" +msgstr "ÌïíïðÜôé êùäéêþí BCA" + +msgid "Back" +msgstr "Back" + +msgid "Back to HBC or Wii Menu" +msgstr "ÌåôÜâáóç óôï êáíÜëé Homebrew Þ óôï ìåíïý ôïõ Wii" + +msgid "Backgroundmusic" +msgstr "ÌïõóéêÞ õðüêñïõóç" + +msgid "Banner Animation" +msgstr "Ánimation ôßôëïõ" + +msgid "Banner Animation Settings" +msgstr "Ñõèìßóåéò animation ôßôëïõ" + +msgid "Banner On Channels" +msgstr "Ôßôëïé-ôáìðÝëåò óôá êáíÜëéá" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "Ç äéÜôáîç ìå ôßôëïõò-ôáìðÝëåò åßíáé äéáèÝséìç ìüíï ìå ôo AHBROT! Ðáñáêáëïýìå åãêáôáóôÞóôå ìéá íåüôåñç Ýêäïóç ôïõ êáíáëéïý Homebrew." + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "Tßôëïé-ôáìðÝëåò åßíáé äéáèÝóéìïé ìüíï ìå ôo AHBROT! Ðáñáêáëïýìå åãêáôáóôÞóôå ìéá íåüôåñç Ýêäïóç ôïõ êáíáëéïý Homebrew." + +msgid "Big thanks to:" +msgstr "ÈåñìÝò åõ÷áñéóôéåò óôïõò:" + +msgid "Block Categories Menu" +msgstr "ÖñáãÞ ìåíïý Êáôçãïñéþí" + +msgid "Block Categories Modify" +msgstr "ÖñáãÞ ôñïðïðïßçóçò Êáôçãïñéþí" + +msgid "Block Cover Downloads" +msgstr "ÖñáãÞ êáôåâÜóìáôïò åîùöýëëùí" + +msgid "Block Custom Paths" +msgstr "ÖñáãÞ ïñéóìÝíùí áðü ôïí ÷ñÞóôç ìïíïðáôéþí" + +msgid "Block Feature Settings" +msgstr "ÖñáãÞ ñõèìßóåùí óôïé÷åßùí ðñïãñÜììáôïò" + +msgid "Block Game Install" +msgstr "ÖñáãÞ åãêáôÜóôáóçò íåùí ðáé÷íéäéþí" + +msgid "Block Game Settings" +msgstr "ÖñáãÞ óå ôñïðïðïßçóç ñõèìßóåùí ðáé÷íéäéþí" + +msgid "Block GameID Change" +msgstr "ÖñáãÞ áëëáãÞò êùäéêïý ID êÜèå ðáé÷íéäéïý" + +msgid "Block Global Settings" +msgstr "ÖñáãÞ ãåíéêþí ñõèìßóåùí" + +msgid "Block Gui Settings" +msgstr "ÖñáãÞ ñõèìßóåùí ðñïâïëÞò åéêïíéäßùí" + +msgid "Block HBC Menu" +msgstr "ÖñáãÞ ðñïâïëÞò åéêïíéäßïõ HBC" + +msgid "Block Hard Drive Settings" +msgstr "ÖñáãÞ ñõèìßóåùí óêëçñïý äßóêïõ" + +msgid "Block IOS Reload" +msgstr "ÖñáãÞ åðáíáöüñôùóçò IOS" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "ÖñáãÞ åéêïíéäßïõ åðéëïãÞò ðáé÷íéäéþí" + +msgid "Block Loader Settings" +msgstr "ÖñáãÞ ñõèìßóåùí Loader" + +msgid "Block Parental Settings" +msgstr "ÖñáãÞ ñõèìßóåùí êëåéäþìáôïò" + +msgid "Block Priiloader Override" +msgstr "ÖñáãÞ åìöÜíéóçò Priiloader" + +msgid "Block Reset Settings" +msgstr "ÖñáãÞ åðáíáöïñÜò ñõèìßóåùí" + +msgid "Block SD Reload Button" +msgstr "ÖñáãÞ åéêïíéäßïõ åðáíáöüñôùóçò SD" + +msgid "Block Sound Settings" +msgstr "ÖñáãÞ ñõèìßóåùí Þ÷ïõ" + +msgid "Block Theme Downloader" +msgstr "ÖñáãÞ ëÞøçò íÝùí èåìÜôùí" + +msgid "Block Theme Menu" +msgstr "ÖñáãÞ áëëáãÞò èåìÜôùí" + +msgid "Block Title Launcher" +msgstr "ÖñáãÞ áëëáãÞò ôßôëùí" + +msgid "Block Updates" +msgstr "ÖñáãÞ áíáâáèìßóåùí" + +msgid "Boot Content" +msgstr "Ðåñéå÷üìåíï ðïõ åêêéíåß" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "åêêßíçóç;" + +msgid "Both" +msgstr "êáé ôá äõï" + +msgid "Both Ports" +msgstr "êáé ïé 2 èýñåò" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "áðïèÞêåõóç áñ÷åßùí BNR" + +msgid "Cache BNR Files Path" +msgstr "áðïèÞêåõóç ôïðïèåóßáò áñ÷åßùí BNR" + +msgid "Cache Titles" +msgstr "ÁðïèÞêåõóç ôßôëùí" + +msgid "Can't be formatted" +msgstr "Áäýíáôç ç áíáóõãêñüôçóç (format)" + +msgid "Can't create directory" +msgstr "Áäýíáôç ç äçìéïõñãßá öáêÝëïõ" + +#, c-format +msgid "Can't create file: %s" +msgstr "Áäýíáôç ç äçìéïõñãßá áñ÷åßïõ: %s" + +#, c-format +msgid "Can't create path: %s" +msgstr "Áäýíáôïò ï ïñéóìüò äéåýèõíóçò: %s" + +msgid "Can't delete:" +msgstr "Áäýíáôç ç äéáãñáöÞ:" + +msgid "Can't mount or unknown disc format." +msgstr "Áäõíáìßá åýñåóçò áðïèçêåõôéêïý ìÝóïõ Þ Üãíùóôï ìÝóï" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "Áäõíáìßá åããñáöÞò óôï áñ÷åßï: %s" + +#, c-format +msgid "Can't open file: %s" +msgstr "Áäõíáìßá áíïßãìáôïò áñ÷åßïõ: %s" + +#, c-format +msgid "Can't read file: %s" +msgstr "Áäõíáìßá áíÜãíùóçò áñ÷åßïõ: %s" + +msgid "Cancel" +msgstr "¢êõñï" + +msgid "Cannot write to destination." +msgstr "Áäõíáìßá åããñáöÞò óôïí ðñïïñéóìü." + +msgid "Categories" +msgstr "Êáôçãïñßåò" + +msgid "Categories:" +msgstr "Êáôçãïñßåò:" + +msgid "Change Play Path" +msgstr "ÁëëáãÞ ôïðïèåóßáò ðáé÷íéäéþí " + +msgid "Channel Launcher" +msgstr "Åêêßíçóç êáíáëéþí" + +msgid "Channels" +msgstr "ÊáíÜëéá" + +msgid "Cheatfile is blank" +msgstr "ôï áñ÷åßï cheat åßíáé êåíü" + +msgid "Clear" +msgstr "ÓâÞóéìï" + +msgid "Click to Download Covers" +msgstr "Êëéê ãéá ëÞøç åîùöýëëùí" + +msgid "Click to change game ID" +msgstr "Êëéê ãéá áëëáãÞ ïíüìáôïò ðáé÷íéäéïý" + +msgid "Clock" +msgstr "Ñïëïú" + +msgid "Clock Scale Factor" +msgstr "MÝãåèïò áñéèìþí ñïëïãéïý" + +msgid "Close" +msgstr "Êëåßóéìï" + +msgid "Code Download" +msgstr "ËÞøç êùäéêïý" + +#, c-format +msgid "Coded by: %s" +msgstr "Ðñïãñáììáôéóìüò: %s" + +msgid "Coding:" +msgstr "Ðñïãñáììáôéóìüò:" + +msgid "Connection to server timed out." +msgstr "Ç óýíäåóç óôïí server ÷Üèçêå." + +msgid "Console" +msgstr "Êïíóüëá" + +msgid "Console Default" +msgstr "ÂáóéêÝò ñõèìßóåéò êïíóüëáò" + +msgid "Console Locked" +msgstr "Êëåéäþèçêå" + +msgid "Console must be unlocked for this option." +msgstr "Ôï ìåíïý ðñÝðåé íá åßíáé îåêëåßäùôï ãéá ôçí åðéëïãÞ áõôÞ." + +msgid "Console must be unlocked to be able to use this." +msgstr "Ôï ìåíïý ðñÝðåé íá åßíáé îåêëåßäùôï ãéá íá ìðïñåßôå íá ôï ÷ñçóéìïðïéÞóåôå." + +msgid "Console should be unlocked to modify it." +msgstr "Ôï ìåíïý ðñÝðåé íá åßíáé îåêëåßäùôï ãéá íá ìðïñåßôå íá ôï ôñïðïðïéÞóåôå." + +msgid "Continue" +msgstr "ÓõíÝ÷åéá" + +msgid "Continue to install game?" +msgstr "ÓõíÝ÷éóç åãêáôÜóôáóçò ðáé÷íéäéïý;" + +msgid "Continue?" +msgstr "ÓõíÝ÷åéá;" + +msgid "Controllevel" +msgstr "" + +msgid "Copy" +msgstr "ÁíôéãñáöÞ" + +msgid "Copying Canceled" +msgstr "ÁíôéãñáöÞ áêõñþèçêå" + +msgid "Copying GC game..." +msgstr "ÁíôéãñáöÞ ðáé÷íéäéïý GameCube..." + +msgid "Copying files..." +msgstr "ÁíôéãñáöÞ áñ÷åßùí..." + +msgid "Correct Password" +msgstr "Óùóôü Password" + +msgid "Could not connect to the server." +msgstr "Áäõíáìßá óýíäåóçò óôï server." + +msgid "Could not create GCT file" +msgstr "Áäõíáìßá äçìéïõñãßáò áñ÷åßïõ GCT" + +#, c-format +msgid "Could not create path: %s" +msgstr "Áäõíáìßá äçìéïõñãßáò ìïíïðáôéïý: %s" + +msgid "Could not extract files for:" +msgstr "Áäõíáìßá áðïóõìðßåóçò áñ÷åßùí ãéá:" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "Äåí âñÝèçêáí ðëçñïöïñßåò ãéá ôï ðáé÷íßäé áõôü óôï áñ÷åßï wiitdb.xml." + +msgid "Could not get free device space for game." +msgstr "Äåí âñÝèçêå åðáñêÞò åëåýèåñïò ÷þñïò ãéá ôï ðáé÷íßäé." + +msgid "Could not initialize DIP module!" +msgstr "Áäõíáìßá åêêßíçóçò óôïé÷åßïõ DIP!" + +msgid "Could not initialize network!" +msgstr "Áäõíáìßá óýíäåóçò ðñïãñÜììáôïò óôï äéáäßêôõï!" + +msgid "Could not initialize network, time out!" +msgstr "Áäõíáìßá óýíäåóçò ðñïãñÜììáôïò óôï äéáäßêôõï, ôÝëïò ÷ñüíïõ!" + +msgid "Could not open Disc" +msgstr "Áäõíáìßá áíÜãíùóçò äßóêïõ" + +msgid "Could not open the WiiTDB.xml file." +msgstr "Áäõíáìßá áíïßãìáôïò áñ÷åßïõ wiitdb.xml" + +msgid "Could not open wiitdb.xml." +msgstr "Áäõíáìßá áíïßãìáôï wiitdb.xml." + +msgid "Could not save." +msgstr "Áäõíáìßá áðïèÞêåõóçò." + +msgid "Could not write file." +msgstr "Äåí åßíáé äõíáôÞ ç åããñáöÞ ôïõ áñ÷åßïõ." + +msgid "Could not write to:" +msgstr "Áäõíáìßá åããñáöÞò óå:" + +msgid "Cover Download" +msgstr "ËÞøç åîùöýëëùí" + +msgid "Create" +msgstr "Äçìéïõñãßá" + +msgid "Credits" +msgstr "ÓõíôåëåóôÝò" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "ÔñïðïðïéçìÝíåò ôáìðÝëåò-åéêïíßäéá" + +msgid "Custom Paths" +msgstr "ÔñïðïðïéçìÝíåò äéåõèýíóåéò/ìïíïðÜôéá áñ÷åßùí" + +msgid "Customs" +msgstr "ÔñïðïðïéçìÝíá" + +msgid "Customs/Original" +msgstr "ÔñïðïðïéçìÝíá/ÁõèåíôéêÜ" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "Äéåýèõíóç DOL" + +msgid "Debug" +msgstr "Debug" + +msgid "Debug Wait" +msgstr "ÁíáìïíÞ debugger" + +msgid "Debugger Paused Start" +msgstr "ÌåôáãåíÝóôåñç åêêßíçóç debugger" + +msgid "Dec" +msgstr "ÄåêÝìâñéïò" + +msgid "Default" +msgstr "ÂáóéêÞ" + +msgid "Default Gamesettings" +msgstr "ÂáóéêÝò ñõèìßóåéò ðáé÷íéäéþí" + +msgid "Default Settings" +msgstr "ÂáóéêÝò ñõèìßóåéò" + +msgid "Delete" +msgstr "ÄéáãñáöÞ" + +msgid "Delete Cached Banner" +msgstr "ÄéáãñáöÞ áðïèçêåõìÝíùí åôéêåôþí" + +msgid "Delete Cheat GCT" +msgstr "ÄéáãñáöÞ áñ÷åßùí cheat GCT" + +msgid "Delete Cheat TXT" +msgstr "ÄéáãñáöÞ áñ÷åßùí cheat TXT" + +msgid "Delete Cover Artwork" +msgstr "ÄéáãñáöÞ åîùöýëëùí" + +msgid "Delete Disc Artwork" +msgstr "ÄéáãñáöÞ åôéêåôþí äßóêùí" + +msgid "Delete category" +msgstr "ÄéáãñáöÞ êáôçãïñßáò" + +msgid "Deleting directories..." +msgstr "ÄéáãñáöÞ öáêÝëùí..." + +msgid "Deleting files..." +msgstr "ÄéáãñáöÞ áñ÷åßùí..." + +msgid "Design:" +msgstr "Ó÷åäéáóìüò:" + +msgid "Details" +msgstr "ËåðôïìÝñåéåò" + +msgid "Developed by" +msgstr "ÁíÜðôõîç áðü" + +msgid "Developer:" +msgstr "ÐñïãñáììáôéóôÞò:" + +msgid "Devolution" +msgstr "Devolution" + +msgid "Devolution Loader Path" +msgstr "Ôïðïèåóßá devolution" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "Ôï áñ÷åßï loader.bin ôïõ devolution äåí öïñôþèçêå." + +msgid "Directory does not exist!" +msgstr "Ï öÜêåëïò äåí õðÜñ÷åé!" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "ËÞøç åôéêåôþí äßóêùí" + +msgid "Disc Artwork Path" +msgstr "Äéåýèõíóç åôéêåôþí äßóêùí" + +msgid "Disc Default" +msgstr "ÐñïåðéëåãìÝíåò ðáé÷íéäéïý" + +msgid "Disc Insert Detected" +msgstr "Áíé÷íåýôçêå ïðôéêüò äßóêïò" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "ÓöÜëìá êáôá ôçí áíÜãíùóç äßóêïõ." + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "ÅôéêÝôåò äßóêïõ" + +msgid "DiskFlip" +msgstr "ÐåñéóôñïöÞ" + +msgid "Display" +msgstr "Áðåéêüíéóç" + +msgid "Display as a carousel" +msgstr "ÐñïâïëÞ óå êáìðýëç" + +msgid "Display as a channel grid" +msgstr "ÐñïâïëÞ óå êáíÜëéá" + +msgid "Display as a grid" +msgstr "ÐñïâïëÞ óå ðëÝãìá" + +msgid "Display as a list" +msgstr "ÐñïâïëÞ óå ëßóôá" + +msgid "Display favorites only" +msgstr "ÐñïâïëÞ ìüíï ôùí áãáðçìÝíùí" + +msgid "Do you want to apply it now?" +msgstr "ÈÝëåôå íá ôï åöáñìüóåôå ôþñá;" + +msgid "Do you want to apply this theme?" +msgstr "ÈÝëåôå íá åíåñãïðïéÞóåôå áõôü ôï èÝìá;" + +msgid "Do you want to change language?" +msgstr "ÈÝëåôå íá áëëÜîåôå ãëþóóá;" + +msgid "Do you want to continue with next game?" +msgstr "Èá èÝëáôå íá ðñï÷ùñÞóåôå ìå ôïí åðüìåíï ôßôëï;" + +msgid "Do you want to copy now?" +msgstr "ÈÝëåôå íá áíôéãñÜøåôå ôþñá;" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "ÈÝëåôå íá áíôéãñÜøåôå ôï ðáé÷íßäé óôçí êÜñôá SD Þ íá ôï äéáãñÜøåôå áðü åêåß;" + +msgid "Do you want to delete a game on SD?" +msgstr "Èá èÝëáôå íá äéáãñÜøåôå åíá ðáé÷íßäé áðü ôçí êÜñôá SD;" + +msgid "Do you want to discard changes?" +msgstr "ÈÝëåôå íá áãíïçèïýí ïé áëëáãÝò;" + +msgid "Do you want to download this theme?" +msgstr "Èá èÝëáôå íá êáôåâÜóåôå ôï óõãêåêñéìÝíï èÝìá;" + +msgid "Do you want to extract all the save games?" +msgstr "Èá èÝëáôå íá áíôéãñÜøåôå üëá ôá saves;" + +msgid "Do you want to extract the save game?" +msgstr "Èá èÝëáôå íá áíôéãñÜøåôå ôï save;" + +msgid "Do you want to format:" +msgstr "ÈÝëåôå íá êÜíåôå format (áíáóõãêñüôçóç);" + +msgid "Do you want to install selected games?" +msgstr "ÈÝëåôå íá åãêáôáóôÞóåôå ôá åðéëåãìÝíá ðáé÷íßäéá;" + +msgid "Do you want to load the default theme?" +msgstr "ÈÝëåôå íá ÷ñçóéìðïðïéÞóôå ôï âáóéêü èÝìá;" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "ÈÝëåôå íá åðáíáóõíäåèåß ôï ðñüãñáììá ìå ôï äéáäßêôõï;" + +msgid "Do you want to start the game now?" +msgstr "ÈÝëåôå íá åêêéíÞóåôå ôï ðñüãñáììá ôþñá;" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "ÈÝëåôå íá óõã÷ñïíßóåôå ôïí êåíü ÷þñï áðü üëá ôá FAT32 partitions;" + +msgid "Do you wish to update/download all language files?" +msgstr "ÈÝëåôå íá áíáâáèìßóåôå/êáôåâÜóåôå üëá ôá áñ÷åßá ìåôáöñÜóåùí;" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "ËÞøç" + +msgid "Download Now" +msgstr "ÊáôÝâáóìá ôþñá" + +msgid "Download finished" +msgstr "ÏëïêëÞñùóç ëÞøçò" + +msgid "Downloading 3D Covers" +msgstr "ËÞøç 3D åîùöýëëùí..." + +msgid "Downloading Custom Banners" +msgstr "ËÞøç ôñïðïðïéçìÝíùí ôáìðåëþí..." + +msgid "Downloading Flat Covers" +msgstr "ËÞøç 2D åîùöýëëùí..." + +msgid "Downloading Full HQ Covers" +msgstr "ËÞøç ïëïêëçñùí åîùöýëëùí óå õøçëÞ ðïéüôçôá..." + +msgid "Downloading Full LQ Covers" +msgstr "ËÞøç ïëïêëçñùí åîùöýëëùí óå ÷áìçëÞ ðïéüôçôá..." + +msgid "Downloading custom Discarts" +msgstr "ËÞøç ôñïðïðïéçìÝíùí åôéêåôþí äßóêùí" + +msgid "Downloading file..." +msgstr "ËÞøç áñ÷åßïõ..." + +msgid "Downloading image:" +msgstr "ËÞøç åéêüíáò:" + +msgid "Downloading original Discarts" +msgstr "ËÞøç áõèåíôéêþí åôéêåôþí äßóêùí" + +msgid "Downloading pagelist:" +msgstr "ËÞøç äéÜôáîçò óåëéäþí:" + +msgid "Dump NAND to EmuNand" +msgstr "ÁíôéãñáöÞ NAND óôçí ôïðïèåóßá emunand" + +msgid "During zoom" +msgstr "Êáôá ôçí åóôßáóç" + +msgid "Dutch" +msgstr "OëëáíäéêÜ" + +msgid "ERROR" +msgstr "ÓÖÁËÌÁ" + +msgid "ERROR:" +msgstr "ÓÖÁËÌÁ:" + +msgid "ERROR: Can't set up theme." +msgstr "ÓÖÁËÌÁ: Äåí åßíáé äõíáôÞ ç åãêáôÜóôáóç èÝìáôïò." + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "ÊáíÜëéá áðü ôçí åéêïíéêÞ nand " + +msgid "Emulated Nand" +msgstr "åéêïíéêç NAND" + +msgid "English" +msgstr "ÁããëéêÜ" + +msgid "Enter Path" +msgstr "Ïñßóôå ôçí ôïðïèåóßá" + +msgid "Error" +msgstr "ÓöÜëìá" + +msgid "Error !" +msgstr "Óöáëìá !" + +#, c-format +msgid "Error creating path: %s" +msgstr "ÓöÜëìá äçìéïõñãßáò ìïíïðáôéïý: %s" + +msgid "Error opening downloaded file" +msgstr "ÓöÜëìá áíïßãìáôïò ëçöèÝíôïò áñ÷åßïõ" + +msgid "Error reading Disc" +msgstr "ÓöÜëìá áíÜãíùóçò Äßóêïõ" + +msgid "Error reading disc" +msgstr "ÓöÜëìá áíÜãíùóçò äßóêïõ" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "ÓöÜëìá êáôá ôçí ëÞøç áñ÷åßïõ: %i" + +msgid "Error while downloding file" +msgstr "ÓöÜëìá êáôá ôçí ëÞøç áñ÷åßïõ" + +msgid "Error while opening the zip." +msgstr "ÓöÜëìá êáôá ôï Üíïéãìá áñ÷åßïõ zip." + +msgid "Error while transfering data." +msgstr "ÓöÜëìá êáôá ôç ìåôáöïñÜ áñ÷åßùí." + +msgid "Error while updating USB Loader GX." +msgstr "ÓöÜëìá êáôá ôçí áíáâÜèìéóç ôïõ USB Loader GX." + +msgid "Error writing the data." +msgstr "ÓöÜëìá êáôá ôçí åããñáöÞ äåäïìÝíùí." + +msgid "Error:" +msgstr "ÓöÜëìá:" + +msgid "Error: Not enough space on SD." +msgstr "ÓöÜëìá: äåí õðÜñ÷åé áñêåôüò äéáèÝóéìïò ÷þñïò óôçí êÜñôá SD" + +msgid "Errors occured." +msgstr "Óçìåéþèçêáí ëÜèç." + +msgid "Everything" +msgstr "¼ëá" + +msgid "Exit" +msgstr "¸îïäïò" + +msgid "Exit to where?" +msgstr "¸îïäïò ðñïò ðïõ;" + +msgid "Export All Saves to EmuNand" +msgstr "ÁíôéãñáöÞ üëùí ôùí saves óôçí åéêïíéêÞ NAND" + +msgid "Export Miis to EmuNand" +msgstr "ÁíôéãñáöÞ ôùí Mii óôçí åéêïíéêÞ NAND" + +msgid "Export SYSCONF to EmuNand" +msgstr "ÁíôéãñáöÞ SYSCONF óôçí åéêïíéêÞ NAND" + +msgid "Extract Miis to the Emu NAND?" +msgstr "ÁíôéãñáöÞ ôùí Mii óôçí åéêïíéêÞ NAND;" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "ÁíôéãñáöÞ SYSCONF óôçí åéêïíéêÞ NAND;" + +msgid "Extract Save to EmuNand" +msgstr "ÁíôéãñáöÞ ôïõ save óôçí åéêïíéêÞ NAND" + +msgid "Extracting file:" +msgstr "Áðïóõìðßåóç áñ÷åßïõ:" + +msgid "Extracting files..." +msgstr "Áðïóõìðßåóç áñ÷åßùí..." + +msgid "Extracting files:" +msgstr "Áðïóõìðßåóç áñ÷åßùí:" + +msgid "Extracting nand files:" +msgstr "ÁíôéãñáöÞ áñ÷åßùí áðü ôç ìíçìç NAND:" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "ÁðÝôõ÷å" + +msgid "Failed copying file" +msgstr "Ìç åðéôõ÷Þò áíôéãñáöÞ áñ÷åßïõ" + +msgid "Failed formating" +msgstr "Ìç åðéôõ÷Þò áíáóõãêñüôçóç (format) " + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "Áíåðéôõ÷Þò áíôéãñáöÞ üëùí ôùí áñ÷åßùí. Ôï save ðéèáíüí äåí áíôåãñÜöç." + +msgid "Failed to extract." +msgstr "Áðïôõ÷ßá áðïóõìðßåóçò." + +msgid "Failed to initialize the USB storage device." +msgstr "Áðïôõ÷ßá Ýíáñîçò áðïèçêåõôéêÞò óõóêåõÞò USB." + +msgid "Failed to open partition" +msgstr "Áäõíáìßá áíïßãìáôïò partition" + +msgid "Failed to read ticket." +msgstr "Aäõíáìßá åýñåóçò áñ÷åßïõ ticket." + +msgid "Failed to read tmd file." +msgstr "Aäõíáìßá áíïßãìáôïò áñ÷åßïõ tmd." + +msgid "Failed to read wad header." +msgstr "Áäõíáìßá áíÜãíùóçò ôßôëïõ ôïõ áñ÷åßïõ wad." + +msgid "Failed updating" +msgstr "Áíåðéôõ÷Þò áíáâÜèìéóç" + +msgid "Favorite Level" +msgstr "Âáèìïëïãßá" + +msgid "Features" +msgstr "ÅðéìÝñïõò óôïé÷åßá" + +msgid "Features Settings" +msgstr "Ñõèìßóåéò åðéìÝñïõò óôïé÷åßùí" + +msgid "Feb" +msgstr "ÖåâñïõÜñéïò" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Ôï áñ÷åßï äåí âñÝèçêå." + +msgid "File read/write error." +msgstr "ÓöÜëìá áíÜãíùóçò/åããñáöÞò áñ÷åßïõ" + +msgid "Files extracted successfully." +msgstr "Ôï áñ÷åßï áðïóõìðéÝóôçêå åðéôõ÷þò." + +#, c-format +msgid "Filesize is %i Byte." +msgstr "Ôï ìÝãåèïò ôïõ áñ÷åßïõ åßíáé %i byte." + +msgid "Filesize is 0 Byte." +msgstr "Ôï ìÝãåèïò ôïõ áñ÷åßïõ åßíáé 0 byte." + +msgid "Flat Covers" +msgstr "2D åîþöõëëá" + +msgid "Flip-X" +msgstr "ïñéæüíôéá áíáóôñïöÞ" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "ÌÝãåèïò ãñáììáôïóåéñÜò" + +msgid "Force 16:9" +msgstr "ÅðéâïëÞ áíáëïãßáò 16:9" + +msgid "Force 4:3" +msgstr "ÅðéâïëÞ áíáëïãßáò 4:3" + +msgid "Force NTSC" +msgstr "ÅðéâïëÞ NTSC" + +msgid "Force NTSC480p" +msgstr "ÅðéâïëÞ NTSC480p" + +msgid "Force PAL480p" +msgstr "ÅðéâïëÞ PAL480p" + +msgid "Force PAL50" +msgstr "ÅðéâïëÞ PAL50" + +msgid "Force PAL60" +msgstr "ÅðéâïëÞ PAL60" + +msgid "Force Titles from Disc" +msgstr "ÅðéâïëÞ ïíüìáôïò áðü ôï ßäéï ôï ðáé÷íßäé" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Áíáóõãêñüôçóç (format)" + +msgid "Formatting, please wait..." +msgstr "Áíáóõãêñüôçóç (format), ðáñáêáëþ ðåñéìÝíåôå..." + +msgid "Found missing images." +msgstr "ÂñÝèçêáí ïé åéêüíåò ðïõ ëåßðïõí." + +msgid "Frame" +msgstr "ÊáñÝ" + +msgid "Frame Projection Height" +msgstr "¾øïò ðñïâïëÞò êáñÝ" + +msgid "Frame Projection Width" +msgstr "ÐëÜôïò ðñïâïëÞò êáñÝ" + +msgid "Frame Projection X-Offset" +msgstr "Ïñéæüíôéï ðëÜôïò ðñïâïëÞò êáñÝ" + +msgid "Frame Projection Y-Offset" +msgstr "ÊÜèåôï ýøïò ðñïâïëÞò êáñÝ" + +msgid "Frames" +msgstr "ÊáñÝ" + +msgid "Free Space" +msgstr "Åëåýèåñïò ÷þñïò" + +msgid "French" +msgstr "ÃáëëéêÜ" + +msgid "Full" +msgstr "ÐëÞñçò/åò" + +msgid "Full Cover Path" +msgstr "ÐëÞñçò äéåýèõíóç åîùöýëëùí" + +msgid "Full Covers" +msgstr "Ïëüêëçñá åîþöõëëá" + +msgid "Full Menu" +msgstr "ÐëÞñåò ìåíïý" + +msgid "Full covers Download" +msgstr "ËÞøç ïëüêëçñùí åîùöýëëùí" + +msgid "Full shutdown" +msgstr "ÐëÞñùò" + +msgid "GAMEID_Gamename" +msgstr "IDðáé÷íéäéïý_¼íïìá ðáé÷íéäéïý" + +msgid "GC Banner Scale" +msgstr "ÌÝãåèïò ôáìðåëþí ôßôëùí GC" + +msgid "GC Games" +msgstr "Ðáé÷íßäéá GC" + +msgid "GC Install 32K Aligned" +msgstr "ÅãêáôÜóôáóç ôßôëùí GC óå óýóôçìá áñ÷åßùí 32Ê" + +msgid "GC Install Compressed" +msgstr "ÅãêáôÜóôáóç ôßôëùí GC óå óõìðéåóìÝíç ìïñöÞ" + +msgid "GCT Cheatcodes Path" +msgstr "Äéåýèõíóç á÷åßùí cheat GCT" + +msgid "GCT File created" +msgstr "ÄçìéïõñãÞèçêå áñ÷åßï cheat GCT" + +msgid "GUI Settings" +msgstr "Ñõèìßóåéò ãñáöéêÞò áðåéêüíéóçò ìÝíïõ" + +msgid "GXDraw" +msgstr "GXDraw" + +msgid "GXFlush" +msgstr "GXFlush" + +msgid "Game Cube Games Delete" +msgstr "ÄéáãñáöÞ ðáé÷íéäéþí Gamecube" + +msgid "Game Cube Install Menu" +msgstr "menu åãêáôÜóôáóçò ðáé÷íéäéþí Gamecube" + +msgid "Game ID" +msgstr "ID ðáé÷íéäéïý" + +msgid "Game IOS" +msgstr "IOS ðáé÷íéäéïý" + +msgid "Game Language" +msgstr "ãëþóóá ðáé÷íéäéïý" + +msgid "Game Load" +msgstr "öüñôùóç ðáé÷íéäéïý" + +msgid "Game Lock" +msgstr "êëÝéäùìá ðáé÷íéäéïý" + +msgid "Game Only" +msgstr "Ìüíï ôï ðáé÷íßäé" + +msgid "Game Region" +msgstr "ðñïÝëåõóç ðáé÷íéäéïý" + +msgid "Game Size" +msgstr "ìÝãåèïò ðáé÷íéäéïý" + +msgid "Game Sound Mode" +msgstr "åðéëïãÞ Þ÷ïõ ðáé÷íéäéïý-ùí" + +msgid "Game Sound Volume" +msgstr "Ýíôáóç Þ÷ïõ ðáé÷íéäéïý-ùí" + +msgid "Game Split Size" +msgstr "ìÝãåèïò êïììáôéþí ðáé÷íéäéïý-ùí" + +msgid "Game Window Mode" +msgstr "åðéëïãÞ áðåéêüíéóçò ðáñáèýñùí" + +msgid "Game is already installed:" +msgstr "Ôï ðáé÷íßäé åßíáé Þäç åãêáôåóôçìÝíï:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "partition ðïõ èá åãêáôáóôçáèåß ôï ðáé÷íßäé." + +msgid "GameCube" +msgstr "GameCube" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "ÌÝèïäïò öüñôùóçò ðáé÷íéäéþí GameCube" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "üíïìá ðáé÷íéäéïý [êùäéêüòðáé÷íéäéïý]" + +msgid "Games" +msgstr "Ðáé÷íßäéá" + +msgid "Generating GXGameCategories.xml" +msgstr "Äçìéïõñãßá áñ÷åßïõ GXGameCategories.xml" + +msgid "Genre:" +msgstr "Åßäïò:" + +msgid "German" +msgstr "ÃåñìáíéêÜ" + +msgid "Getting file list..." +msgstr "¢íïéãìá ëßóôáò áñ÷åßùí..." + +msgid "Getting game folder size..." +msgstr "¢íß÷íåõóç ìåãÝèïõò öáêÝëùí..." + +msgid "Global Settings" +msgstr "ÃåíéêÝò ñõèìßóåéò" + +msgid "Grid Scroll Speed" +msgstr "Ôá÷ýôçôá åíáëëáãÞò åéêüíùí" + +msgid "HOME Menu" +msgstr "Måíïý HOME" + +msgid "Hard Drive Settings" +msgstr "Ñõèìßóåéò óêëçñïý äßóêïõ" + +msgid "High Quality" +msgstr "ÕøçëÞ ðïéüôçôá" + +msgid "High/Low" +msgstr "ÕøçëÞ/×áìçëÞ" + +msgid "Homebrew Apps Path" +msgstr "Ôïðïèåóßá åöáñìïãþí homebrew" + +msgid "Homebrew Channel" +msgstr "ÊáíÜëé homebrew" + +msgid "Homebrew Launcher" +msgstr "åêêßíçóç homebrew" + +msgid "Hooktype" +msgstr "ôýðïò hook" + +msgid "Hour" +msgstr "¿ñá" + +msgid "How do you want to update?" +msgstr "Ðþò èá èÝëáôå íá áíáâáèìßóåôå;" + +msgid "How to Shutdown?" +msgstr "Ðùò íá ôåñìáôéóôåé ç åöáñìïãÞ;" + +msgid "Import Categories" +msgstr "ÅéóáãùãÞ êáôçãïñéþí" + +msgid "Import operation successfully completed." +msgstr "Ç åéóáãùãÞ ïëïêëçñþèçêå åðéôõ÷þò." + +msgid "Importing categories" +msgstr "ÅéóáãùãÞ êáôçãïñéþí..." + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Åéóåñ÷üìåíï áñ÷åßï %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Åéóåñ÷üìåíï áñ÷åßï %0.2fMB" + +msgid "Individual" +msgstr "Îå÷ùñéóôÜ" + +msgid "Initializing Network" +msgstr "Óýíäåóç óôï äéáäßêôõï" + +msgid "Insert Disk" +msgstr "ÅéóÜãåôå äßóêï" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "ÅéóÜãåôå Ýíáí ïðôéêü äßóêï Wii Þ GameCube!" + +msgid "Install" +msgstr "ÅãêáôÜóôáóç" + +msgid "Install Canceled" +msgstr "Ç åãêáôÜóôáóç áêõñþèçêå" + +msgid "Install Directories" +msgstr "Ôïðïèåóßåò/ÖÜêåëïé åãêáôÜóôáóçò" + +msgid "Install Error!" +msgstr "ÓöÜëìá åãêáôÜóôáóçò!" + +msgid "Install Partitions" +msgstr "Partitions åãêáôÜóôáóçò" + +msgid "Install a game" +msgstr "ÅãêáôáóôÞóôå åíá ðáé÷íßäé" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "Ç åãêáôÜóôáóç ïëïêëçñþèçêå" + +msgid "Installing Game Cube Game..." +msgstr "Åãêáèßóôáôáé ðáé÷íßäé GameCube..." + +msgid "Installing content" +msgstr "Åãêáèßóôáôáé ðåñéå÷üìåíï" + +msgid "Installing game:" +msgstr "Åãêáèßóôáôáé ðáé÷íßäé:" + +msgid "Installing title..." +msgstr "Åãêáèßóôáôáé ôßôëïò..." + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "ËáíèáóìÝíïò áñéèìüò IOS. ÐñÝðåé íá åßíáé ìåôáîý 200 êáé 255 Þ -1 ãéá ôïí âáóéêü" + +msgid "Invalid wad file." +msgstr "Ìç óõìâáôü áñ÷åßï WAD." + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Öáßíåôáé üôé Ý÷åôå ðëçñïöïñßåò ðïõ èá ìðïñïýóáí íá áðïâïýí ÷ñÞóéìåò ãéá ôçí åöáñìïãÞ. Ðáñáêáëþ ìåôáâéâÜóôå ôåò óôïõò óõíôåëåóôÝò." + +msgid "Italian" +msgstr "ÉôáëéêÜ" + +msgid "Jan" +msgstr "ÉáíïõÜñéïò" + +msgid "Japanese" +msgstr "ÉáðùíéêÜ" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "Joypad" + +msgid "July" +msgstr "Éïýëéïò" + +msgid "June" +msgstr "Éïýíéïò" + +msgid "KPAD Read" +msgstr "KPAD Read" + +msgid "Keyboard" +msgstr "Ðëçêôñïëüãéï" + +msgid "Korean" +msgstr "ÊïñåÜôéêá" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "áñ÷åßá ìåôáöñÜóåùí" + +msgid "Language change:" +msgstr "ÅðéëïãÞ ãëþóóáò:" + +msgid "Languagefiles Path" +msgstr "ôïðïèåóßá áñ÷åßùí ìåôáöñÜóåùí" + +msgid "Languagepath changed." +msgstr "Ç ôïðïèåóßá áñ÷åßùí ìåôáöñÜóåùí Üëëáîå." + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Ç åêêßíçóç êáíáëéþí áðü ôçí åéêïíéêÞ NAND õðïóôçñßæåôáé ìüíï áðü ôï cIOS d2x! ÅðéëÝîôå Ýíá ÉÏS ìå d2x ãéá íá óõíå÷ßóåôå." + +msgid "Left" +msgstr "ÁñéóôåñÜ" + +msgid "Like SysMenu" +msgstr "üðùò óôï êåíôñéêü ìåíïý" + +msgid "List on Gamelaunch" +msgstr "ÐñïâïëÞ êáôá ôçí åêêßíçóç ðáé÷íéäéïý" + +msgid "Load" +msgstr "Öüñôùóç" + +msgid "Load From SD/USB" +msgstr "¢íïéãìá áðü SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "¢íïéãìá áñ÷åßïõ áðü: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "ÖÃüñôùóç áõôïý ôïõ áñ÷åßïõ DOL ùò åíáëëáêôéêü;" + +msgid "Loader Settings" +msgstr "Ñõèìßóåéò ðñïãñÜììáôïò" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "Öüñôùóç âáóéêÞò ãëþóóáò." + +msgid "Loading standard music." +msgstr "Öüñôùóç âáóéêÞò ìïõóéêÞò." + +msgid "Lock Console" +msgstr "ÖñáãÞ ìåíïý" + +msgid "Lock USB Loader GX" +msgstr "Êëåßäùìá USB Loader GX" + +msgid "Locked" +msgstr "Êëåéäþèçêå" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "Ëïýðá ôùí áñ÷åßùí óôï öÜêåëï" + +msgid "Loop Music" +msgstr "Ëïýðá ôçò ìïõóéêÞò" + +msgid "Loop Sound" +msgstr "Ëïýðá ôïõ Þ÷ïõ" + +msgid "Low Quality" +msgstr "×áìçëÞ ðïéüôçôá" + +msgid "Low/High" +msgstr "×áìçëÞ/ÕøçëÞ" + +msgid "MIOS (Default & Customs)" +msgstr "MIOS (Âáóéêü & ôñïðïðïéçìÝíá)" + +msgid "Main DOL" +msgstr "êýñéï áñ÷åßï .dol" + +msgid "Main GameCube Games Path" +msgstr "ÂáóéêÞ ôïðïèåóßá ðáé÷íéäéþí GameCube" + +msgid "Main GameCube Path" +msgstr "ÂáóéêÞ ôïðïèåóßá GameCube" + +msgid "Main Path" +msgstr "ÂáóéêÞ ôïðïèåóßá" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "MÜñôéïò" + +msgid "Mark new games" +msgstr "ÌáñêÜñéóìá íÝùí ðáé÷íéäéþí" + +msgid "May" +msgstr "Máúïò" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "ÅíçìÝñùóç messageboard ôïõ Wii" + +msgid "Motion+ Video" +msgstr "âéíôåï motion+" + +msgid "Mount DVD drive" +msgstr "Öüñôùóç DVD" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "ðïëëáðëÜ partitions" + +msgid "Music Loop Mode" +msgstr "Íá ëïõðÜñåé ç ìïõóéêÞ;" + +msgid "Music Volume" +msgstr "¸íôáóç ìïõóéêÞò" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "åîïìïßùóç êáíáëéþí åéêïíéêÞò NAND" + +msgid "Nand Channels" +msgstr "êáíÜëéá NAND" + +msgid "Nand Emu Channel Path" +msgstr "ôïðïèåóßá êáíáëéþí åéêïíéêÞò NAND" + +msgid "Nand Emu Path" +msgstr "ôïðïèåóßá åéêïíéêÞò NAND" + +msgid "Nand Emulation" +msgstr "åîïìïßùóç åéêïíéêÞò NAND" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "ç åîïìïßùóç åéêïíéêÞò NAND åßíáé åöéêôÞ ìüíï ìå cIOS d2x!" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "ç åîïìïßùóç åéêïíéêÞò NAND åßíáé åöéêôÞ ìüíï óå partitions FAT/FAT32!" + +msgid "Nand Saves Emulation" +msgstr "saves óôçí åéêïíéêÞ NAND" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "ÊáíÝíá áðü ôá äõï" + +msgid "Network is not initiated." +msgstr "ç óýíäåóç óôï äéáäßêôõï äåí åßíáé åöéêôÞ." + +msgid "Next" +msgstr "Åðüìåíï" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "Ï÷é" + +msgid "No Cheatfile found" +msgstr "Äåí âñÝèçêå áñ÷åßï cheat" + +msgid "No DOL file found on disc." +msgstr "Äåí âñÝèçêå áñ÷åßï DOL óôïí äßóêï." + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "×ùñßò äéá÷ùñéóìü" + +msgid "No URL or Path specified." +msgstr "Äåí ïñßóôçêå URL Þ ôïðïèåóßá." + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "Äåí âñÝèçêå WBFS Þ FAT/NTFS/EXT partition" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "Äåí âñÝèçêå áñ÷åßï Winnertag.xml. ÈÝëåôå íá äçìéïõñãçèåß Ýíá áñ÷åßï-ðáñÜäåéãìá;" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "Äåí åðéëÝ÷èçêáí cheats! ÈÝëåôå íá äéáãñáöåß ôï áñ÷åßï cheat GCT;" + +msgid "No data could be read." +msgstr "Áäýíáôç ç áíÜãíùóç äåäïìÝíùí." + +msgid "No disc inserted." +msgstr "Äåí åéóÞ÷èç äßóêïò." + +msgid "No favorites selected." +msgstr "Äåí åðéëÝ÷èçêáí áãáðçìÝíá." + +msgid "No file missing!" +msgstr "Äåí ëåßðåé êáíÝíá áñ÷åßï!" + +msgid "No games found on the disc" +msgstr "Äåí âñÝèçêáí ðáé÷íßäéá óôïí äßóêï" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "Äåí âñÝèçêáí áñ÷åßá ìåôáöñÜóåùò! ÈÝëåôå íá êáôåâÜóåôå íÝá; " + +msgid "No new updates." +msgstr "Äåí õðÜñ÷ïõí äéáèÝóéìåò áíáâáèìßóåéò." + +msgid "No themes found on the site." +msgstr "Äåí âñÝèçêáí èÝìáôá óôï site." + +msgid "No themes found." +msgstr "Äåí âñÝèçêáí èÝìáôá." + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "ÊáíÝíá" + +msgid "Normal" +msgstr "ÊáíïíéêÜ" + +msgid "Not Initialized" +msgstr "Äåí îåêßíçóå" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "Äåí åßíáé äßóêïò Wii/GameCube" + +msgid "Not a valid URL" +msgstr "Ìç Ýãêõñï URL" + +msgid "Not a valid URL path" +msgstr "Ìç Ýãêõñï ìïíïðÜôé URL" + +msgid "Not a valid domain" +msgstr "Ìç Ýãêõñç ôïðïèåóßá" + +msgid "Not enough free memory." +msgstr "Äåí õðÜñ÷åé áñêåôÞ ìíÞìç äéáèÝóéìç." + +msgid "Not enough free space on device." +msgstr "Äåí õðÜñ÷åé áñêåôüò äéáèÝóéìïò åëåýèåñïò ÷þñïò óôçí óõóêåõÞ." + +msgid "Not enough free space!" +msgstr "Äåí õðÜñ÷åé áñêåôüò äéáèÝóéìïò åëåýèåñïò ÷þñïò!" + +msgid "Not enough memory for FST." +msgstr "Äåí õðÜñ÷åé áñêåôÞ ìíÞìç äéáèÝóéìç ãéá FST." + +msgid "Not enough memory." +msgstr "Äåí õðÜñ÷åé áñêåôÞ ìíÞìç äéáèÝóéìç." + +msgid "Not required" +msgstr "Äåí áðáéôåßôáé" + +msgid "Not supported format!" +msgstr "Ï ôýðïò áñ÷åßïõ äåí õðïóôçñßæåôáé!" + +msgid "Nothing selected to delete." +msgstr "Ôßðïôå Üëëï äåí åðéëÝ÷èçêå ðñïò äéáãñáöÞ." + +msgid "Nothing selected to install." +msgstr "Ôßðïôå Üëëï äåí åðéëÝ÷èçêå ðñïò åãêáôÜóôáóç." + +msgid "Nov" +msgstr "NoÝìâñéïò" + +msgid "OFF" +msgstr "OXI" + +msgid "OK" +msgstr "OK" + +msgid "ON" +msgstr "NAI" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "OSSleepThread" + +msgid "Ocarina" +msgstr "Ocarina" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Oêôþâñéïò" + +msgid "Official Site:" +msgstr "Åðßóçìï Site:" + +msgid "Offset" +msgstr "Offset" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "Müíï ôï partition ôùí ðáé÷íéäéþí" + +msgid "Only for Install" +msgstr "ìüíï ãéá åãêáôÜóôáóç" + +msgid "Original" +msgstr "ÁõèåíôéêÜ" + +msgid "Original/Customs" +msgstr "ÁõèåíôéêÜ/ÔñïðïðïéçìÝíá" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Ãïíéêüò Ýëåã÷ïò" + +msgid "Partial" +msgstr "ÔìçìáôéêÞ" + +msgid "Partition" +msgstr "ÔìÞìá" + +msgid "Password" +msgstr "Password - Kùäéêüò" + +msgid "Password Changed" +msgstr "Ï êùäéêüò Üëëáîå" + +msgid "Password has been changed" +msgstr "Ï êùäéêüò Ý÷åé áëëÜîåé" + +msgid "Patch Country Strings" +msgstr "Patch ðñïÝëåõóçò ðáé÷íéäéïý" + +msgid "Path Changed" +msgstr "ç ôïðïèåóßá Üëëáîå" + +msgid "Permission denied." +msgstr "¢êõñï." + +msgid "Pick from a list" +msgstr "ÅðéëïãÞ áðü ëßóôá" + +msgid "Pixels" +msgstr "Pixel" + +msgid "Play Count" +msgstr "ÌåôñçôÞò ÷ñÞóçò" + +msgid "Play Next" +msgstr "ÁíáðáñáãùãÞ åðüìåíïõ" + +msgid "Play Once" +msgstr "ÁíáðáñáãùãÞ ìéá öïñÜ" + +msgid "Play Previous" +msgstr "ÁíáðáñáãùãÞ ðñïçãïýìåíïõ" + +msgid "Playing Music:" +msgstr "ÁíáðáñáãùãÞ ìïõóéêÞò:" + +msgid "Please wait" +msgstr "Ðáñáêáëþ ðåñéìÝíåôå" + +msgid "Please wait..." +msgstr "Ðáñáêáëþ ðåñéìÝíåôå..." + +msgid "Power off the Wii" +msgstr "Êëåßóôå ôï Wii" + +msgid "Prev" +msgstr "Ðñïçãïýìåíï." + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "ÏëïêëÞñùóç äéáäéêáóßáò." + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "ÅéäïðïéÞóåéò" + +msgid "Published by" +msgstr "¸êäïóç áðü" + +msgid "Quick Boot" +msgstr "¢ìåóç åêêßíçóç" + +msgid "Random Directory Music" +msgstr "Ôõ÷áßï ìïõóéêü áñ÷åßï áðü ôï öÜêåëï" + +msgid "Real Nand" +msgstr "ðñáãìáôéêÞ ìíÞìç NAND" + +msgid "Receiving file from:" +msgstr "ËÞøç áñ÷åßïõ áðü:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "Patch ðåñéï÷Þò ðñïÝëåõóçò" + +msgid "Released" +msgstr "Êõêëïöüñçóå" + +msgid "Reload SD" +msgstr "Åðáíáöüñôùóç êÜñôáò SD" + +msgid "Reloading game list now, please wait..." +msgstr "Åðáíáöüñôùóç ëßóôáò ðáé÷íéäéþí, ðáñáêáëþ ðåñéìÝíåôå..." + +msgid "Remember Unlock" +msgstr "Ìüíéìï îåêëåßäùìá" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "ÁðïìÜêñõíóç áñ÷åßùí áíáâÜèìéóçò." + +msgid "Rename Game Title" +msgstr "Ìåôïíïìáóßá ðáé÷íéäéïý" + +msgid "Rename category" +msgstr "Ìåôïíïìáóßá êáôçãïñßáò" + +msgid "Reset" +msgstr "Åðáíåêêßíçóç" + +msgid "Reset BG Music" +msgstr "ÅðáíáöïñÜ ìïõóéêÞò õðüêñïõóçò." + +msgid "Reset Playcounter" +msgstr "Ìçäåíéóìüò ìåôñçôÞ ÷ñÞóçò;" + +msgid "Reset to default BGM?" +msgstr "ÅðáíáöïñÜ óôçí âáóéêÞ ìïõóéêÞ õðüêñïõóç;" + +msgid "Restarting..." +msgstr "Åðáíåêêßíçóç..." + +msgid "Return" +msgstr "ÅðéóôñïöÞ" + +msgid "Return To" +msgstr "ÅðéóôñïöÞ óå" + +msgid "Return to Wii Menu" +msgstr "" + +msgid "Right" +msgstr "ÄåîéÜ" + +msgid "Rotating Disc" +msgstr "Ðåñéóôñåöüìåíïò ïðôéêüò äßóêïò" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Äüíçóç" + +msgid "SChinese" +msgstr "ÁðëïðïéçìÝíá êéíåæéêá" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "Ìç ðñïóðåëÜóéìç SD." + +msgid "SD GameCube Games Path" +msgstr "Ôïðïèåóßá/ìïíïðÜôé ôßôëùí GameCube óôçí êÜñôá SD" + +msgid "SD GameCube Path" +msgstr "Ôïðïèåóßá/ìïíïðÜôé GameCube óôçí êÜñôá SD" + +msgid "SD Path" +msgstr "Ôïðïèåóßá/ìïíïðÜôé SD" + +msgid "SFX Volume" +msgstr "¸íôáóç ç÷çôéêþí åöÝ" + +msgid "Save" +msgstr "ÁðïèÞêåõóç" + +msgid "Save Failed. No device inserted?" +msgstr "Ç áðïèÞêåõóç áðÝôõ÷å. ÌÞðùò äåí åßíáé óõíäåäåìÝíï ôï áðïèçêåõôéêü ìÝóï;" + +msgid "Save Game List to" +msgstr "ÁðïèÞêåõóç ëßóôáò óå" + +msgid "Save List" +msgstr "ÁðïèÞêåõóç ëßóôáò" + +msgid "Saved" +msgstr "Áðïèçêåýôçêå" + +msgid "Savegame might not exist for this game." +msgstr "ßóùò íá ìçí õðÜñ÷åé save ãéá ôï ðáé÷íßäé áõôü." + +msgid "Screensaver" +msgstr "screen saver" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "ÅðéëïãÞ" + +msgid "Select DOL Offset" +msgstr "ÅðéëïãÞ äåõôåñåýïíôïò DOL" + +msgid "Select a DOL" +msgstr "ÅðéëïãÞ DOL" + +msgid "Select a DOL from Game" +msgstr "ÅðéëïãÞ áñ÷åßïõ DOL áðü ôï ðáé÷íßäé" + +msgid "Select game categories" +msgstr "Êáôçãïñßåò ðáé÷íéäéþí" + +msgid "Select loader mode" +msgstr "ÅðéëïãÞ ðáé÷íéäéþí" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "ÐçãÝò ðáé÷íéäéþí." + +msgid "Sept" +msgstr "ÓåðôÝìâñéïò" + +msgid "Set Search-Filter" +msgstr "Ñýèìéóç áíáæÞôçóçò" + +msgid "Settings" +msgstr "Settings" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "ÐñïâïëÞ êáôçãïñéþí" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "ÐñïâïëÞ åëåýèåñïõ åíáðïìåßíáíôïò ÷þñïõ" + +msgid "Show Play Count" +msgstr "ÐñïâïëÞ óõ÷íüôçôáò ÷ñÞóçò" + +msgid "Show SD" +msgstr "ÐñïâïëÞ êÜñôáò SD" + +msgid "Shutdown System" +msgstr "Këåßóéìï óõóôÞìáôïò" + +msgid "Shutdown Wii" +msgstr "Êëåßóéìï Wii" + +msgid "Skip Errors" +msgstr "Áãíüçóç óöáëìÜôùí" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "Patch åéêüíáò ãéá sneek" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "ÄéÜôáîç áëöáâçôéêÜ" + +msgid "Sort by number of players" +msgstr "ÄéÜôáîç ìå êñéôÞñéï ôïí áñéèìü ðáéêôþí" + +msgid "Sort by rank" +msgstr "ÄéÜôáîç ìå êñéôÞñéï ôï âáèìü" + +msgid "Sort order by most played" +msgstr "ÄéÜôáîç ìå êñéôÞñéï ôçí óõ÷íüôçôá ÷ñÞóçò" + +msgid "Sound" +msgstr "¹÷ïò" + +msgid "Sound Settings" +msgstr "Ñõèìßóåéò Þ÷ïõ" + +msgid "Sound+BGM" +msgstr "¹÷ïò+ìïõóéêÞ õðüêñïõóç." + +msgid "Sound+Quiet" +msgstr "¹÷ïò+ðáýóç" + +msgid "Spanish" +msgstr "ÉóðáíéêÜ" + +msgid "Special thanks to:" +msgstr "ÈåñìÝò åõ÷áñéóôßåò:" + +msgid "Split each 2GB" +msgstr "Äéá÷ùñéóìüò óå ôìÞìáôá 2GB" + +msgid "Split each 4GB" +msgstr "Äéá÷ùñéóìüò óå ôìÞìáôá 4GB" + +msgid "Standby" +msgstr "ÁíáìïíÞ" + +msgid "Start" +msgstr "Start" + +msgid "Success" +msgstr "Åðéôõ÷Þò" + +msgid "Success." +msgstr "Åðéôõ÷Þò." + +msgid "Success:" +msgstr "Åðéôõ÷Þò:" + +msgid "Successfully Saved" +msgstr "Áðïèçêåýôçêå" + +msgid "Successfully Updated" +msgstr "Åðéôõ÷Þò áíáâÜèìéóç" + +msgid "Successfully copied" +msgstr "Åðéôõ÷Þò áíôéãñáöÞ" + +msgid "Successfully deleted:" +msgstr "Åðéôõ÷Þò äéáãñáöÞ:" + +msgid "Successfully extracted theme." +msgstr "Åðéôõ÷Þò ìåôáöïñÜ èÝìáôïò." + +msgid "Successfully installed:" +msgstr "Åðéôõ÷Þò åãêáôÜóôáóç:" + +msgid "Successfully updated." +msgstr "Åðéôõ÷Þò áíáâÜèìéóç." + +msgid "Switching to channel list mode." +msgstr "ÁëëáãÞ åìöÜíéóçò óå ëßóôá." + +msgid "Sync FAT32 FS Info" +msgstr "Óõã÷ñïíéóìüò FAT32" + +msgid "Synchronizing..." +msgstr "Óõã÷ñïíéóìüò..." + +msgid "System Default" +msgstr "Âáóéêü-ç óõóôÞìáôïò" + +msgid "TChinese" +msgstr "ÐáñáäïóéáêÜ êéíÝæéêá" + +msgid "TXT Cheatcodes Path" +msgstr "ôïðïèåóßá áñ÷åßùí cheats TXT" + +msgid "The .them file was not found in the zip." +msgstr "To áñ÷åßï .them äåí âñÝèçêå óôïí öÜêåëï zip." + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "Ç ñýèìéóç ãéá åðéâïëÞ áíáëïãßáò ïèüíçò 16:9 áðáéôåß DIOS MIOS 2.1 Þ íåüôåñï. Ç ðáñïýóá ñýèìéóç èá áãíïçèåß." + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Ôá Mii èá áíôéãñáöïýí óôçí ôïðïèåóßá åéêïíéêÞò NAND. Ðñïóï÷Þ, üëá ôá êïéíÜ õðÜñ÷ïíôá áñ÷åßá èá áíôéêáôáóôáèïýí." + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "Ç ñýèìéóç No Disc+ áðáéôåß ôï DIOS MIOS 2.2 update 2. Ç ðáñïýóá ñýèìéóç èá áãíïçèåß." + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Ôï áñ÷åßï SYSCONF èá áíôéãñáöåß óôçí åéêïíéêÞ NAND. Ðñïóï÷Þ: üëá ôá êïéíÜ õðÜñ÷ïíôá áñ÷åßá èá áíôéêáôáóôáèïýí." + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "Ôï ðñüãñáììá ìðïñåß íá ìðëïêÜñåé áí õðÜñîåé ôáõôü÷ñïíç áíÜãíùóç/åããñáöÞ óôçí êÜñôá SD!" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "Ç ïñéóìÝíç ôïðïèåóßá äåí õðÜñ÷åé. Èá èÝëáôå íá äçìéïõñãÞóåôå ôïí öÜêåëï;" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "Ôá áñ÷åßá èá áðïóõìðéåóôïýí óôç emunand.Ðñïóï÷Þ:üëá ôá ðñïýðÜñ÷ïíôá áñ÷åßá èá áíôéêáôáóôáèïýí" + +msgid "The game is on SD Card." +msgstr "Ôï ðáé÷íßäé áõôü âñßóêåôáé óôç êÜñôá SD." + +msgid "The game is on USB." +msgstr "Ôï ðáé÷íßäé áõôü âñßóêåôáé óôïí äßóêï USB." + +msgid "The save game will be extracted to your emu nand path." +msgstr "Ôï save óáò èá áíôéãñáöåß óôçí emunand." + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "Ôá save óáò èá áíôéãñáöïýí óôçí emunand. Ðñïóï÷Þ: üëá ôá ðñïûðÜñ÷ïíôá áñ÷åßá èá áíôéêáôáóôáèïýí" + +msgid "The wad file was installed" +msgstr "Ôï áñ÷åßï WAD åãêáôáóôÜèçêå" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "Ç åãêáôÜóôáóç ôïõ áñ÷åßïõ WAD áðÝôõ÷å, ìå ôï ëÜèïò %i" + +msgid "Theme Downloader" +msgstr "ÊáôåâÜóôå íÝá èÝìáôá" + +msgid "Theme Menu" +msgstr "Ñõèìßóåéò èåìÜôùí" + +msgid "Theme Path" +msgstr "Ôïðïèåóßá èåìÜôùí" + +msgid "Theme Title:" +msgstr "üíïìá èÝìáôïò:" + +msgid "Themes by www.spiffy360.com" +msgstr "ÈÝìáôá áðü ôçí éóôïóåëßäá www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "Ôï ÉÏS áõôü åßíáé ôïõ ëåéôïõñãéêïý BootMii. Áí üìùò åßóôå âÝâáéïò-ç üôé äåí åßíáé, ðáñáêáëþ áãíïÞóôå áõôÞ ôçí ðñïåéäïðïßçóç ." + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "Ôï ÉÏS áõôü äåí âñÝèçêå óôçí ëßóôá. Áí åßóôå âÝâáéïò-ç üôé ôï Ý÷åôå åãêáôåóôçìÝíï, ðáñáêáëþ áãíïÞóôå áõôÞ ôçí ðñïåéäïðïßçóç." + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "Ôï ìïíïðÜôé áõôü ðñÝðåé íá êáôåõèýíåé óå áñ÷åßï óôçí êÜñôá SD!" + +msgid "Time left:" +msgstr "×ñüíïò ðïõ áðïìÝíåé:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "ÅêêéíçôÞò ôßôëùí" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "Ôßôëïé áðü ôï GameTDB" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "Ãéá áíáðáñáãùãÞ ôßôëùí Gamecube áðü ôïõò áõèåíôéêïýò äßóêïõò ôïõò, ðñÝðåé íá ïñßóåôå ôçí åðéëïãÞ Gamecube óå ÌÉÏS, óôéò ñõèìßóåéò êÜèå ôßôëïõ." + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "ÊáèõóôÝñçóç åìöÜíéóçò åôéêåôþí" + +msgid "Tooltips" +msgstr "ÅôéêÝôåò" + +msgid "Transfer failed" +msgstr "Áíåðéôõ÷Þò ìåôáöïñÜ áñ÷åßùí" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "Ôï USB Loader GX åßíáé ðñïóôáôåõìÝíï" + +msgid "USB Port" +msgstr "Èýñá USB" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "Ç áëëáãÞ èýñáò USB õðïóôçñßæåôáé ìüíï áðü ôï cIOS Hermes." + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "ÁðåãêáôÜóôáóç" + +msgid "Uninstall Game" +msgstr "ÁðåãêáôÜóôáóç ðáé÷íéäéïý" + +msgid "Uninstall Menu" +msgstr "ÁðåãêáôÜóôáóç ìåíïý" + +msgid "Uninstall all" +msgstr "ÁðåãêáôÜóôáóç üëùí" + +msgid "Unknown" +msgstr "¢ãíùóôï" + +msgid "Unlock USB Loader GX" +msgstr "Îåêëåßäùìá USB Loader GX" + +msgid "Unlocked" +msgstr "Îåêëåéäþèçêå" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "Ìç óõìâáôüò ôýðïò áñ÷åßïõ, äïêéìÜóôå íá áðïóõìðéÝóåôå ôïí öÜêåëï TempTheme.zip." + +msgid "Update" +msgstr "AíáâÜèìéóç" + +msgid "Update All" +msgstr "ÁíáâÜèìéóç üëùí" + +msgid "Update DOL" +msgstr "ÁíáâÜèìéóç DOL" + +msgid "Update Files" +msgstr "ÁíáâÜèìéóç áñ÷åßùí" + +msgid "Update Path" +msgstr "ÌïíïðÜôé áñ÷åßùí áíáâÜèìéóçò." + +msgid "Update all Language Files" +msgstr "ÁíáâÜèìéóç üëùí ôùí ìåôáöñÜóåùí" + +msgid "Update failed" +msgstr "Áðïôõ÷ßá áíáâÜèìéóçò" + +msgid "Update successfull" +msgstr "Åðéôõ÷Þò áíáâÜèìéóç" + +msgid "Updating Language Files:" +msgstr "ÁíáâÜèìéóç áñ÷åßùí ìåôáöñÜóåùí:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "ÁíáâáèìßóìÝíï áñ÷åßï ZIP åãêáôáóôÜèçêå óôçí êáôçãïñßá Homebrew." + +msgid "Use System Font" +msgstr "×ñÞóç ãñáììáôïóåéñÜò óõóôÞìáôïò" + +msgid "Use global" +msgstr "×ñÞóç âáóéêïý" + +msgid "VBI (Default)" +msgstr "VBI (ÐñïêáèïñéìÝíï)" + +msgid "VIDTV Patch" +msgstr "Patch VIDTV" + +msgid "Version:" +msgstr "¸êäïóç:" + +#, c-format +msgid "Version: %s" +msgstr "¸êäïóç: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Ñýèìéóç âßíôåï" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "Ôá÷ýôçôá åéêïíéêïý äåßêôç" + +msgid "WDM Files Path" +msgstr "ÌïíïðÜôé áñ÷åßùí WDM" + +msgid "WIP Patches Path" +msgstr "ÌïíïðÜôé áñ÷åßùí WIP patches" + +msgid "Waiting..." +msgstr "AíáìïíÞ..." + +msgid "Warning" +msgstr "Ðñïóï÷Þ" + +msgid "Warning:" +msgstr "Ðñïóï÷Þ:" + +msgid "What do you want to do?" +msgstr "Ôé èá èÝëáôå íá êÜíåôå?" + +msgid "What do you want to update?" +msgstr "Ôé èá èÝëáôå íá áíáâáèìßóåôå?" + +msgid "What should be deleted for this game title:" +msgstr "Ôé èá èÝëáôå íá äéáãñÜøåôå áðü áõôü ôïí ôßôëï:" + +msgid "What to extract from NAND?" +msgstr "Ôé íá ìåôáöåñèåß áðü ôç ìíÞìç NAND?" + +msgid "Where should the game be installed to?" +msgstr "Ðïõ íá åãêáôáóôáèåß ôï ðáé÷íßäé;" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "Ëåéôïõñãßåò wi-fi" + +msgid "Widescreen Factor" +msgstr "ÓõíôåëåóôÞò ãéá widescreen" + +msgid "Widescreen Fix" +msgstr "Äéüñèùóç ãéá åõñåßåò ïèüíåò" + +msgid "Wii Games" +msgstr "Ðáé÷íßäéá Wii" + +msgid "Wii Menu" +msgstr "Ìåíïý ôïõ Wii" + +msgid "Wii Settings" +msgstr "Ñõèìßóåéò ôïõ Wii" + +msgid "WiiTDB.xml" +msgstr "WiiTDB.xml" + +msgid "WiiTDB.xml is up to date." +msgstr "Ôï áñ÷åßï WiiTDB.xml åßíáé åíçìåñùìÝíï" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "ËÜìðáêé DVD drive ôïõ Wii" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "Wiinnertag" + +msgid "Wiinnertag Path" +msgstr "ÌïíïðÜôé áñ÷åßùí wiinnertag" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Ôï Wiinnertag áðáéôåß íá Ý÷åôå åíåñãïðïéÞóåé ôçí áõôüìáôç óýíäåóç ôçò åöáñìïãÞò óôï äéáäßêôõï êáôá ôçí åêêßíçóç ôïõ. ÈÝëåôå íá ôçí åíåñãïðïéÞóåôå ôþñá;" + +msgid "Wiird Debugger" +msgstr "×ñÞóç Wiird Debugger" + +#, c-format +msgid "Write error on file: %s" +msgstr "ÃñÜøéìï ôïõ ëÜèïõò óôï áñ÷åßï: %s" + +msgid "Writing GXGameCategories.xml" +msgstr "ÃñÜöåôáé ôï áñ÷åßï Categories.xml" + +msgid "Wrong Password" +msgstr "ËáíèáóìÝíïò êùäéêüò" + +msgid "Yes" +msgstr "Íáé" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "Ðñïóðáèåßôå íá åðéëÝîåôå åíá partition FAT32/NTFS/EXT ìå cIOS 249 Ýêäïóçò < 18. Áõôü äåí õðïóôçñßæåôáé. Ðñï÷ùñÞóôå ìå äéêÞ óáò åõèýíç." + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "Ìðïñåßôå íá åðéëÝîåôå Þ íá åðáíáóõãêñïôÞóåôå åíá partition Þ íá ÷ñçóéìïðïéÞóåôå ôçí åðéëïãÞ channel loader." + +msgid "You cannot delete this category." +msgstr "Äåí ìðïñåßôå íá äéáãñÜøåôå áõôÞí ôçí êáôçãïñßá." + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "ÐñÝðåé íá åãêáôáóôÞóåéò ôï DIOS MIOS Lite v1.2 Þ ìéá íåüôåñç Ýêäïóç." + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "äéÜñêåéá åóôßáóçò (Ôá÷ýôçôá)" + +msgid "and translators for language files updates" +msgstr "êáé ôïõò ìåôáöñáóôÝò ãéá ôéò áíáâáèìßóåéò óôéò äéáèÝóéìåò ãëþóóåò ôïõ ðñïãñÜììáôïò" + +msgid "available" +msgstr "äéáèÝóéìï" + +msgid "does not exist!" +msgstr "äåí õðÜñ÷åé!" + +msgid "does not exist! Loading game without cheats." +msgstr "äåí âñÝèçêå. Öüñôùóç ðáé÷íéäéïý ÷ùñßò cheats." + +msgid "files left" +msgstr "åíáðïìåßíáíôá áñ÷åßá" + +msgid "for FAT/NTFS support" +msgstr "ãéá õðïóôÞñéîç FAT/NTFS" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "ãéá ôï GameTDB êáé ôçí áðïèÞêåõóç åîùöýëëùí / åéêüíùí äßóêùí" + +msgid "for Ocarina" +msgstr "ãéá ôï Ocarina" + +msgid "for diverse patches" +msgstr "ãéá äéÜöïñá patches" + +msgid "for his awesome tool LibWiiGui" +msgstr "ãéá ôï áðßèáíï åñãáëåßï ôïõ LibWiiGui" + +msgid "for hosting the themes" +msgstr "ãéá ôçí áðïèÞêåõóç ôùí èåìÜôùí" + +msgid "for the USB Loader source" +msgstr "ãéá ôïí êþäéêá ôïõ 'USB Loader" + +msgid "for their work on the wiki page" +msgstr "ãéá ôçí äïõëåéÜ ôïõò óôçí óåëßäá ìáò óôï wiki" + +msgid "formatted!" +msgstr "áíáóõãêñïôÞèçêå!" + +msgid "free" +msgstr "åëåõèåñá" + +msgid "ms" +msgstr "ms" + +msgid "not set" +msgstr "äåí ïñßóôçêå" + +msgid "of" +msgstr "áðü" + +msgid "seconds left" +msgstr "äåõôåñüëåðôá áðïìÝíïõí" + +#~ msgid "Install WAD to EmuNand" +#~ msgstr "ÅãêáôÜóôáóç WAD óôçí åéêïíéêÞ NAND" + +#~ msgid "WAD Installation" +#~ msgstr "ÅãêáôÜóôáóç WAD" + +#~ msgid "GameTDB Path" +#~ msgstr "Äéåýèõíóç/ìïíïðÜôé áñ÷åßïõ GameTDB" + +#~ msgid "Anti" +#~ msgstr "ÊáôÜ" + +#~ msgid "Error 002 fix" +#~ msgstr "Äéüñèùóç óöÜëìáôïò 002" + +#~ msgid "Use Game Settings" +#~ msgstr "×ñÞóç ñõèìßóåùí óõóôÞìáôïò" + +#~ msgid "Main tester:" +#~ msgstr "Kýñéïò äïêéìáóôÞò:" + +#~ msgid "USB Device not found." +#~ msgstr "Äåí âñÝèçêå ç óõóêåõÞ USB." + +#~ msgid "Boot/Standard" +#~ msgstr "Åêêéíçóç/Âáóéêü" + +#~ msgid "DEVO MemCard Emulation" +#~ msgstr "åîïìïßùóç ôçò memory card áðü ôï devolution" + +#~ msgid "DML Auto" +#~ msgstr "áõôüìáôá áðü ôï DML" + +#~ msgid "DML Debug" +#~ msgstr "Debug DML" + +#~ msgid "DML Force Widescreen" +#~ msgstr "ÅðéâïëÞ åõñåßáò áðåéêüíéóçò áðü ôï DML" + +#~ msgid "DML Japanese Patch" +#~ msgstr "Patch ãéá éáðùíéêá games áðü ôï DML" + +#~ msgid "DML LED Activity" +#~ msgstr "Ëåéôïõñãßá ëõ÷íßáò ôïõ Wii áðü ôï DML" + +#~ msgid "DML NMM Mode" +#~ msgstr "÷ñÞóç NMM áðü DML" + +#~ msgid "DML No Disc+" +#~ msgstr "åðéëïãÞ No Disc+ áðü ôï DML" + +#~ msgid "DML None" +#~ msgstr "êáìßá ðáñåìâïëÞ áðü ôï DML" + +#~ msgid "DML PAD Hook" +#~ msgstr "PAD hook DML" + +#~ msgid "DML Progressive Patch" +#~ msgstr "Patch óôçí åéêüíá áðü ôï DML" + +#~ msgid "DML Video Mode" +#~ msgstr "åðéëïãÞ video ñõèìßóåùí áðü ôï DML" + +#~ msgid "To run GameCube games with DIOS MIOS you need to place them on an USB FAT32 partition." +#~ msgstr "Ãéá áíáðáñáãùãÞ ôßôëùí Gamecube ìå ôï ðñüãñáììá DIOS MIOS ðñÝðåé íá ôïõò ôïðïèåôÞóåôå óå åíá USB FAT32 partition." + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' to an USB FAT32 partition." +#~ msgstr "Ãéá áíáðáñáãùãÞ ôßôëùí Gamecube ìå ôï ðñüãñáììá DIOS MIOS ðñÝðåé íá ïñßóåôå ôï 'êýñéï ïíïðÜôé Gamecube' óå åíá USB FAT32 partition." + +#~ msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Path." +#~ msgstr "Ãéá áíáðáñáãùãÞ ôßôëùí Gamecube ìå ôï ðñüãñáììá devolution ÷ñåéÜæåóôå ôï áñ÷åßï loader.bin óôï êáèïñéìÝíï ìïíïðÜôé ôïõ devolution." + +#~ msgid "You need to install Devolution or DIOS MIOS (Lite) to launch GameCube games from USB or SD card" +#~ msgstr "ÐñÝðåé íá åãêáôáóôÞóåôå ôï Devolution Þ ôï DIOS MIOS (Lite) ãéá íá ðáßîåôå ôßôëïõò GameCube áðü USB Þ SD" + +#~ msgid "DML No Disc" +#~ msgstr "åðéëïãÞ No-disc áðü ôï DML" + +#~ msgid "The No Disc setting is not used anymore by DIOS MIOS (Lite). Now you need to place a disc in your drive." +#~ msgstr "Ç ñýèìéóç No Disc äåí õðïóôçñßæåôáé ðëÝïí áðü ôï DIOS MIOS (Lite). ÐëÝïí ðñÝðåé íá ôïðïèåôÞóåôå åíá game disc óôï Wii." + +#~ msgid "Control level" +#~ msgstr "Åðßðåäï åëÝã÷ïõ" + +#~ msgid "Return to Wii " +#~ msgstr "ÅðéóôñïöÞ óôï êåíôñéêü ìåíïý ôïõ Wii" + +#~ msgid "The GCT Cheatcodes Path and this game are not on the same partition. Run the game without Ocarina?" +#~ msgstr "Ç ôïðïèåóßá áñ÷åßùí cheats GCT êáé ôï ðáé÷íßäé áõôü äåí âñßóêïíôáé óï ßäéï partition. ÈÝëåôå íá åêêéíÞóåôå ôïí ôßôëï ÷ùñßò cheats; " + +#~ msgid "The GCT Cheatcodes Path must be on SD card. Run the game without Ocarina?" +#~ msgstr "Ôá áñ÷åßá cheats GCT ðñÝðåé íá âñßóêïíôáé óôçí êÜñôá SD. ÈÝëåôå íá åêêéíÞóåôå ôïí ôßôëï ÷ùñßò cheats;" diff --git a/Languages/hungarian.lang b/Languages/hungarian.lang new file mode 100644 index 0000000..11ded18 --- /dev/null +++ b/Languages/hungarian.lang @@ -0,0 +1,2928 @@ +# USB Loader GX language source file. +# hungarian.lang - r878 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:02+0200\n" +"PO-Revision-Date: 2009-12-29 11:05+0100\n" +"Last-Translator: Springdale\n" +"Language-Team: Tusk, Springdale\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr "nem letölthetõ." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr "elmentve. A fájl nincs ellenõrizve, és egyes kódok nem feltétlenül működnek együtt. Probléma esetén további információért nyisd meg a fájlt szövegszerkesztõvel." + +msgid " is not on the server." +msgstr "nincs a szerveren." + +#, c-format +msgid "%i files not found on the server!" +msgstr "" + +#, c-format +msgid "%i missing files" +msgstr "" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Mindenkinek)" + +msgid "1 (Child 7+)" +msgstr "1 (Gyermekeknek 12+)" + +msgid "1 hour" +msgstr "1 óra" + +msgid "10 min" +msgstr "10 perc" + +msgid "2 (Teen 12+)" +msgstr "2 (Tinédzserek 14+)" + +msgid "20 min" +msgstr "20 perc" + +msgid "2D Cover Path" +msgstr "2D Boritó Útvonala" + +msgid "3 (Mature 16+)" +msgstr "3 (Kamaszok 16+)" + +msgid "3 min" +msgstr "3 perc" + +msgid "30 min" +msgstr "30 perc" + +msgid "3D Cover Path" +msgstr "3D Boritó Útvonala" + +msgid "3D Covers" +msgstr "3D Borítók" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Felnõtteknek 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 perc" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "" + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "" + +msgid "All Partitions" +msgstr "" + +msgid "All files extracted." +msgstr "" + +msgid "All images downloaded successfully." +msgstr "" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Az USB Loader GX minden funkciója elérhetõ." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Alternatív DOL" + +msgid "An example file was created here:" +msgstr "" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "Nyelv" + +msgid "Apply" +msgstr "" + +msgid "Apr" +msgstr "Ápr" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "" + +msgid "Are you sure?" +msgstr "Biztos vagy benne?" + +msgid "Aspect Ratio" +msgstr "" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "" + +msgid "Author(s):" +msgstr "" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "Hálózat AutoInit" + +msgid "BCA Codes Path" +msgstr "BCA kód útvonal" + +msgid "Back" +msgstr "Vissza" + +msgid "Back to HBC or Wii Menu" +msgstr "Visszatérés a HBC-be vagy Wii Menübe" + +msgid "Backgroundmusic" +msgstr "Háttérzene" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "Köszönet:" + +msgid "Block Categories Menu" +msgstr "" + +msgid "Block Categories Modify" +msgstr "" + +msgid "Block Cover Downloads" +msgstr "" + +msgid "Block Custom Paths" +msgstr "" + +msgid "Block Feature Settings" +msgstr "" + +msgid "Block Game Install" +msgstr "" + +msgid "Block Game Settings" +msgstr "" + +msgid "Block GameID Change" +msgstr "" + +msgid "Block Global Settings" +msgstr "" + +msgid "Block Gui Settings" +msgstr "" + +msgid "Block HBC Menu" +msgstr "" + +msgid "Block Hard Drive Settings" +msgstr "" + +msgid "Block IOS Reload" +msgstr "IOS újratöltés blokkolása" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "" + +msgid "Block Parental Settings" +msgstr "" + +msgid "Block Priiloader Override" +msgstr "" + +msgid "Block Reset Settings" +msgstr "" + +msgid "Block SD Reload Button" +msgstr "" + +msgid "Block Sound Settings" +msgstr "" + +msgid "Block Theme Downloader" +msgstr "" + +msgid "Block Theme Menu" +msgstr "" + +msgid "Block Title Launcher" +msgstr "" + +msgid "Block Updates" +msgstr "" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "" + +msgid "Both" +msgstr "Mindkettõ" + +msgid "Both Ports" +msgstr "" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "" + +msgid "Can't be formatted" +msgstr "Nem Formázható" + +msgid "Can't create directory" +msgstr "Mappa nem hozható létre" + +#, c-format +msgid "Can't create file: %s" +msgstr "" + +#, c-format +msgid "Can't create path: %s" +msgstr "" + +msgid "Can't delete:" +msgstr "Nem törölhetõ" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "" + +#, c-format +msgid "Can't read file: %s" +msgstr "" + +msgid "Cancel" +msgstr "Mégse" + +msgid "Cannot write to destination." +msgstr "" + +msgid "Categories" +msgstr "" + +msgid "Categories:" +msgstr "" + +msgid "Change Play Path" +msgstr "" + +msgid "Channel Launcher" +msgstr "" + +msgid "Channels" +msgstr "Csatornák" + +msgid "Cheatfile is blank" +msgstr "A cheat-fájl üres" + +msgid "Clear" +msgstr "" + +msgid "Click to Download Covers" +msgstr "Kattints a borítók letöltéséhez" + +msgid "Click to change game ID" +msgstr "Kattints a játékID megváltoztatásához" + +msgid "Clock" +msgstr "Óra" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "Bezárás" + +msgid "Code Download" +msgstr "Kód letöltés" + +#, c-format +msgid "Coded by: %s" +msgstr "Kódolás: %s" + +msgid "Coding:" +msgstr "Kódolás:" + +msgid "Connection to server timed out." +msgstr "" + +msgid "Console" +msgstr "Konzol" + +msgid "Console Default" +msgstr "Konzol Alapértelmezett" + +msgid "Console Locked" +msgstr "Konzol Zárolva" + +msgid "Console must be unlocked for this option." +msgstr "" + +msgid "Console must be unlocked to be able to use this." +msgstr "" + +msgid "Console should be unlocked to modify it." +msgstr "A konzol zárolva, ezért nem változtatható meg." + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "Játék telepítésének folytatása?" + +msgid "Continue?" +msgstr "" + +msgid "Controllevel" +msgstr "Kontrollszint" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "Helyes Jelszó" + +msgid "Could not connect to the server." +msgstr "" + +msgid "Could not create GCT file" +msgstr "Nem hozható létre GCT fájl" + +#, c-format +msgid "Could not create path: %s" +msgstr "" + +msgid "Could not extract files for:" +msgstr "" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "" + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "DIP modul nem tölthetõ be!" + +msgid "Could not initialize network!" +msgstr "Kapcsolat nem hozható létre!" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "Lemez nem betölthetõ" + +msgid "Could not open the WiiTDB.xml file." +msgstr "" + +msgid "Could not open wiitdb.xml." +msgstr "" + +msgid "Could not save." +msgstr "A mentés nem sikerült." + +msgid "Could not write file." +msgstr "" + +msgid "Could not write to:" +msgstr "" + +msgid "Cover Download" +msgstr "Boritó Letöltés" + +msgid "Create" +msgstr "Létrehozás" + +msgid "Credits" +msgstr "Készítõk" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "Egyéni útvonalak" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "Egyéni/Eredeti" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "DOL Útvonal" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "" + +msgid "Default" +msgstr "Alapértelmezett" + +msgid "Default Gamesettings" +msgstr "Alapértelmezett beállítások" + +msgid "Default Settings" +msgstr "Alapértelmezett beállítások" + +msgid "Delete" +msgstr "Törlés" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "Cheat GCT törlés" + +msgid "Delete Cheat TXT" +msgstr "Cheat TXT törlés" + +msgid "Delete Cover Artwork" +msgstr "Borító törlése" + +msgid "Delete Disc Artwork" +msgstr "Lemezfotó törlése" + +msgid "Delete category" +msgstr "" + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "Felület:" + +msgid "Details" +msgstr "" + +msgid "Developed by" +msgstr "Készítette" + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "A könyvtár nem létezik!" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "Lemezfotó letöltése" + +msgid "Disc Artwork Path" +msgstr "Lemezképek Útvonala" + +msgid "Disc Default" +msgstr "Lemez Alapértelmezettje" + +msgid "Disc Insert Detected" +msgstr "" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "Lemezforgatás" + +msgid "Display" +msgstr "Játékinfo megj." + +msgid "Display as a carousel" +msgstr "Körhinta megjelenítés" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "Rács megjelenítés" + +msgid "Display as a list" +msgstr "Lista megjelenítés" + +msgid "Display favorites only" +msgstr "" + +msgid "Do you want to apply it now?" +msgstr "Alkalmazás most?" + +msgid "Do you want to apply this theme?" +msgstr "" + +msgid "Do you want to change language?" +msgstr "Nyelv megváltoztatása?" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "Téma letöltése?" + +msgid "Do you want to extract all the save games?" +msgstr "" + +msgid "Do you want to extract the save game?" +msgstr "" + +msgid "Do you want to format:" +msgstr "Formázás?" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "" + +msgid "Do you wish to update/download all language files?" +msgstr "Minden nyelvi fájl letöltése/frissítése?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "Letöltés" + +msgid "Download Now" +msgstr "Letöltés most" + +msgid "Download finished" +msgstr "Letöltés kész" + +msgid "Downloading 3D Covers" +msgstr "" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "" + +msgid "Downloading Full HQ Covers" +msgstr "" + +msgid "Downloading Full LQ Covers" +msgstr "" + +msgid "Downloading custom Discarts" +msgstr "" + +msgid "Downloading file..." +msgstr "" + +msgid "Downloading image:" +msgstr "Kép letöltése:" + +msgid "Downloading original Discarts" +msgstr "" + +msgid "Downloading pagelist:" +msgstr "" + +msgid "Dump NAND to EmuNand" +msgstr "" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "Holland" + +msgid "ERROR" +msgstr "HIBA" + +msgid "ERROR:" +msgstr "HIBA:" + +msgid "ERROR: Can't set up theme." +msgstr "HIBA: Téma nem állítható be" + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "" + +msgid "Emulated Nand" +msgstr "" + +msgid "English" +msgstr "Angol" + +msgid "Enter Path" +msgstr "" + +msgid "Error" +msgstr "Hiba" + +msgid "Error !" +msgstr "Hiba !" + +#, c-format +msgid "Error creating path: %s" +msgstr "" + +msgid "Error opening downloaded file" +msgstr "" + +msgid "Error reading Disc" +msgstr "Lemezolvasási hiba" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "" + +msgid "Error while downloding file" +msgstr "" + +msgid "Error while opening the zip." +msgstr "" + +msgid "Error while transfering data." +msgstr "Adatátviteli hiba." + +msgid "Error while updating USB Loader GX." +msgstr "" + +msgid "Error writing the data." +msgstr "" + +msgid "Error:" +msgstr "Hiba:" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "" + +msgid "Everything" +msgstr "" + +msgid "Exit" +msgstr "" + +msgid "Exit to where?" +msgstr "" + +msgid "Export All Saves to EmuNand" +msgstr "" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "" + +msgid "Extracting file:" +msgstr "" + +msgid "Extracting files..." +msgstr "Fájlok kicsomagolása..." + +msgid "Extracting files:" +msgstr "" + +msgid "Extracting nand files:" +msgstr "" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "Formázás sikertelen" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "" + +msgid "Failed to extract." +msgstr "A kicsomagolás nem sikerült." + +msgid "Failed to initialize the USB storage device." +msgstr "" + +msgid "Failed to open partition" +msgstr "Hiba a partíció megnyitásakor" + +msgid "Failed to read ticket." +msgstr "" + +msgid "Failed to read tmd file." +msgstr "" + +msgid "Failed to read wad header." +msgstr "" + +msgid "Failed updating" +msgstr "" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "" + +msgid "Features Settings" +msgstr "" + +msgid "Feb" +msgstr "" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Fájl nem található" + +msgid "File read/write error." +msgstr "" + +msgid "Files extracted successfully." +msgstr "" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "" + +msgid "Filesize is 0 Byte." +msgstr "" + +msgid "Flat Covers" +msgstr "" + +msgid "Flip-X" +msgstr "" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "" + +msgid "Force NTSC480p" +msgstr "" + +msgid "Force PAL480p" +msgstr "" + +msgid "Force PAL50" +msgstr "" + +msgid "Force PAL60" +msgstr "" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Formázás" + +msgid "Formatting, please wait..." +msgstr "Formatálás folyamatban, kérlek várj..." + +msgid "Found missing images." +msgstr "" + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "Szabad Hely" + +msgid "French" +msgstr "Francia" + +msgid "Full" +msgstr "" + +msgid "Full Cover Path" +msgstr "" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "" + +msgid "GAMEID_Gamename" +msgstr "" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "Kódok Útvonala" + +msgid "GCT File created" +msgstr "GCT Fájl létrehozva" + +msgid "GUI Settings" +msgstr "Kezelõfelület" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "Játék ID" + +msgid "Game IOS" +msgstr "" + +msgid "Game Language" +msgstr "Játéknyelv" + +msgid "Game Load" +msgstr "Játék Betöltés" + +msgid "Game Lock" +msgstr "" + +msgid "Game Only" +msgstr "" + +msgid "Game Region" +msgstr "Játék Régió" + +msgid "Game Size" +msgstr "Játék Méret" + +msgid "Game Sound Mode" +msgstr "Játék Banner hang" + +msgid "Game Sound Volume" +msgstr "Játék Banner hangerő" + +msgid "Game Split Size" +msgstr "" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "A játék már fel van telepítve:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "" + +msgid "Games" +msgstr "Játékok" + +msgid "Generating GXGameCategories.xml" +msgstr "" + +msgid "Genre:" +msgstr "" + +msgid "German" +msgstr "Német" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "HOME Menü" + +msgid "Hard Drive Settings" +msgstr "" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "Homebrew Útvonal" + +msgid "Homebrew Channel" +msgstr "" + +msgid "Homebrew Launcher" +msgstr "Homebrew indító" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "Óra" + +msgid "How do you want to update?" +msgstr "Hogyan szeretnél frissíteni?" + +msgid "How to Shutdown?" +msgstr "Hogyan kapcsoljon ki?" + +msgid "Import Categories" +msgstr "" + +msgid "Import operation successfully completed." +msgstr "" + +msgid "Importing categories" +msgstr "" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Bejövõ fájl %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Bejövõ fájl %0.2fMB" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "Hálózat inicializálása..." + +msgid "Insert Disk" +msgstr "Helyezz be egy lemezt" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "Telepítés" + +msgid "Install Canceled" +msgstr "" + +msgid "Install Directories" +msgstr "" + +msgid "Install Error!" +msgstr "Telepítési Hiba!" + +msgid "Install Partitions" +msgstr "" + +msgid "Install a game" +msgstr "Játék telepítése" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "" + +msgid "Installing game:" +msgstr "Játék telepítése" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Számunkra segítõ információid lehetnek - kérlek továbbítsd ezeket a fejlesztõi csapat felé." + +msgid "Italian" +msgstr "Olasz" + +msgid "Jan" +msgstr "" + +msgid "Japanese" +msgstr "Japán" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "Júl" + +msgid "June" +msgstr "Jún" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Billenyûzet" + +msgid "Korean" +msgstr "Koreai" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "" + +msgid "Language change:" +msgstr "Nyelv választás:" + +msgid "Languagefiles Path" +msgstr "" + +msgid "Languagepath changed." +msgstr "Nyelvek útvonala megváltozott." + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Left" +msgstr "Balra" + +msgid "Like SysMenu" +msgstr "Mint a Rendszermenü" + +msgid "List on Gamelaunch" +msgstr "" + +msgid "Load" +msgstr "Betöltés" + +msgid "Load From SD/USB" +msgstr "Betöltés SD/USB-rõl" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Fájl betöltése innen: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "DOL betöltése alternatív DOL-ként?" + +msgid "Loader Settings" +msgstr "" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "Alapnyelv betõltése" + +msgid "Loading standard music." +msgstr "Alapzene betõltése" + +msgid "Lock Console" +msgstr "Konzol Lezárása" + +msgid "Lock USB Loader GX" +msgstr "" + +msgid "Locked" +msgstr "Lezárva" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "" + +msgid "Loop Music" +msgstr "" + +msgid "Loop Sound" +msgstr "Folyamatos hang" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "Már" + +msgid "Mark new games" +msgstr "Új játékok megjelölése" + +msgid "May" +msgstr "Máj" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "" + +msgid "Motion+ Video" +msgstr "" + +msgid "Mount DVD drive" +msgstr "DVD meghajtó felcsatolása" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "" + +msgid "Music Loop Mode" +msgstr "" + +msgid "Music Volume" +msgstr "Zene Hangerõ" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "" + +msgid "Nand Channels" +msgstr "" + +msgid "Nand Emu Channel Path" +msgstr "" + +msgid "Nand Emu Path" +msgstr "" + +msgid "Nand Emulation" +msgstr "" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Egyik sem" + +msgid "Network is not initiated." +msgstr "" + +msgid "Next" +msgstr "Következõ" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "Nem" + +msgid "No Cheatfile found" +msgstr "Kód nem található" + +msgid "No DOL file found on disc." +msgstr "Nem található DOL fájl a lemezen." + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "" + +msgid "No URL or Path specified." +msgstr "" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "Adat nem olvasható." + +msgid "No disc inserted." +msgstr "" + +msgid "No favorites selected." +msgstr "" + +msgid "No file missing!" +msgstr "Egy fájl sem hiányzik!" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "" + +msgid "No new updates." +msgstr "Nincs elérhetõ frissítés." + +msgid "No themes found on the site." +msgstr "Nem találhatóak témák az oldalon." + +msgid "No themes found." +msgstr "" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "" + +msgid "Normal" +msgstr "Normális" + +msgid "Not Initialized" +msgstr "" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "" + +msgid "Not a valid URL path" +msgstr "" + +msgid "Not a valid domain" +msgstr "" + +msgid "Not enough free memory." +msgstr "Nincs elég memória." + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "Nincs elég szabad hely" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "" + +msgid "Not required" +msgstr "" + +msgid "Not supported format!" +msgstr "Nem támogatott formátum" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "" + +msgid "OFF" +msgstr "KI" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "BE" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Okt" + +msgid "Official Site:" +msgstr "Hivatalos oldal:" + +msgid "Offset" +msgstr "" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "" + +msgid "Only for Install" +msgstr "Csak telepítéshez" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Eredeti/Egyéni" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Szülõi Felügyelet" + +msgid "Partial" +msgstr "" + +msgid "Partition" +msgstr "Partició" + +msgid "Password" +msgstr "Jelszó" + +msgid "Password Changed" +msgstr "Jelszó Megváltozott" + +msgid "Password has been changed" +msgstr "A Jelszó megváltozott" + +msgid "Patch Country Strings" +msgstr "Country String Patch" + +msgid "Path Changed" +msgstr "" + +msgid "Permission denied." +msgstr "" + +msgid "Pick from a list" +msgstr "Válassz a listából" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Indítások" + +msgid "Play Next" +msgstr "" + +msgid "Play Once" +msgstr "" + +msgid "Play Previous" +msgstr "" + +msgid "Playing Music:" +msgstr "" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "Kérlek várj..." + +msgid "Power off the Wii" +msgstr "Wii kikapcsolása" + +msgid "Prev" +msgstr "Elõzõ" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Gyors Gombok" + +msgid "Published by" +msgstr "Kiadta" + +msgid "Quick Boot" +msgstr "Gyors Boot" + +msgid "Random Directory Music" +msgstr "" + +msgid "Real Nand" +msgstr "" + +msgid "Receiving file from:" +msgstr "Fájl fogadása innen:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "" + +msgid "Released" +msgstr "Kiadva" + +msgid "Reload SD" +msgstr "SD Újratöltése" + +msgid "Reloading game list now, please wait..." +msgstr "" + +msgid "Remember Unlock" +msgstr "" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "" + +msgid "Rename Game Title" +msgstr "" + +msgid "Rename category" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Reset BG Music" +msgstr "" + +msgid "Reset Playcounter" +msgstr "Elindítások nullázása" + +msgid "Reset to default BGM?" +msgstr "" + +msgid "Restarting..." +msgstr "Újraindítás..." + +msgid "Return" +msgstr "Vissza" + +msgid "Return To" +msgstr "" + +msgid "Return to Wii Menu" +msgstr "Vissza a Wii Menübe" + +msgid "Right" +msgstr "Jobb" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Rezgés" + +msgid "SChinese" +msgstr "SKínai" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "Effekt Hangerõ" + +msgid "Save" +msgstr "Mentés" + +msgid "Save Failed. No device inserted?" +msgstr "" + +msgid "Save Game List to" +msgstr "Játéklista mentése ide:" + +msgid "Save List" +msgstr "" + +msgid "Saved" +msgstr "Elmentve" + +msgid "Savegame might not exist for this game." +msgstr "" + +msgid "Screensaver" +msgstr "Képernyõkimélõ" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "Válassz" + +msgid "Select DOL Offset" +msgstr "" + +msgid "Select a DOL" +msgstr "DOL kiválasztása" + +msgid "Select a DOL from Game" +msgstr "" + +msgid "Select game categories" +msgstr "" + +msgid "Select loader mode" +msgstr "" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "" + +msgid "Sept" +msgstr "Szep" + +msgid "Set Search-Filter" +msgstr "Keresés" + +msgid "Settings" +msgstr "Beállítások" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "" + +msgid "Show Play Count" +msgstr "" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "Leállítás" + +msgid "Shutdown Wii" +msgstr "" + +msgid "Skip Errors" +msgstr "" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Rendezés ABC-sorrendben" + +msgid "Sort by number of players" +msgstr "" + +msgid "Sort by rank" +msgstr "Rendezés rang szerint" + +msgid "Sort order by most played" +msgstr "Rendezés indítások száma szerint" + +msgid "Sound" +msgstr "Hang" + +msgid "Sound Settings" +msgstr "" + +msgid "Sound+BGM" +msgstr "Hang+háttérzene" + +msgid "Sound+Quiet" +msgstr "Csak hang" + +msgid "Spanish" +msgstr "Spanyol" + +msgid "Special thanks to:" +msgstr "Külön Köszönet:" + +msgid "Split each 2GB" +msgstr "" + +msgid "Split each 4GB" +msgstr "" + +msgid "Standby" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "Sikeres" + +msgid "Success." +msgstr "" + +msgid "Success:" +msgstr "Sikeres:" + +msgid "Successfully Saved" +msgstr "Sikeresen Mentve" + +msgid "Successfully Updated" +msgstr "Sikeres frissítés" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "Sikeresen törölve:" + +msgid "Successfully extracted theme." +msgstr "Téma kicsomagolva." + +msgid "Successfully installed:" +msgstr "Sikeresen telepítve:" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "" + +msgid "Sync FAT32 FS Info" +msgstr "" + +msgid "Synchronizing..." +msgstr "" + +msgid "System Default" +msgstr "Rendszer Alapértelmezett" + +msgid "TChinese" +msgstr "Tradicionális Kínai" + +msgid "TXT Cheatcodes Path" +msgstr "TXT Cheatkódok Útvonala" + +msgid "The .them file was not found in the zip." +msgstr "" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "A megadott könyvtár nem létezik. Létrehozzuk?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "" + +msgid "Theme Downloader" +msgstr "Témák Letöltése" + +msgid "Theme Menu" +msgstr "" + +msgid "Theme Path" +msgstr "Témák Útvonala" + +msgid "Theme Title:" +msgstr "Téma címe:" + +msgid "Themes by www.spiffy360.com" +msgstr "" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "" + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "Hátralevõ idõ" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Programindító" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "Súgók" + +msgid "Transfer failed" +msgstr "" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX levédve" + +msgid "USB Port" +msgstr "" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "Törlés" + +msgid "Uninstall Game" +msgstr "Játék törlése" + +msgid "Uninstall Menu" +msgstr "Adatkezelés" + +msgid "Uninstall all" +msgstr "" + +msgid "Unknown" +msgstr "" + +msgid "Unlock USB Loader GX" +msgstr "" + +msgid "Unlocked" +msgstr "Feloldva" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "" + +msgid "Update" +msgstr "Frissítés" + +msgid "Update All" +msgstr "Minden Frissítése" + +msgid "Update DOL" +msgstr "DOL Frissítése" + +msgid "Update Files" +msgstr "Fájlok frissítése" + +msgid "Update Path" +msgstr "Frissítés Útvonala" + +msgid "Update all Language Files" +msgstr "Minden nyelvi fájl frissítése" + +msgid "Update failed" +msgstr "Frissítési hiba" + +msgid "Update successfull" +msgstr "" + +msgid "Updating Language Files:" +msgstr "Nyelvi fájlok frissítése:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Feltöltött ZIP fájl telepítve a Homebrew mappába." + +msgid "Use System Font" +msgstr "" + +msgid "Use global" +msgstr "" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "" + +msgid "Version:" +msgstr "" + +#, c-format +msgid "Version: %s" +msgstr "Verzió: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Videó Mód" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "" + +msgid "WDM Files Path" +msgstr "" + +msgid "WIP Patches Path" +msgstr "WIP Patch útvonal" + +msgid "Waiting..." +msgstr "Várakozás..." + +msgid "Warning" +msgstr "" + +msgid "Warning:" +msgstr "" + +msgid "What do you want to do?" +msgstr "" + +msgid "What do you want to update?" +msgstr "Mit szeretnél frissíteni?" + +msgid "What should be deleted for this game title:" +msgstr "" + +msgid "What to extract from NAND?" +msgstr "" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "WiFi Sajátosságok" + +msgid "Widescreen Factor" +msgstr "" + +msgid "Widescreen Fix" +msgstr "Szélesvászon Fix" + +msgid "Wii Games" +msgstr "" + +msgid "Wii Menu" +msgstr "Wii Menü" + +msgid "Wii Settings" +msgstr "Wii Beállítások" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "WiiFény" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "" + +msgid "Wiird Debugger" +msgstr "" + +#, c-format +msgid "Write error on file: %s" +msgstr "" + +msgid "Writing GXGameCategories.xml" +msgstr "" + +msgid "Wrong Password" +msgstr "Hibás Jelszó" + +msgid "Yes" +msgstr "Igen" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "" + +msgid "You cannot delete this category." +msgstr "" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "" + +msgid "available" +msgstr "elérhetõ" + +msgid "does not exist!" +msgstr "nem létezik!" + +msgid "does not exist! Loading game without cheats." +msgstr "nem létezik! Játék betöltése kódok nélkül." + +msgid "files left" +msgstr "hátralévõ fájl" + +msgid "for FAT/NTFS support" +msgstr "FAT/NTFS támogatás" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "" + +msgid "for Ocarina" +msgstr ": Ocarina" + +msgid "for diverse patches" +msgstr ": többféle patch" + +msgid "for his awesome tool LibWiiGui" +msgstr "-nak kiváló eszközéért: LibWiiGui" + +msgid "for hosting the themes" +msgstr ": témák tárhelye" + +msgid "for the USB Loader source" +msgstr ": USB Loader forráskód" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "Formázva!" + +msgid "free" +msgstr "szabad" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "nem beállított" + +msgid "of" +msgstr "./" + +msgid "seconds left" +msgstr "hátralévõ másodperc" + +#~ msgid "Error 002 fix" +#~ msgstr "Error 02 javítás" + +#~ msgid "Boot/Standard" +#~ msgstr "Boot/Alapértelmezett" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "WBFS játék átnevezése" + +#~ msgid "for hosting the update files" +#~ msgstr ": frissítési fájlok tárhelye" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Helyezz be Wii lemezt!" + +#~ msgid "No cheats were selected" +#~ msgstr "Nincsenek kiválasztott cheat-ek" + +#~ msgid "Not a Wii Disc" +#~ msgstr "Nem Wii lemez" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> Ticket-ek törlése..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> Ticket-ek törlése...HIBA!" + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> Ticket-ek törlése...Ok!" + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> Title törlése...HIBA!" + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> Title törlése...Ok!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> Title tartalom törlése..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> Title tartalom törlése...HIBA!" + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> Title tartalom törlése...Ok!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> Title törlése..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> Telepítés befejezése..." + +#~ msgid ">> Installing content #" +#~ msgstr ">> Telepítés: tartalom #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> Ticket telepítése" + +#~ msgid ">> Installing title..." +#~ msgstr ">> Title telepítése..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> WAD adatok olvasása..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> WAD adatok olvasása...HIBA!" + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> WAD adatok olvasása...Ok!" + +#~ msgid "Done!" +#~ msgstr "Kész!" + +#~ msgid "Error..." +#~ msgstr "Hiba..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "Telepítés befejezése...Ok!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "Tartalom telepítése... Ok!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "Ticket telepítése... Ok!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "Title telepítése... Ok!" + +#~ msgid "Installing wad" +#~ msgstr "Wad telepítése" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "WAD adat olvasás... Ok!" + +#~ msgid "Uninstalling wad" +#~ msgstr "Wad törlése" + +#~ msgid "New Disc Detected" +#~ msgstr "Új lemez észlelve" + +#~ msgid "USB Device not found" +#~ msgstr "USB Meghajtó nem található" + +#~ msgid "You need to select or format a partition" +#~ msgstr "Választanod vagy formáznod kell egy partíciót" + +#~ msgid "Language File" +#~ msgstr "Nyelvi fájl" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Címek WiiTDB fájlból" + +#~ msgid "WiiTDB Files" +#~ msgstr "WiiTDB fájlok" + +#~ msgid "WiiTDB Path" +#~ msgstr "WiiTDB Útvonala" + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr ": WiiTDB és borítók/lemezfotók" + +#~ msgid "Install partitions" +#~ msgstr "Partíciók telepítése" + +#~ msgid " Wad Saved as:" +#~ msgstr "Wad elmentve mint:" + +#~ msgid "Delete ?" +#~ msgstr "Törlés?" + +#~ msgid "Keep" +#~ msgstr "Megtartás" + +#~ msgid "Author:" +#~ msgstr "Készítõ:" + +#~ msgid "Download Boxart image?" +#~ msgstr "Borító letöltése?" + +#~ msgid "Download Discart image?" +#~ msgstr "Lemezfotó letöltése?" + +#~ msgid "Downloading file" +#~ msgstr "Fájl letöltése" + +#~ msgid "Missing files" +#~ msgstr "Hiányzó fájl" + +#~ msgid "files not found on the server!" +#~ msgstr "fájl nem található a szerveren" + +#~ msgid "Disc Images" +#~ msgstr "Lemezfotók" + +#~ msgid "Only Customs" +#~ msgstr "Csak egyéni" + +#~ msgid "Only Original" +#~ msgstr "Csak eredeti" + +#~ msgid "Do you really want to delete:" +#~ msgstr "Biztosan törlöd?" + +#~ msgid "Do you want to use the alternate DOL that is known to be correct?" +#~ msgstr "Köztudottan működõ alternatív DOL használata?" + +#~ msgid "BETA revisions" +#~ msgstr "Béta változatok" + +#~ msgid "Unlock console to use this option." +#~ msgstr "Zárolva a program, ezt nem használhatod." + +#~ msgid "Full Shutdown" +#~ msgstr "Teljes Kikapcsolás" + +#~ msgid "GXtheme.cfg not found in any subfolder." +#~ msgstr "GXtheme.cfg nem található." + +#~ msgid "If you don't have WiFi, press 1 to get an URL to get your WiiTDB.zip" +#~ msgstr "WiFi hiánya esetén nyomj 1-es gombot a WiiTDB.zip URL-ért." + +#~ msgid "Paste it into your browser to get your WiiTDB.zip." +#~ msgstr "Másold be a böngészõbe a WiiTDB.zip letöltéséhez." + +#~ msgid "Shutdown to Idle" +#~ msgstr "Készenlét" + +#~ msgid "Your URL has been saved in %sWiiTDB_URL.txt." +#~ msgstr "URL elmentve itt: %sWiiTDB_URL.txt" + +#~ msgid "Can't create file" +#~ msgstr "A fájl nem hozható létre." + +#~ msgid "Connection lost..." +#~ msgstr "A kapcsolat megszakadt..." + +#~ msgid "Download failed." +#~ msgstr "Sikertelen letöltés." + +#~ msgid "Download request failed." +#~ msgstr "Sikertelen letöltési kérelem." + +#~ msgid "Downloading Page List:" +#~ msgstr "Lista letöltése:" + +#~ msgid "Theme Download Path" +#~ msgstr "Téma Letöltés Útvonal" + +#~ msgid "Transfer failed." +#~ msgstr "Átviteli hiba." + +#~ msgid "Unsupported format, try to extract manually." +#~ msgstr "Nem támogatott formátum, próbáld manuálisan kicsomagolni." + +#~ msgid "and translaters for language files updates" +#~ msgstr "valamint minden fordító" + +#~ msgid "Insert an SD-Card to save." +#~ msgstr "Helyezz be egy SD Kártyát, hogy ments," + +#~ msgid "Insert an SD-Card to use this option." +#~ msgstr "Helyezz be egy SD Kártyát, hogy használhasd ezt a lehetõséget." + +#~ msgid "No SD-Card inserted!" +#~ msgstr "Nincs SD kártya behelyezve!" + +#~ msgid "Waiting for USB Device" +#~ msgstr "Várakozás az USB Meghajtóra" + +#~ msgid "Back to Loader" +#~ msgstr "HBC" + +#~ msgid "FAT: Use directories" +#~ msgstr "FAT: könyvtárak használata" + +#~ msgid "All partitions" +#~ msgstr "Minden partíció" + +#~ msgid "Game partition" +#~ msgstr "Játék partíció" + +#~ msgid "Install 1:1 Copy" +#~ msgstr "1:1 másolat telepítése" + +#~ msgid "An Error occured" +#~ msgstr "Hiba történt" + +#~ msgid "Are you sure you want to enable Parent Control?" +#~ msgstr "Szülõi felügyelet bekapcsolása?" + +#~ msgid "Checking for Updates" +#~ msgstr "Frissitések keresése..." + +#~ msgid "Downloading" +#~ msgstr "Letöltés" + +#~ msgid "Invalid PIN code" +#~ msgstr "Hibás PIN kód" + +#~ msgid "Parental Control disabled" +#~ msgstr "Szülõi felügyelet kikapcsolva" + +#~ msgid "The wad file was installed. But It could not be deleted from the SD card." +#~ msgstr "A wad fájl telepítése megtörtént, de nem volt törölhetõ az SD kártyáról." + +#~ msgid "The wad installation failed with error %ld" +#~ msgstr "A wad telepítés nem sikerült - hiba %ld" + +#~ msgid "Unable to open the wad that was just downloaded (%s)." +#~ msgstr "Az épp letöltött wad megnyitása nem sikerült (%s)." + +#~ msgid "Unlock Parental Control" +#~ msgstr "Szülõi felügyelet feloldása" + +#~ msgid "Update to" +#~ msgstr "Frissítés ide: " + +#~ msgid "Updating" +#~ msgstr "Frissítés" + +#~ msgid "Updating Language Files..." +#~ msgstr "Nyelvi fájlok frissítése..." + +#~ msgid "Updating WiiTDB.zip" +#~ msgstr "WiiTDB.zip frissítése" + +#~ msgid "You don't have Parental Control enabled. If you wish to use Parental Control, enable it in the Wii Settings." +#~ msgstr "A szülõi felügyelet nincs bekapcsolva - bekapcsolható a Wii Beállításokban." + +#~ msgid "%s : %s May not boot correctly if your System Menu is not up to date." +#~ msgstr "%s : %s Lehet, hogy nem fut megfelelõen, ha a System Menu nem a legfrissebb." + +#~ msgid "BCA Codes Path changed" +#~ msgstr "BCA kód útvonal megváltozott" + +#~ msgid "Back to Wii Menu" +#~ msgstr "Visszatérés a Wii Menübe" + +#~ msgid "Checking existing artwork" +#~ msgstr "Meglévõ képek ellenõrzése" + +#~ msgid "Confirm" +#~ msgstr "Megerõsítés" + +#~ msgid "Could not find a WBFS partition." +#~ msgstr "WBFS partíció nem található." + +#~ msgid "Could not open WBFS partition" +#~ msgstr "WBFS partíció nem nyitható meg." + +#~ msgid "Could not read the disc." +#~ msgstr "A lemez nem olvasható." + +#~ msgid "Could not set USB." +#~ msgstr "USB beállítási hiba." + +#~ msgid "Cover Path Changed" +#~ msgstr "Boritó útvonala megváltozott" + +#~ msgid "DOL path changed" +#~ msgstr "DOL útvonal megváltozott" + +#~ msgid "Disc Path Changed" +#~ msgstr "Borítók útvonala megváltoztatva" + +#~ msgid "Display favorites" +#~ msgstr "Kedvencek megjelenítése" + +#~ msgid "Do you want to retry for 30 secs?" +#~ msgstr "30 másodpercig szeretnéd még tovább próbálni?" + +#~ msgid "Enable Parental Control" +#~ msgstr "Szülői felügyelet bekapcsolása" + +#~ msgid "Force" +#~ msgstr "Kényszerítés" + +#~ msgid "GCT Cheatcodes Path changed" +#~ msgstr "Kódok útvonala megváltozott" + +#~ msgid "Homebrew Appspath changed" +#~ msgstr "Homebrew útvonal megváltoztatva" + +#~ msgid "Insert an SD-Card to download images." +#~ msgstr "Helyezz be egy SD Kártyát, hogy letöltsd a képeket." + +#~ msgid "Install not possible" +#~ msgstr "A telepítés nem lehetséges" + +#~ msgid "Most likely it has dimensions that are not evenly divisible by 4." +#~ msgstr "Vélhetõen méretei nem oszhatók 4-gyel." + +#~ msgid "Network init error" +#~ msgstr "Hálozat létrehozásában hiba történt" + +#~ msgid "No .dol or .elf files found." +#~ msgstr "Nem taláhatóak .dol vagy .elf fájlok." + +#~ msgid "No Favorites" +#~ msgstr "Nincsenek kedvencek" + +#~ msgid "No USB Device" +#~ msgstr "Nincs USB meghajtó" + +#~ msgid "No USB Device found." +#~ msgstr "Nincs USB meghajtó csatlakoztatva." + +#~ msgid "No WBFS or FAT/NTFS partition found" +#~ msgstr "Nem található WBFS vagy FAT/NTFS partíció" + +#~ msgid "Normal Covers" +#~ msgstr "Sima Borítók" + +#~ msgid "Not Found" +#~ msgstr "Nem található" + +#~ msgid "Not a DOL/ELF file." +#~ msgstr "Nem DOL/ELF fájl." + +#~ msgid "Save Failed" +#~ msgstr "Mentési hiba" + +#~ msgid "Selected DOL" +#~ msgstr "Kiválasztott DOL" + +#~ msgid "Standard" +#~ msgstr "Alap" + +#~ msgid "TXT Cheatcodes Path changed" +#~ msgstr "TXT CheatKódok Útvonala megváltozott" + +#~ msgid "Theme Download Path changed" +#~ msgstr "Téma letöltés útvonal megváltozott" + +#~ msgid "Theme Path Changed" +#~ msgstr "Témák útvonala megváltozott" + +#~ msgid "USB Loader GX will only run with Hermes CIOS rev 4! Please make sure you have revision 4 installed!" +#~ msgstr "Az USB Loader GX csak Hermes CIOS rev 4 mellett működik! Gyõződj meg róla, hogy telepítetted!" + +#~ msgid "Update Path changed." +#~ msgstr "Frissítés útvonala megváltozott." + +#~ msgid "WIP Patches Path changed" +#~ msgstr "WIP Patch útvonal megváltozott" + +#~ msgid "WiiTDB Path changed." +#~ msgstr "WiiTDB útvonal megváltozott." + +#~ msgid "You are about to delete " +#~ msgstr "Törölni készülsz: " + +#~ msgid "You are choosing to display favorites and you do not have any selected." +#~ msgstr "A Kedvencek megjelenítését választottad, de egy játék sincs így megjelölve." + +#~ msgid "You are using NTFS filesystem. Due to possible write errors to a NTFS partition, installing a game is not possible." +#~ msgstr "NTFS fájlrendszert használata esetén a lehetséges írási hibák miatt játékok telepítése nem lehetséges." + +#~ msgid "You have attempted to load a bad image" +#~ msgstr "Rossz képfájl próbáltál betõlteni" + +#~ msgid "does not exist! You Messed something up, Idiot." +#~ msgstr "nem létezik! Valamit elcsesztéll :-)" + +#~ msgid "file left" +#~ msgstr "hátralévõ fájl" diff --git a/Languages/italian.lang b/Languages/italian.lang new file mode 100644 index 0000000..9a92f4a --- /dev/null +++ b/Languages/italian.lang @@ -0,0 +1,2574 @@ +# USB Loader GX language source file. +# italian.lang - r1267 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:02+0200\n" +"PO-Revision-Date: 2011-09-11 12:19+0100\n" +"Last-Translator: Zonta85\n" +"Language-Team: Zonta85 (zonta_85@hotmail.it)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " non può essere scaricato." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " è stato salvato. Il testo non è stato verificato. Parti di codice potrebbero essere in conflitto. Se incontri dei problemi, apri il testo in un editor per ulteriori informazioni." + +msgid " is not on the server." +msgstr "non è presente sul server." + +#, c-format +msgid "%i files not found on the server!" +msgstr "%i file non trovati sul server!" + +#, c-format +msgid "%i missing files" +msgstr "%i files mancanti" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "%i files(s) wad non processati" + +#, c-format +msgid "%i wad found." +msgstr "%i wad trovati" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "%s accetta solo backup GameCube in formato ISO" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "%s richiede accesso AHB! Per favore avvia USBLoaderGX da HBC o da un canale o forwarder aggiornato" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Tutti)" + +msgid "1 (Child 7+)" +msgstr "1 (Bambini 7+)" + +msgid "1 hour" +msgstr "1 ora" + +msgid "10 min" +msgstr "10 minuti" + +msgid "2 (Teen 12+)" +msgstr "2 (Ragazzi 12+)" + +msgid "20 min" +msgstr "20 minuti" + +msgid "2D Cover Path" +msgstr "Percorso copertine 2D" + +msgid "3 (Mature 16+)" +msgstr "3 (Giovani 16+)" + +msgid "3 min" +msgstr "3 minuti" + +msgid "30 min" +msgstr "30 minuti" + +msgid "3D Cover Path" +msgstr "Percorso copertine 3D" + +msgid "3D Covers" +msgstr "Copertine 3D" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Maggiorenni 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 minuti" + +msgid "=== GameCube Settings" +msgstr "=== Impostazioni GameCube" + +msgid "AUTO" +msgstr "AUTO" + +msgid "AXNextFrame" +msgstr "AXNextFrame" + +msgid "Add category" +msgstr "Aggiungi categoria" + +msgid "Adjust Overscan X" +msgstr "Regola overscan X" + +msgid "Adjust Overscan Y" +msgstr "Regola overscan Y" + +msgid "After zoom" +msgstr "Dopo lo zoom" + +msgid "All" +msgstr "Tutte" + +msgid "All Partitions" +msgstr "Tutte le partizioni" + +msgid "All files extracted." +msgstr "Tutti i file sono stati estratti." + +msgid "All images downloaded successfully." +msgstr "Tutte le immagini sono state scaricate correttamente." + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Tutte le funzioni di USB Loader GX sono sbloccate." + +msgid "All wad files processed successfully." +msgstr "Tutti i files wad processati correttamente" + +msgid "Alternate DOL" +msgstr "DOL alternativo" + +msgid "An example file was created here:" +msgstr "Un file di esempio è stato creato qui:" + +msgid "Animation Start" +msgstr "Avvio dell'animazione" + +msgid "App Language" +msgstr "Lingua applicazione" + +msgid "Apply" +msgstr "Applica" + +msgid "Apr" +msgstr "Aprile" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "Sei sicuro di voler eliminare tutti i giochi selezionati dalla scheda SD?" + +msgid "Are you sure you want to delete this category?" +msgstr "Sei sicuro di voler eliminare questa categoria?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "Sei sicuro di voler importare le categorie dei giochi da GameTDB?" + +msgid "Are you sure you want to install on SD?" +msgstr "Sei sicuro di voler installare nella SD?" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "Sei sicuro di voler bloccare USB Loader GX?" + +msgid "Are you sure you want to remount SD?" +msgstr "Sei sicuro di voler rimontare la SD?" + +msgid "Are you sure you want to reset?" +msgstr "Sei sicuro di voler ripristinare tutto?" + +msgid "Are you sure?" +msgstr "Sei sicuro?" + +msgid "Aspect Ratio" +msgstr "Formato TV" + +msgid "Attention!" +msgstr "Attenzione!" + +msgid "Attention: All savegames will be deleted." +msgstr "Attenzione: tutti i salvataggi saranno eliminati" + +msgid "Aug" +msgstr "Agosto" + +msgid "Author(s):" +msgstr "Autore/i:" + +msgid "Auto" +msgstr "Auto" + +msgid "Auto Boot" +msgstr "Avvio automatico" + +msgid "AutoInit Network" +msgstr "Inizializzazione automatica rete" + +msgid "BCA Codes Path" +msgstr "Percorso codici BCA" + +msgid "Back" +msgstr "Indietro" + +msgid "Back to HBC or Wii Menu" +msgstr "Torna a HBC o Menu Wii" + +msgid "Backgroundmusic" +msgstr "Musica di sottofondo" + +msgid "Banner Animation" +msgstr "Animazione banner" + +msgid "Banner Animation Settings" +msgstr "Impostazioni animazione banner" + +msgid "Banner On Channels" +msgstr "Banner nei canali" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "La visualizzazione con banner è disponibile solo con AHBPROT! Installa l'ultima versione di HBC." + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "L'animazione dei banner è disponibile solo con AHBPROT! Installa l'ultima versione di HBC." + +msgid "Big thanks to:" +msgstr "Grazie mille a:" + +msgid "Block Categories Menu" +msgstr "Blocca Menu categorie" + +msgid "Block Categories Modify" +msgstr "Blocca Modifica categorie" + +msgid "Block Cover Downloads" +msgstr "Blocca Download copertine" + +msgid "Block Custom Paths" +msgstr "Blocca Percorsi personalizzati" + +msgid "Block Feature Settings" +msgstr "Blocca Impostazioni funzionalità" + +msgid "Block Game Install" +msgstr "Blocca Installazione giochi" + +msgid "Block Game Settings" +msgstr "Blocca Impostazioni gioco" + +msgid "Block GameID Change" +msgstr "Blocca Modifica ID gioco" + +msgid "Block Global Settings" +msgstr "Blocca Impostazioni globali" + +msgid "Block Gui Settings" +msgstr "Blocca Impostazioni interfaccia" + +msgid "Block HBC Menu" +msgstr "Blocca menu HBC" + +msgid "Block Hard Drive Settings" +msgstr "Blocca Impostazioni Hard Disk" + +msgid "Block IOS Reload" +msgstr "Blocca ricarica IOS" + +msgid "Block Loader Layout Button" +msgstr "Blocco pulsante layout del loader" + +msgid "Block Loader Mode Button" +msgstr "Blocca pulsante Modalità loader" + +msgid "Block Loader Settings" +msgstr "Blocca Impostazioni Loader" + +msgid "Block Parental Settings" +msgstr "Blocca Controllo Genitori" + +msgid "Block Priiloader Override" +msgstr "Blocca Annulla Priiloader" + +msgid "Block Reset Settings" +msgstr "Blocca impostazioni predefinite" + +msgid "Block SD Reload Button" +msgstr "Blocca Pulsante ricarica SD" + +msgid "Block Sound Settings" +msgstr "Blocca Impostazioni Audio" + +msgid "Block Theme Downloader" +msgstr "Blocca Download Temi" + +msgid "Block Theme Menu" +msgstr "Blocca Menu Temi" + +msgid "Block Title Launcher" +msgstr "Blocca Avvio titoli" + +msgid "Block Updates" +msgstr "Blocca Aggiornamenti" + +msgid "Boot Content" +msgstr "Avvio normale" + +msgid "Boot Neek System Menu" +msgstr "Avvia System Menu Neek" + +msgid "Boot?" +msgstr "Avviare?" + +msgid "Both" +msgstr "Entrambi" + +msgid "Both Ports" +msgstr "Entrambe le porte" + +msgid "CC Rumble" +msgstr "Vibrazione CC" + +msgid "Cache BNR Files" +msgstr "Cache file BNR" + +msgid "Cache BNR Files Path" +msgstr "Percorso cache file BNR" + +msgid "Cache Titles" +msgstr "Cache titoli" + +msgid "Can't be formatted" +msgstr "Impossibile formattare" + +msgid "Can't create directory" +msgstr "Impossibile creare la cartella" + +#, c-format +msgid "Can't create file: %s" +msgstr "Impossibile creare il file: %s" + +#, c-format +msgid "Can't create path: %s" +msgstr "Impossibile creare il percorso: %s" + +msgid "Can't delete:" +msgstr "Impossibile eliminare:" + +msgid "Can't mount or unknown disc format." +msgstr "Impossibile montare o formato sconosciuto" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "Impossibile aprire il file da scrivere: %s" + +#, c-format +msgid "Can't open file: %s" +msgstr "Impossibile aprire il file: %s" + +#, c-format +msgid "Can't read file: %s" +msgstr "Impossibile leggere il file: %s" + +msgid "Cancel" +msgstr "Annulla" + +msgid "Cannot write to destination." +msgstr "Impossibile scrivere nella destinazione." + +msgid "Categories" +msgstr "Categorie" + +msgid "Categories:" +msgstr "Categorie:" + +msgid "Change Play Path" +msgstr "Cambia percorso Musica" + +msgid "Channel Launcher" +msgstr "Modalità avvio canali" + +msgid "Channels" +msgstr "Canali" + +msgid "Cheatfile is blank" +msgstr "Il file dei trucchi è vuoto" + +msgid "Clear" +msgstr "Azzera" + +msgid "Click to Download Covers" +msgstr "Clicca per scaricare le copertine" + +msgid "Click to change game ID" +msgstr "Clicca per cambiare ID al gioco" + +msgid "Clock" +msgstr "Orologio" + +msgid "Clock Scale Factor" +msgstr "Rapporto orologio" + +msgid "Close" +msgstr "Chiudi" + +msgid "Code Download" +msgstr "Scarica trucchi" + +#, c-format +msgid "Coded by: %s" +msgstr "Sviluppato da: %s" + +msgid "Coding:" +msgstr "Sviluppo:" + +msgid "Connection to server timed out." +msgstr "Connessione al server scaduta." + +msgid "Console" +msgstr "Console" + +msgid "Console Default" +msgstr "Predefinita" + +msgid "Console Locked" +msgstr "Console bloccata" + +msgid "Console must be unlocked for this option." +msgstr "Il Wii deve essere sbloccato per questa opzione." + +msgid "Console must be unlocked to be able to use this." +msgstr "Il Wii deve essere sbloccato per usare questa opzione." + +msgid "Console should be unlocked to modify it." +msgstr "Il Wii deve essere sbloccato per modificarla." + +msgid "Continue" +msgstr "Prosegui" + +msgid "Continue to install game?" +msgstr "Proseguire con l'installazione del gioco?" + +msgid "Continue?" +msgstr "Proseguire?" + +msgid "Controllevel" +msgstr "Livello di protezione" + +msgid "Copy" +msgstr "Copia" + +msgid "Copying Canceled" +msgstr "Copia cancellata" + +msgid "Copying GC game..." +msgstr "Copiando il gioco GC..." + +msgid "Copying files..." +msgstr "Copiando i file..." + +msgid "Correct Password" +msgstr "Password corretta" + +msgid "Could not connect to the server." +msgstr "Impossibile connettersi al server." + +msgid "Could not create GCT file" +msgstr "Impossibile creare il file GCT" + +#, c-format +msgid "Could not create path: %s" +msgstr "Impossibile creare la cartella: %s" + +msgid "Could not extract files for:" +msgstr "Impossibile estrarre il file per:" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "Informazioni non disponibili per questo gioco nel file wiitdb.xml." + +msgid "Could not get free device space for game." +msgstr "Non è disponibile abbastanza spazio per il gioco." + +msgid "Could not initialize DIP module!" +msgstr "Impossibile inizializzare il modulo DIP!" + +msgid "Could not initialize network!" +msgstr "Impossibile inizializzare la rete!" + +msgid "Could not initialize network, time out!" +msgstr "Impossibile inizializzare la rete, tempo scaduto!" + +msgid "Could not open Disc" +msgstr "Impossibile aprire il disco" + +msgid "Could not open the WiiTDB.xml file." +msgstr "Impossibile aprire il file wiitdb.xml" + +msgid "Could not open wiitdb.xml." +msgstr "Impossibile aprire wiitdb.xml." + +msgid "Could not save." +msgstr "Impossibile salvare." + +msgid "Could not write file." +msgstr "Impossibile scrivere il file." + +msgid "Could not write to:" +msgstr "Impossibile scrivere in:" + +msgid "Cover Download" +msgstr "Scarica copertine" + +msgid "Create" +msgstr "Crea" + +msgid "Credits" +msgstr "Ringraziamenti" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "Questi files neek non sono neek2o. Autoboot dei giochi disabilitato" + +msgid "Custom Banners" +msgstr "Banner personalizzati" + +msgid "Custom Paths" +msgstr "Percorsi personalizzati" + +msgid "Customs" +msgstr "Personalizzati" + +msgid "Customs/Original" +msgstr "Modificati/Originali" + +msgid "D Buttons" +msgstr "Croce direzionale" + +msgid "DOL Path" +msgstr "Percorso DOL" + +msgid "Debug" +msgstr "Debug" + +msgid "Debug Wait" +msgstr "Pausa debugger" + +msgid "Debugger Paused Start" +msgstr "Avvia debugger pausato" + +msgid "Dec" +msgstr "Dicembre" + +msgid "Default" +msgstr "Predefinita" + +msgid "Default Gamesettings" +msgstr "Impostazioni di gioco predefinite" + +msgid "Default Settings" +msgstr "Impostazioni predefinite" + +msgid "Delete" +msgstr "Elimina" + +msgid "Delete Cached Banner" +msgstr "Elimina banner cachato" + +msgid "Delete Cheat GCT" +msgstr "Elimina trucchi GCT" + +msgid "Delete Cheat TXT" +msgstr "Elimina trucchi TXT" + +msgid "Delete Cover Artwork" +msgstr "Elimina copertina" + +msgid "Delete Disc Artwork" +msgstr "Elimina immagine disco" + +msgid "Delete category" +msgstr "Elimina categoria" + +msgid "Deleting directories..." +msgstr "Eliminando i percorsi..." + +msgid "Deleting files..." +msgstr "Eliminando i file..." + +msgid "Design:" +msgstr "Grafica:" + +msgid "Details" +msgstr "Dettagli" + +msgid "Developed by" +msgstr "Sviluppato da" + +msgid "Developer:" +msgstr "Sviluppatore:" + +msgid "Devolution" +msgstr "Devolution" + +msgid "Devolution Loader Path" +msgstr "Percorso loader Devolution" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "Impossibile caricare il file loader.bin di Devolution." + +msgid "Directory does not exist!" +msgstr "Il percorso non esiste!" + +msgid "Disc 1" +msgstr "Disco 1" + +msgid "Disc 2" +msgstr "Disco 2" + +msgid "Disc Artwork Download" +msgstr "Scarica immagine disco" + +msgid "Disc Artwork Path" +msgstr "Percorso immagini dischi" + +msgid "Disc Default" +msgstr "Da disco" + +msgid "Disc Insert Detected" +msgstr "Rilevato il disco" + +msgid "Disc Read Delay" +msgstr "Ritardo nella lettura del disco" + +msgid "Disc read error." +msgstr "Errore durante la lettura del disco." + +msgid "Disc-Select Prompt" +msgstr "Prompt di selezione disco" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "Il disco 2 deve essere installato in formato non compresso per funzionare con DM(L) v2.6+, sicuro di volerlo installare in formato compresso?" + +msgid "Discarts" +msgstr "Dischi" + +msgid "DiskFlip" +msgstr "Rotazione dischi" + +msgid "Display" +msgstr "Visualizza" + +msgid "Display as a carousel" +msgstr "Visualizz. carosello" + +msgid "Display as a channel grid" +msgstr "Visualizz. canali" + +msgid "Display as a grid" +msgstr "Visualizz. griglia" + +msgid "Display as a list" +msgstr "Visualizz. elenco" + +msgid "Display favorites only" +msgstr "Mostra solo i preferiti" + +msgid "Do you want to apply it now?" +msgstr "Vuoi applicarlo ora?" + +msgid "Do you want to apply this theme?" +msgstr "Vuoi applicare questo tema?" + +msgid "Do you want to change language?" +msgstr "Vuoi cambiare lingua?" + +msgid "Do you want to continue with next game?" +msgstr "Vuoi continuare con il prossimo gioco?" + +msgid "Do you want to copy now?" +msgstr "Vuoi copiarlo ora?" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "Vuoi copiare un gioco sulla SD o eliminarne uno?" + +msgid "Do you want to delete a game on SD?" +msgstr "Vuoi eliminare un gioco dalla SD?" + +msgid "Do you want to discard changes?" +msgstr "Vuoi annullare le modifiche?" + +msgid "Do you want to download this theme?" +msgstr "Vuoi scaricare questo tema?" + +msgid "Do you want to extract all the save games?" +msgstr "Vuoi estrarre tutti i salvataggi?" + +msgid "Do you want to extract the save game?" +msgstr "Vuoi estrarre il salvataggio del gioco?" + +msgid "Do you want to format:" +msgstr "Vuoi formattare:" + +msgid "Do you want to install selected games?" +msgstr "Vuoi installare i giochi selezionati?" + +msgid "Do you want to load the default theme?" +msgstr "Vuoi caricare il tema predefinito?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "Vuoi spostare questi file(s)? Ogni file esistente verrà eliminato!" + +msgid "Do you want to re-init network?" +msgstr "Vuoi reinizializzare la rete?" + +msgid "Do you want to start the game now?" +msgstr "Vuoi avviare il gioco ora?" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "Vuoi sincronizzare le info sullo spazio libero in tutte le partizioni FAT32?" + +msgid "Do you wish to update/download all language files?" +msgstr "Vuoi scaricare/aggiornare tutte le traduzioni?" + +msgid "Dol Video Patch" +msgstr "Patch Video DOL" + +msgid "Download" +msgstr "Scarica" + +msgid "Download Now" +msgstr "Scarica adesso" + +msgid "Download finished" +msgstr "Download completato" + +msgid "Downloading 3D Covers" +msgstr "Scaricando copertine 3D..." + +msgid "Downloading Custom Banners" +msgstr "Scaricando banner personalizzati..." + +msgid "Downloading Flat Covers" +msgstr "Scaricando copertine 2D..." + +msgid "Downloading Full HQ Covers" +msgstr "Scaricando copertine intere HQ..." + +msgid "Downloading Full LQ Covers" +msgstr "Scaricando copertine intere LQ..." + +msgid "Downloading custom Discarts" +msgstr "Scaricando immagini disco personalizzate" + +msgid "Downloading file..." +msgstr "Scaricando file..." + +msgid "Downloading image:" +msgstr "Scaricando immagine:" + +msgid "Downloading original Discarts" +msgstr "Scaricando immagini disco originali" + +msgid "Downloading pagelist:" +msgstr "Scaricando l'anteprima di:" + +msgid "Dump NAND to EmuNand" +msgstr "Dumpa NAND su NAND emulata" + +msgid "During zoom" +msgstr "Durante zoom" + +msgid "Dutch" +msgstr "Olandese" + +msgid "ERROR" +msgstr "ERRORE" + +msgid "ERROR:" +msgstr "ERRORE:" + +msgid "ERROR: Can't set up theme." +msgstr "ERRORE: Impossibile configurare il tema." + +msgid "EmuNAND Wad Manager" +msgstr "Wad Manager NAND emulata" + +msgid "EmuNand Channels" +msgstr "Canali NAND Emulata" + +msgid "Emulated Nand" +msgstr "NAND emulata" + +msgid "English" +msgstr "Inglese" + +msgid "Enter Path" +msgstr "Inserisci percorso" + +msgid "Error" +msgstr "Errore" + +msgid "Error !" +msgstr "Errore!" + +#, c-format +msgid "Error creating path: %s" +msgstr "Errore creazione cartella: %s" + +msgid "Error opening downloaded file" +msgstr "Errore aprendo il file scaricato" + +msgid "Error reading Disc" +msgstr "Errore di lettura Disco" + +msgid "Error reading disc" +msgstr "Errore di lettura disco" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "Errore scaricando il file: %i" + +msgid "Error while downloding file" +msgstr "Errore scaricando il file" + +msgid "Error while opening the zip." +msgstr "Errore apertura file zip." + +msgid "Error while transfering data." +msgstr "Errore trasferendo i dati." + +msgid "Error while updating USB Loader GX." +msgstr "Errore aggiornando USB Loader GX." + +msgid "Error writing the data." +msgstr "Errore scrittura dati." + +msgid "Error:" +msgstr "Errore:" + +msgid "Error: Not enough space on SD." +msgstr "Errore: Spazio insufficiente sulla SD" + +msgid "Errors occured." +msgstr "Si sono verificati degli errori." + +msgid "Everything" +msgstr "Tutto" + +msgid "Exit" +msgstr "Esci" + +msgid "Exit to where?" +msgstr "Uscire dove?" + +msgid "Export All Saves to EmuNand" +msgstr "Esporta salvataggi su NAND Emulata" + +msgid "Export Miis to EmuNand" +msgstr "Esporta Mii su NAND Emulata" + +msgid "Export SYSCONF to EmuNand" +msgstr "Esporta SYSCONF su NAND emulata" + +msgid "Extract Miis to the Emu NAND?" +msgstr "Estrarre i Mii su NAND emulata?" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "Estrarre il SYSCONF su NAND emulata?" + +msgid "Extract Save to EmuNand" +msgstr "Estrai i salvataggi su NAND emulata" + +msgid "Extracting file:" +msgstr "Estraendo file:" + +msgid "Extracting files..." +msgstr "Estraendo i file..." + +msgid "Extracting files:" +msgstr "Estraendo i file:" + +msgid "Extracting nand files:" +msgstr "Estraendo il file della NAND:" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "Fallito" + +msgid "Failed copying file" +msgstr "Copia dei file fallita" + +msgid "Failed formating" +msgstr "Formattazione fallita" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "Estrazione di tutti i file fallita. Il salvataggio potrebbe non esistere." + +msgid "Failed to extract." +msgstr "Estrazione fallita." + +msgid "Failed to initialize the USB storage device." +msgstr "Inizializzazione della periferica USB fallita." + +msgid "Failed to open partition" +msgstr "Accesso alla partizione fallito" + +msgid "Failed to read ticket." +msgstr "Lettura del ticket fallita." + +msgid "Failed to read tmd file." +msgstr "Lettura del file tmd fallita." + +msgid "Failed to read wad header." +msgstr "Lettura dell'header del wad fallita." + +msgid "Failed updating" +msgstr "Aggiornamento fallito" + +msgid "Favorite Level" +msgstr "Livello di preferenza" + +msgid "Features" +msgstr "Funzionalità" + +msgid "Features Settings" +msgstr "Impostazioni funzionalità" + +msgid "Feb" +msgstr "Febbraio" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "File non trovato." + +msgid "File read/write error." +msgstr "Errore di lettura/scrittura nel file" + +msgid "Files extracted successfully." +msgstr "Files estratti con successo." + +#, c-format +msgid "Filesize is %i Byte." +msgstr "La dimensione del file è di %i byte." + +msgid "Filesize is 0 Byte." +msgstr "La dimensione del file è di 0 byte." + +msgid "Flat Covers" +msgstr "Copertine 2D" + +msgid "Flip-X" +msgstr "Scorrimento dischi" + +msgid "Folder" +msgstr "Cartella" + +msgid "Font Scale Factor" +msgstr "Rapporto font" + +msgid "Force 16:9" +msgstr "Forza 16:9" + +msgid "Force 4:3" +msgstr "Forza 4:3" + +msgid "Force NTSC" +msgstr "Forza NTSC" + +msgid "Force NTSC480p" +msgstr "Forza NTSC480p" + +msgid "Force PAL480p" +msgstr "Forza PAL480p" + +msgid "Force PAL50" +msgstr "Forza PAL50" + +msgid "Force PAL60" +msgstr "Forza PAL60" + +msgid "Force Titles from Disc" +msgstr "Forza titolo da disco" + +msgid "Force Widescreen" +msgstr "Forza Widescreen" + +msgid "Format" +msgstr "Formatta" + +msgid "Formatting, please wait..." +msgstr "Formattando, attendere prego..." + +msgid "Found missing images." +msgstr "Trovate le immagini mancanti." + +msgid "Frame" +msgstr "Frame" + +msgid "Frame Projection Height" +msgstr "Proiezione altezza frame" + +msgid "Frame Projection Width" +msgstr "Proiezione larghezza frame" + +msgid "Frame Projection X-Offset" +msgstr "Proiezione offset-x frame" + +msgid "Frame Projection Y-Offset" +msgstr "Proiezione offset-y frame" + +msgid "Frames" +msgstr "Frames" + +msgid "Free Space" +msgstr "Spazio libero" + +msgid "French" +msgstr "Francese" + +msgid "Full" +msgstr "Completa" + +msgid "Full Cover Path" +msgstr "Percorso copertine intere" + +msgid "Full Covers" +msgstr "Copertine intere" + +msgid "Full Menu" +msgstr "Menu completo" + +msgid "Full covers Download" +msgstr "Scarica copertine intere" + +msgid "Full shutdown" +msgstr "Spegnimento completo" + +msgid "GAMEID_Gamename" +msgstr "IDGIOCO_Nomegioco" + +msgid "GC Banner Scale" +msgstr "Rapporto banner GC" + +msgid "GC Games" +msgstr "Giochi GC" + +msgid "GC Install 32K Aligned" +msgstr "Allineamento 32K giochi GC" + +msgid "GC Install Compressed" +msgstr "Compressione giochi GC" + +msgid "GCT Cheatcodes Path" +msgstr "Percorso trucchi GCT" + +msgid "GCT File created" +msgstr "File GCT creato" + +msgid "GUI Settings" +msgstr "Impostazioni interfaccia" + +msgid "GXDraw" +msgstr "GXDraw" + +msgid "GXFlush" +msgstr "GXFlush" + +msgid "Game Cube Games Delete" +msgstr "Menu disinstallazioni GC" + +msgid "Game Cube Install Menu" +msgstr "Menu installazioni GC" + +msgid "Game ID" +msgstr "ID gioco" + +msgid "Game IOS" +msgstr "IOS gioco" + +msgid "Game Language" +msgstr "Lingua gioco" + +msgid "Game Load" +msgstr "Impost. gioco" + +msgid "Game Lock" +msgstr "Blocco gioco" + +msgid "Game Only" +msgstr "Solo gioco" + +msgid "Game Region" +msgstr "Regione gioco" + +msgid "Game Size" +msgstr "Dimensione gioco" + +msgid "Game Sound Mode" +msgstr "Modalità suono giochi" + +msgid "Game Sound Volume" +msgstr "Volume suono giochi" + +msgid "Game Split Size" +msgstr "Suddivisione giochi" + +msgid "Game Window Mode" +msgstr "Tipo visualizzazione giochi" + +msgid "Game is already installed:" +msgstr "Gioco già installato:" + +msgid "Game's IOS" +msgstr "IOS del gioco" + +msgid "Game/Install Partition" +msgstr "Partizione giochi/inst." + +msgid "GameCube" +msgstr "GameCube" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "Modalità GameCube" + +msgid "GameCube Source" +msgstr "Sorgente GameCube" + +msgid "Gamename [GAMEID]" +msgstr "Nomegioco [IDGIOCO]" + +msgid "Games" +msgstr "Giochi" + +msgid "Generating GXGameCategories.xml" +msgstr "Generando GXGameCategories.xml" + +msgid "Genre:" +msgstr "Genere:" + +msgid "German" +msgstr "Tedesco" + +msgid "Getting file list..." +msgstr "Ottenendo la lista dei file..." + +msgid "Getting game folder size..." +msgstr "Ottenendo la dimensione della cartella del gioco..." + +msgid "Global Settings" +msgstr "Impostazioni globali" + +msgid "Grid Scroll Speed" +msgstr "Velocità " + +msgid "HOME Menu" +msgstr "Menu HOME" + +msgid "Hard Drive Settings" +msgstr "Impostazioni Hard Disk" + +msgid "High Quality" +msgstr "Alta qualità" + +msgid "High/Low" +msgstr "Alta/Bassa" + +msgid "Homebrew Apps Path" +msgstr "Percorso Homebrew" + +msgid "Homebrew Channel" +msgstr "Canale homebrew" + +msgid "Homebrew Launcher" +msgstr "Applicazioni homebrew" + +msgid "Hooktype" +msgstr "Tipo di hook" + +msgid "Hour" +msgstr "Ora" + +msgid "How do you want to update?" +msgstr "Come vuoi aggiornare?" + +msgid "How to Shutdown?" +msgstr "Come vuoi spegnere?" + +msgid "Import Categories" +msgstr "Importa categorie" + +msgid "Import operation successfully completed." +msgstr "Importazione completata con successo." + +msgid "Importing categories" +msgstr "Importando categorie..." + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "File in arrivo %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "File in arrivo %0.2fMB" + +msgid "Individual" +msgstr "Individuale" + +msgid "Initializing Network" +msgstr "Inizializzando la rete" + +msgid "Insert Disk" +msgstr "Inserisci un disco" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "Inserisci un disco Wii o GameCube!" + +msgid "Install" +msgstr "Installa" + +msgid "Install Canceled" +msgstr "Installazione cancellata" + +msgid "Install Directories" +msgstr "Directory di installazione" + +msgid "Install Error!" +msgstr "Errore durante l'installazione!" + +msgid "Install Partitions" +msgstr "Installa partizioni" + +msgid "Install a game" +msgstr "Installa un gioco" + +msgid "Install error - Cleaning incomplete data." +msgstr "Error di installazione. Pulizia dei dati incompleti" + +msgid "Install finished" +msgstr "Installazione completata" + +msgid "Installing Game Cube Game..." +msgstr "Installando il gioco GameCube..." + +msgid "Installing content" +msgstr "Installando contenuto" + +msgid "Installing game:" +msgstr "Installando gioco:" + +msgid "Installing title..." +msgstr "Installando titolo..." + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "Numero IOS invalido. Deve essere compreso tra 200 e 255 o -1 per globale" + +msgid "Invalid wad file." +msgstr "File WAD invalido." + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Hai informazioni che potrebbero esserci utili. Per favore, comunicale al team di sviluppo." + +msgid "Italian" +msgstr "Italiano" + +msgid "Jan" +msgstr "Gennaio" + +msgid "Japanese" +msgstr "Giapponese" + +msgid "Japanese Patch" +msgstr "Patch Giapponese (NTSC J)" + +msgid "Joypad" +msgstr "Joypad" + +msgid "July" +msgstr "Luglio" + +msgid "June" +msgstr "Giugno" + +msgid "KPAD Read" +msgstr "KPAD Read" + +msgid "Keyboard" +msgstr "Tastiera" + +msgid "Korean" +msgstr "Coreano" + +msgid "LED Activity" +msgstr "Illuminazione LED" + +msgid "Language Files" +msgstr "Traduzioni" + +msgid "Language change:" +msgstr "Cambia Lingua:" + +msgid "Languagefiles Path" +msgstr "Percorso Traduzioni" + +msgid "Languagepath changed." +msgstr "Percorso Traduzioni modificato." + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Puoi avviare i giochi Wii dalla NAND emulata solo con i cIOS d2x! Modifica l'IOS a un cIOS d2x prima." + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Puoi avviare i canali nella NAND Emulata soltanto con i cIOS d2x! Modifica l'IOS a un cIOS d2x prima." + +msgid "Left" +msgstr "Sinistra" + +msgid "Like SysMenu" +msgstr "Come il menu di sistema" + +msgid "List on Gamelaunch" +msgstr "Elenco all'avvio del gioco" + +msgid "Load" +msgstr "Carica" + +msgid "Load From SD/USB" +msgstr "Carica da SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Caricare il file da: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Usare questo DOL come DOL alternativo?" + +msgid "Loader Settings" +msgstr "Impostazioni loader" + +msgid "Loader's IOS" +msgstr "IOS del Loader" + +msgid "Loading standard language." +msgstr "Caricando la lingua predefinita." + +msgid "Loading standard music." +msgstr "Caricando la musica predefinita." + +msgid "Lock Console" +msgstr "Blocca console" + +msgid "Lock USB Loader GX" +msgstr "Blocca USB Loader GX" + +msgid "Locked" +msgstr "Bloccata" + +msgid "Log to file" +msgstr "Log su file" + +msgid "Loop Directory" +msgstr "Sequenza brani" + +msgid "Loop Music" +msgstr "Ripeti brano" + +msgid "Loop Sound" +msgstr "Suono ripetuto" + +msgid "Low Quality" +msgstr "Bassa qualità" + +msgid "Low/High" +msgstr "Bassa/Alta" + +msgid "MIOS (Default & Customs)" +msgstr "MIOS (Predefinito e personalizzati)" + +msgid "Main DOL" +msgstr "Avvio main.dol" + +msgid "Main GameCube Games Path" +msgstr "Percorso giochi GameCube" + +msgid "Main GameCube Path" +msgstr "Percorso GameCube" + +msgid "Main Path" +msgstr "Percorso principale" + +msgid "Manual (40~120)" +msgstr "Manuale (40~120)" + +msgid "Mar" +msgstr "Marzo" + +msgid "Mark new games" +msgstr "Evidenzia i giochi nuovi" + +msgid "May" +msgstr "Maggio" + +msgid "Memory Card Blocks Size" +msgstr "Blocchi Memory card" + +msgid "Memory Card Emulation" +msgstr "Emulazione Memory card" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "Le Memory card da 2043 blocchi hanno alcuni problemi con Nintendont. Usale a tuo rischio e pericolo." + +msgid "Messageboard Update" +msgstr "Aggiorna messaggi" + +msgid "Motion+ Video" +msgstr "Video motion+" + +msgid "Mount DVD drive" +msgstr "Avvia DVD" + +msgid "Mount USB at launch" +msgstr "Monta USB all'avvio" + +msgid "Move File" +msgstr "Muovi il file" + +msgid "Multiple Partitions" +msgstr "Partizioni multiple" + +msgid "Music Loop Mode" +msgstr "Ripeti musica sottofondo" + +msgid "Music Volume" +msgstr "Volume musica" + +msgid "NMM Mode" +msgstr "Modalità NMM" + +msgid "Nand Chan. Emulation" +msgstr "Emulazione canali NAND" + +msgid "Nand Channels" +msgstr "Canali NAND" + +msgid "Nand Emu Channel Path" +msgstr "Percorso emulazione canali " + +msgid "Nand Emu Path" +msgstr "Percorso NAND emulata" + +msgid "Nand Emulation" +msgstr "Emulazione della NAND" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "L'emulazione della NAND è disponibile solo con i cIOS d2x!" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "L'emulazione della NAND funziona solo con partizioni FAT/FAT32!" + +msgid "Nand Saves Emulation" +msgstr "Emulazione salvataggi" + +msgid "Native Controller" +msgstr "Controller Nativi" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "Selezione percorso NAND Neek fallito" + +msgid "Neek kernel file not found." +msgstr "File kernel neek non trovato" + +msgid "Neek kernel loading failed." +msgstr "Caricamento Kernel Neek fallito" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "Neek2o non supporta 'Percorso dei canali NAND emulati' su SD! Per favore imposta Uneek2o al suo posto" + +msgid "Neither" +msgstr "Neanche" + +msgid "Network is not initiated." +msgstr "La rete non è inizializzata." + +msgid "Next" +msgstr "Succ." + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "Percorso loader Nintendont" + +msgid "No" +msgstr "No" + +msgid "No Cheatfile found" +msgstr "Nessun file di trucchi trovato" + +msgid "No DOL file found on disc." +msgstr "Nessun file DOL trovato sul disco." + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "Non Suddividere" + +msgid "No URL or Path specified." +msgstr "Nessun URL o Cartella specificata." + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "Nessuna partizione WBFS o FAT/NTFS/EXT trovata" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "Winnertag.xml non trovato nel percorso specificato. Vuoi creare un file di esempio?" + +msgid "No change" +msgstr "Non cambiare" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "Nessun trucco selezionato! Il file GCT deve essere eliminato?" + +msgid "No data could be read." +msgstr "Impossibile leggere i dati." + +msgid "No disc inserted." +msgstr "Nessun disco inserito." + +msgid "No favorites selected." +msgstr "Nessun preferito selezionato." + +msgid "No file missing!" +msgstr "Nessun file mancante!" + +msgid "No games found on the disc" +msgstr "Nessun gioco trovato nel disco" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "Non è stata trovata nessuna traduzione da aggiornare! Vuoi scaricarle ora? " + +msgid "No new updates." +msgstr "Nessun nuovo aggiornamento." + +msgid "No themes found on the site." +msgstr "Nessun tema trovato sul sito." + +msgid "No themes found." +msgstr "Nessun tema trovato." + +msgid "No wad file found in this folder." +msgstr "Nessun file wad in questa cartella" + +msgid "NoSSL only" +msgstr "Solo NoSSL" + +msgid "None" +msgstr "Nessuno" + +msgid "Normal" +msgstr "Normale" + +msgid "Not Initialized" +msgstr "Non Inizializzato" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "Il disco non è per Wii/GameCube" + +msgid "Not a valid URL" +msgstr "Non è un URL valido" + +msgid "Not a valid URL path" +msgstr "Non è un percorso URL valido" + +msgid "Not a valid domain" +msgstr "Non è un dominio valido" + +msgid "Not enough free memory." +msgstr "Memoria libera insufficiente." + +msgid "Not enough free space on device." +msgstr "Spazio insufficiente nel dispositivo." + +msgid "Not enough free space!" +msgstr "Spazio libero insufficiente!" + +msgid "Not enough memory for FST." +msgstr "Memoria insufficiente per l'FST." + +msgid "Not enough memory." +msgstr "Memoria insufficiente." + +msgid "Not required" +msgstr "Non necessario" + +msgid "Not supported format!" +msgstr "Formato non supportato!" + +msgid "Nothing selected to delete." +msgstr "Non è stato selezionato niente da eliminare." + +msgid "Nothing selected to install." +msgstr "Non è stato selezionato niente da installare." + +msgid "Nov" +msgstr "Novembre" + +msgid "OFF" +msgstr "OFF" + +msgid "OK" +msgstr "OK" + +msgid "ON" +msgstr "ON" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "OSSleepThread" + +msgid "Ocarina" +msgstr "Ocarina" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "Ocarina non è ancora supportato da neek2o. Avviare comunque il gioco?" + +msgid "Oct" +msgstr "Ottobre" + +msgid "Official Site:" +msgstr "Sito ufficiale:" + +msgid "Offset" +msgstr "Offset" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "Singola linea A" + +msgid "One Line B" +msgstr "Singola Linea B" + +msgid "Only Game Partition" +msgstr "Solo Partizione Gioco" + +msgid "Only for Install" +msgstr "Solo per Installare" + +msgid "Original" +msgstr "Originale" + +msgid "Original/Customs" +msgstr "Origin./Modific." + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "Patch PAL50" + +msgid "Parental Control" +msgstr "Controllo Genitori" + +msgid "Partial" +msgstr "Parziale" + +msgid "Partition" +msgstr "Partizione" + +msgid "Password" +msgstr "Password" + +msgid "Password Changed" +msgstr "Password cambiata" + +msgid "Password has been changed" +msgstr "La password è stata cambiata" + +msgid "Patch Country Strings" +msgstr "Patch codice regione" + +msgid "Path Changed" +msgstr "Percorso cambiato" + +msgid "Permission denied." +msgstr "Permesso negato." + +msgid "Pick from a list" +msgstr "Seleziona da un elenco" + +msgid "Pixels" +msgstr "Pixel" + +msgid "Play Count" +msgstr "Contatore" + +msgid "Play Next" +msgstr "Riproduci successivo" + +msgid "Play Once" +msgstr "Riproduci una volta" + +msgid "Play Previous" +msgstr "Riproduci precedente" + +msgid "Playing Music:" +msgstr "Riproducendo:" + +msgid "Please wait" +msgstr "Attendere prego" + +msgid "Please wait..." +msgstr "Attendere prego..." + +msgid "Power off the Wii" +msgstr "Spegni il Wii" + +msgid "Prev" +msgstr "Prec." + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "Processo completato." + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Pulsanti" + +msgid "Published by" +msgstr "Pubblicato da" + +msgid "Quick Boot" +msgstr "Avvio rapido" + +msgid "Random Directory Music" +msgstr "Riproduci brani in ordine casuale" + +msgid "Real Nand" +msgstr "NAND reale" + +msgid "Receiving file from:" +msgstr "Ricevendo file da:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "Patch regione" + +msgid "Released" +msgstr "Rilasciato" + +msgid "Reload SD" +msgstr "Ricarica SD" + +msgid "Reloading game list now, please wait..." +msgstr "Ricaricando la lista dei giochi, attendere prego..." + +msgid "Remember Unlock" +msgstr "Ricorda sblocco" + +msgid "Remove Read Speed Limit" +msgstr "Rimuovi limite vel. lettura" + +msgid "Remove update" +msgstr "Rimuovi aggiornamento" + +msgid "Rename Game Title" +msgstr "Rinomina gioco" + +msgid "Rename category" +msgstr "Rinomina categoria" + +msgid "Reset" +msgstr "Riavvia" + +msgid "Reset BG Music" +msgstr "Ripristina musica sottofondo" + +msgid "Reset Playcounter" +msgstr "Azzera contatore" + +msgid "Reset to default BGM?" +msgstr "Ripristinare la musica di sottofondo predefinita?" + +msgid "Restarting..." +msgstr "Riavviando..." + +msgid "Return" +msgstr "Ritorna" + +msgid "Return To" +msgstr "Ritorna a" + +msgid "Return to Wii Menu" +msgstr "Ritorna al menu Wii" + +msgid "Right" +msgstr "Destra" + +msgid "Rotating Disc" +msgstr "Rotazione disco" + +msgid "Round" +msgstr "Rotondo" + +msgid "Rumble" +msgstr "Vibrazione" + +msgid "SChinese" +msgstr "Cinese semplificato" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "SD inacessibile." + +msgid "SD GameCube Games Path" +msgstr "Percorso giochi Gamecube su SD" + +msgid "SD GameCube Path" +msgstr "Percorso GameCube su SD" + +msgid "SD Path" +msgstr "Percorso SD" + +msgid "SFX Volume" +msgstr "Volume SFX" + +msgid "Save" +msgstr "Salva" + +msgid "Save Failed. No device inserted?" +msgstr "Salvataggio fallito. La periferica è connessa?" + +msgid "Save Game List to" +msgstr "Salva l'elenco dei giochi in" + +msgid "Save List" +msgstr "Salva elenco" + +msgid "Saved" +msgstr "Salvato" + +msgid "Savegame might not exist for this game." +msgstr "Il salvataggio potrebbe non esistere per questo gioco." + +msgid "Screensaver" +msgstr "Salvaschermo" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "Seleziona" + +msgid "Select DOL Offset" +msgstr "Seleziona Offset DOL" + +msgid "Select a DOL" +msgstr "Seleziona un DOL" + +msgid "Select a DOL from Game" +msgstr "Seleziona un DOL dal gioco" + +msgid "Select game categories" +msgstr "Seleziona categorie giochi" + +msgid "Select loader mode" +msgstr "Seleziona modalità loader" + +msgid "Select the NAND Emu Path to use." +msgstr "Seleziona il percorso della NAND emulata da usare" + +msgid "Select titles sources." +msgstr "Seleziona la sorgente dei titoli." + +msgid "Sept" +msgstr "Settembre" + +msgid "Set Search-Filter" +msgstr "Imposta il filtro di ricerca" + +msgid "Settings" +msgstr "Impostazioni" + +msgid "Settings File" +msgstr "File impostazioni" + +msgid "Show Categories" +msgstr "Visualizza categorie" + +msgid "Show Favorite on banner" +msgstr "Mostra banner sui preferiti" + +msgid "Show Free Space" +msgstr "Visualizza spazio libero" + +msgid "Show Play Count" +msgstr "Visualizza contatore" + +msgid "Show SD" +msgstr "Mostra SD" + +msgid "Shutdown System" +msgstr "Spegnimento" + +msgid "Shutdown Wii" +msgstr "Spegni Wii" + +msgid "Skip Errors" +msgstr "Salta errori" + +msgid "Skip IPL" +msgstr "Salta IPL" + +msgid "Sneek Video Patch" +msgstr "Patch video sneek" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "Spiacenti, il menu di download temi non funziona più perché http://wii.spiffy360.com ora richiede la registrazione degli utenti" + +msgid "Sort alphabetically" +msgstr "Ordina alfabeticamente" + +msgid "Sort by number of players" +msgstr "Ordinea per numero giocatori" + +msgid "Sort by rank" +msgstr "Ordina per più votato" + +msgid "Sort order by most played" +msgstr "Ordine per più giocato" + +msgid "Sound" +msgstr "Audio" + +msgid "Sound Settings" +msgstr "Impostazioni audio" + +msgid "Sound+BGM" +msgstr "Suono+sottof." + +msgid "Sound+Quiet" +msgstr "Suono+silenzio" + +msgid "Spanish" +msgstr "Spagnolo" + +msgid "Special thanks to:" +msgstr "Un ringraziamento speciale a:" + +msgid "Split each 2GB" +msgstr "Suddividi ogni 2GB" + +msgid "Split each 4GB" +msgstr "Suddividi ogni 4GB" + +msgid "Standby" +msgstr "Standby" + +msgid "Start" +msgstr "Avvia" + +msgid "Success" +msgstr "Successo" + +msgid "Success." +msgstr "Successo." + +msgid "Success:" +msgstr "Successo:" + +msgid "Successfully Saved" +msgstr "Salvato correttamente" + +msgid "Successfully Updated" +msgstr "Aggiornato correttamente" + +msgid "Successfully copied" +msgstr "Copiato correttamente" + +msgid "Successfully deleted:" +msgstr "Eliminato correttamente:" + +msgid "Successfully extracted theme." +msgstr "Tema estratto correttamente." + +msgid "Successfully installed:" +msgstr "Installato correttamente:" + +msgid "Successfully updated." +msgstr "Aggiornato correttamente." + +msgid "Switching to channel list mode." +msgstr "Passando alla modalità canali." + +msgid "Sync FAT32 FS Info" +msgstr "Sincronizza info FS FAT 32" + +msgid "Synchronizing..." +msgstr "Sincronizzando..." + +msgid "System Default" +msgstr "Predefinita del sistema" + +msgid "TChinese" +msgstr "Cinese tradizionale" + +msgid "TXT Cheatcodes Path" +msgstr "Percorso trucchi TXT" + +msgid "The .them file was not found in the zip." +msgstr "Il file .them non è stato trovato nelllo zip." + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "L'impostazione forza widescreen richieder DIOS MIOS v2.1 o superiore. L'impostazione verrà ignorata." + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "I Mii verranno estratti nei percorsi della NAND emulata e dei canali NAND emulati. Attenzione: Tutti i file esistenti saranno sovrascritti." + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "L'impostazione No Disc+ richiede DIOS MIOS 2.2 update2. L'impostazione verrà ignorata." + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Il file SYSCONF verranno estratti nei percorsi della NAND emulata e dei canali NAND emulati. Attenzione: Tutti i file esistenti saranno sovrascritti." + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "L'applicazione potrebbe crashare se è in corso un accesso di lettura/scrittura sulla SD!" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "La cartella specificata non esiste. Vuoi crearla ora?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "I file verranno estratti nei percorsi della NAND emulata e dei canali NAND emulati. Attenzione: Tutti i file esistenti saranno sovrascritti." + +msgid "The game is on SD Card." +msgstr "Il gioco è sulla SD." + +msgid "The game is on USB." +msgstr "Il gioco è sull'USB." + +msgid "The save game will be extracted to your emu nand path." +msgstr "Il salvataggio verrà estratto nel percorso della NAND Emulata." + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "Il salvataggio verrà estratto nel percorso dei salvataggi e canali emulati. Attenzione: Tutti i file esistenti saranno sovrascritti." + +msgid "The wad file was installed" +msgstr "File WAD installato" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "Installazione del WAD fallita con errore %i" + +msgid "Theme Downloader" +msgstr "Download temi" + +msgid "Theme Menu" +msgstr "Menu temi" + +msgid "Theme Path" +msgstr "Percorso temi" + +msgid "Theme Title:" +msgstr "Titolo del tema:" + +msgid "Themes by www.spiffy360.com" +msgstr "Temi da www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "Questo IOS è quello di BootMii ios. Se sei sicuro di aver installato qualcos'altro al suo posto allora ignora questo avvertimento." + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "Questo IOS non è stato trovato nella lista dei titoli. Se sei sicuro di averlo installato allora ignora questo avvertimento." + +msgid "This Nintendont version does not support games on USB." +msgstr "Questa versione di Nintendont non supporta i giochi da USB" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "Questa versione di Nintendont non è correttamente supportata. Autoboot disabilitato." + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "Questo gioco contiene più di un disco. Selezione quello da avviare." + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "Questo percorso deve essere sulla SD!" + +msgid "Time left:" +msgstr "Tempo rimasto:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Avvia titoli" + +msgid "Titles Path" +msgstr "Percorso titoli" + +msgid "Titles from GameTDB" +msgstr "Titoli da GameTDB" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "Per avviare i giochi GameCube da disco devi impostare la modalità Gamecube su MIOS nelle impostazioni del gioco." + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "Per avviare giochi gamecube con %s devi inserirli in una partizione USB FAT 32" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "Per avviare giochi gamecube con %s devi impostare il tuo 'Percorso principale GameCube' nella prima partizione primaria FAT 32" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "Per avviare giochi gamecube con %s devi impostare il tuo 'Percorso principale GameCube' nella prima partizione primaria dell'Hard Disk" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "Per avviare giochi gamecube con %s devi impostare il tuo 'Percorso principale GameCube' su una partizione USB FAT 32" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "Per avviare i giochi GameCube con %s devi usare un Hard Disk con settori da 512 bytes" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "Per avviare giochi Gamecube con %s devi usare una partizione con cluster da 32k o meno" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "Per lanciare giochi GameCube con Devolution hai bisogno del file loader.bin nella tua cartella Devolution" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "Per lanciare giochi Gamcube con Nintendont hai bisogno del file boot. Dol nella tua cartella Nintendont" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "Per usare controller HID con %s hai bisogno del file %$" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "Per usare neek devi impostare il tuo 'Percorso canale NAND emulata' nella prima partizione primaria dell'Hard Disk" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "Per usare neek devi impostare il tuo 'Percorso canale NAND emulata' su una partizione FAT32 " + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "Per usare neek hai bisogno di un Hard Disk da 512 bytes per settore" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "Per usare Ocarina con %s hai bisogno del file %s" + +msgid "Tooltip Delay" +msgstr "Ritardo suggerimenti" + +msgid "Tooltips" +msgstr "Suggerimenti" + +msgid "Transfer failed" +msgstr "Trasferimento fallito" + +msgid "Triforce Arcade Mode" +msgstr "Modalità Triforce Arcade" + +msgid "Two Lines" +msgstr "Due linee" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "Periferica USB non inizializzata" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX è protetto" + +msgid "USB Port" +msgstr "Porta USB" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "Il cambio della porta USB è possibile solo con i cIOS di Hermes." + +msgid "USB-HID Controller" +msgstr "Controller USB-HID" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "Usb Loader GX non può verificare il file boot.dol di Nintendont. Avviare comunque questo boot.dol?" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "USBLoader GX non può sceivere il file configurazione. Avviare comuqnue Nintendont?" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "USBLoaderGX r1218 o successivo è richiesto per Nintendont Alpha v0.1. Per favore aggiorna la tua versione di Nintendont" + +msgid "Uninstall" +msgstr "Disinstalla" + +msgid "Uninstall Game" +msgstr "Disinstalla gioco" + +msgid "Uninstall Menu" +msgstr "Menu disinstallazioni" + +msgid "Uninstall all" +msgstr "Disinstalla tutto" + +msgid "Unknown" +msgstr "Sconosciuto" + +msgid "Unlock USB Loader GX" +msgstr "Sblocca USB Loader GX" + +msgid "Unlocked" +msgstr "Sbloccata" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "Formato non supportato, prova a estrarre manualmente TempTheme.zip." + +msgid "Update" +msgstr "Aggiornamenti" + +msgid "Update All" +msgstr "Aggiorna tutto" + +msgid "Update DOL" +msgstr "Aggiorna DOL" + +msgid "Update Files" +msgstr "Aggiorna i files" + +msgid "Update Path" +msgstr "Percorso aggiornamenti" + +msgid "Update all Language Files" +msgstr "Aggiorna tutte le traduzioni" + +msgid "Update failed" +msgstr "Aggiornamento fallito" + +msgid "Update successfull" +msgstr "Aggiornato con successo" + +msgid "Updating Language Files:" +msgstr "Aggiornando traduzioni:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "File ZIP installato nella cartella degli Homebrew." + +msgid "Use System Font" +msgstr "Usa il font di sistema" + +msgid "Use global" +msgstr "Usa globalmente" + +msgid "VBI (Default)" +msgstr "VBI (Predefinito)" + +msgid "VIDTV Patch" +msgstr "Patch VIDTV" + +msgid "Version:" +msgstr "Versione:" + +#, c-format +msgid "Version: %s" +msgstr "Versione: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Modalità video" + +msgid "Video Scale Value" +msgstr "Valore scaling video" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "Scaling video" + +msgid "Virtual Pointer Speed" +msgstr "Velocità puntatore virtuale" + +msgid "WDM Files Path" +msgstr "Percorso file WDM" + +msgid "WIP Patches Path" +msgstr "Percorso patch WIP" + +msgid "Waiting..." +msgstr "In attesa..." + +msgid "Warning" +msgstr "Attenzione" + +msgid "Warning:" +msgstr "Attenzione:" + +msgid "What do you want to do?" +msgstr "Che cosa vuoi fare?" + +msgid "What do you want to update?" +msgstr "Che cosa vuoi aggiornare?" + +msgid "What should be deleted for this game title:" +msgstr "Cosa deve essere eliminato per questo gioco:" + +msgid "What to extract from NAND?" +msgstr "Che cosa vuoi estrarre dalla NAND?" + +msgid "Where should the game be installed to?" +msgstr "Dove deve essere installato il gioco?" + +msgid "Where to dump NAND?" +msgstr "Dove effettuare il dump della NAND?" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "Quale periferica vuoi usare per i files Nintendont" + +msgid "Which mode do you want to use?" +msgstr "Quale modalità vuoi usare?" + +msgid "WiFi Features" +msgstr "Funzionalità wi-fi" + +msgid "Widescreen Factor" +msgstr "Fattore widescreen" + +msgid "Widescreen Fix" +msgstr "Correzione Widescreen" + +msgid "Wii Games" +msgstr "Giochi Wii" + +msgid "Wii Menu" +msgstr "Menu Wii" + +msgid "Wii Settings" +msgstr "Impostazioni Wii" + +msgid "WiiTDB.xml" +msgstr "WiiTDB.xml" + +msgid "WiiTDB.xml is up to date." +msgstr "WiiTDB.xml è già aggiornato" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "Illuminazione Wii" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "Wiinnertag" + +msgid "Wiinnertag Path" +msgstr "Percorso Wiinnertag" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Wiinnertag richiede la connessione automatica delle rete all'avvio. Vuoi abilitarla ora?" + +msgid "Wiird Debugger" +msgstr "Debugger wiird" + +#, c-format +msgid "Write error on file: %s" +msgstr "Errore di scrittura sul file: %s" + +msgid "Writing GXGameCategories.xml" +msgstr "Scrivendo GXGameCategories.xml" + +msgid "Wrong Password" +msgstr "Password errata" + +msgid "Yes" +msgstr "Si" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "Stai cercando di selezionare una partizione FAT32/NTFS/EXT con un cIOS 249 di versione < 18. Continua a tuo rischio e pericolo." + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "Puoi selezionare,formattare una partizione o usare la Modalità Canali." + +msgid "You cannot delete this category." +msgstr "Non puoi eliminare questa categoria." + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "Hai bisogno di neek2o per caricare EmuNAND dalle sottocartelle" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "Devi installare DIOS MIOS Lite v1.2 o una versione successiva." + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "Hai bisogno di installare un loader GameCube aggiuntivo o selezionare una modalità GameCube differente per lanciare giochi GameCube da USB o SD" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "La tua partizione GameCube attuale non è compatibile. Per favore aggiorna Nintendont" + +msgid "Zoom Duration (Speed)" +msgstr "Durata dello zoom (Velocità)" + +msgid "and translators for language files updates" +msgstr "ed ai traduttori per gli agg. delle traduzioni" + +msgid "available" +msgstr "disponibile" + +msgid "does not exist!" +msgstr "non esiste!" + +msgid "does not exist! Loading game without cheats." +msgstr "non esiste! Caricando il gioco senza trucchi." + +msgid "files left" +msgstr "file mancanti" + +msgid "for FAT/NTFS support" +msgstr "per il supporto FAT/NTFS" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "per GameTBD e hosting copertine/immagine dischi" + +msgid "for Ocarina" +msgstr "per Ocarina" + +msgid "for diverse patches" +msgstr "per le numerose correzioni" + +msgid "for his awesome tool LibWiiGui" +msgstr "per la fantastica LibWiiGui" + +msgid "for hosting the themes" +msgstr "per i temi online" + +msgid "for the USB Loader source" +msgstr "per il codice sorgente dell'USB Loader" + +msgid "for their work on the wiki page" +msgstr "per il lavoro sulla pagina wiki" + +msgid "formatted!" +msgstr "formattato!" + +msgid "free" +msgstr "liberi" + +msgid "ms" +msgstr "ms" + +msgid "not set" +msgstr "Non impostata" + +msgid "of" +msgstr "di" + +msgid "seconds left" +msgstr "secondi rimasti" + +#~ msgid "Plugins Default Partition" +#~ msgstr "Partizione predefinita Plugins" + +#~ msgid "Plugin Files Path" +#~ msgstr "Percorso files Plugin" + +#~ msgid "Install WAD to EmuNand" +#~ msgstr "Installa WAD nella NAND emulata" + +#~ msgid "WAD Installation" +#~ msgstr "Installazione WAD" + +#~ msgid "GameTDB Path" +#~ msgstr "Percorso GameTDB" + +#~ msgid "Anti" +#~ msgstr "Anti" + +#~ msgid "Error 002 fix" +#~ msgstr "Correzione errore 002" + +#~ msgid "Use Game Settings" +#~ msgstr "Usa impostazioni gioco" + +#~ msgid "Main tester:" +#~ msgstr "Tester principale:" + +#~ msgid "USB Device not found." +#~ msgstr "Periferica USB non trovata." + +#~ msgid "Boot/Standard" +#~ msgstr "cIOS predefinito" + +#~ msgid "DEVO LED Activity" +#~ msgstr "Led attività DEVO" + +#~ msgid "DEVO MemCard Emulation" +#~ msgstr "Emulazione memory card DEVO" + +#~ msgid "DML Auto" +#~ msgstr "Patch auto DML" + +#~ msgid "DML Debug" +#~ msgstr "Debug DML" + +#~ msgid "DML Force Widescreen" +#~ msgstr "Forza widescreen DML" + +#~ msgid "DML Japanese Patch" +#~ msgstr "Patch giapponese DML" + +#~ msgid "DML LED Activity" +#~ msgstr "Led attività DML" + +#~ msgid "DML NMM Mode" +#~ msgstr "Modalità NMM in DML" + +#~ msgid "DML No Disc+" +#~ msgstr "No Disc+ DML" + +#~ msgid "DML None" +#~ msgstr "Nessuna patch DML" + +#~ msgid "DML PAD Hook" +#~ msgstr "PAD hook DML" + +#~ msgid "DML Progressive Patch" +#~ msgstr "Patch video-progressivo DML" + +#~ msgid "DML Screenshot" +#~ msgstr "Screenshot DML" diff --git a/Languages/japanese.lang b/Languages/japanese.lang new file mode 100644 index 0000000..bdeaffd --- /dev/null +++ b/Languages/japanese.lang @@ -0,0 +1,2784 @@ +# USB Loader GX language source file. +# japanese.lang - r1142 +# don't delete/change this line (e). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:02+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: hosigumayuugi\n" +"Language-Team: hosigumayuugi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr "ダウンロードできませんでした" + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr "に保存されました。使用は 自己責任でお願いします" + +msgid " is not on the server." +msgstr "はサーバーにありません" + +#, c-format +msgid "%i files not found on the server!" +msgstr "%i 個のファイルがサーバーにありません" + +#, c-format +msgid "%i missing files" +msgstr "%i 個のファイルが不足しています" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "セットしない" + +msgid "1 (Child 7+)" +msgstr "7歳以上を制限" + +msgid "1 hour" +msgstr "1時間" + +msgid "10 min" +msgstr "10分" + +msgid "2 (Teen 12+)" +msgstr "12歳以上を制限" + +msgid "20 min" +msgstr "20分" + +msgid "2D Cover Path" +msgstr "2Dカバー" + +msgid "3 (Mature 16+)" +msgstr "16歳以上を制限" + +msgid "3 min" +msgstr "3分" + +msgid "30 min" +msgstr "30分" + +msgid "3D Cover Path" +msgstr "3Dカバー" + +msgid "3D Covers" +msgstr "3Dカバー" + +msgid "4 (Adults Only 18+)" +msgstr "CERO Zを制限" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5分" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "自動" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "カテゴリを追加" + +msgid "Adjust Overscan X" +msgstr "オーバースキャン調整 X" + +msgid "Adjust Overscan Y" +msgstr "オーバースキャン調整 Y" + +msgid "After zoom" +msgstr "ズーム後" + +msgid "All" +msgstr "全て" + +msgid "All Partitions" +msgstr "全ての領域" + +msgid "All files extracted." +msgstr "全てのファイルを書き出しました" + +msgid "All images downloaded successfully." +msgstr "全ての画像をダウンロードしました" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "使用制限が解除されました" + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "代替DOL起動" + +msgid "An example file was created here:" +msgstr "テンプレファイルが作成されました:" + +msgid "Animation Start" +msgstr "アニメ開始" + +msgid "App Language" +msgstr "使用言語" + +msgid "Apply" +msgstr "適用" + +msgid "Apr" +msgstr "4月" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "選択した全てのゲームをSDカードから削除しますか?" + +msgid "Are you sure you want to delete this category?" +msgstr "カテゴリを削除しますか?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "GameTDBからカテゴリをインポートしますか?" + +msgid "Are you sure you want to install on SD?" +msgstr "SDカードにインストールしますか?" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "USB Loader GXをロックしますか?" + +msgid "Are you sure you want to remount SD?" +msgstr "SDカードを再マウントしますか?" + +msgid "Are you sure you want to reset?" +msgstr "リセットしますか?" + +msgid "Are you sure?" +msgstr "よろしいですか?" + +msgid "Aspect Ratio" +msgstr "アスペクト比" + +msgid "Attention!" +msgstr "注意!" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "8月" + +msgid "Author(s):" +msgstr "制作者:" + +msgid "Auto" +msgstr "自動" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "自動ネット接続" + +msgid "BCA Codes Path" +msgstr "BCAコード" + +msgid "Back" +msgstr "もどる" + +msgid "Back to HBC or Wii Menu" +msgstr "HBC/Wiiメニューへ" + +msgid "Backgroundmusic" +msgstr "BGM" + +msgid "Banner Animation" +msgstr "バナーアニメ" + +msgid "Banner Animation Settings" +msgstr "バナーアニメ設定" + +msgid "Banner On Channels" +msgstr "チャンネル上のバナー" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "バナーグリッドレイアウトはAHBPROTが有効でないといけません!新しいHBCに更新してください" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "バナーウインドウはAHBPROTが有効でないといけません!新しいHBCに更新してください" + +msgid "Big thanks to:" +msgstr "協力:" + +msgid "Block Categories Menu" +msgstr "カテゴリメニューを制限" + +msgid "Block Categories Modify" +msgstr "カテゴリの編集を制限" + +msgid "Block Cover Downloads" +msgstr "カバーのダウンロードを制限" + +msgid "Block Custom Paths" +msgstr "パスの変更を制限" + +msgid "Block Feature Settings" +msgstr "機能設定を制限" + +msgid "Block Game Install" +msgstr "ゲームの追加を制限" + +msgid "Block Game Settings" +msgstr "ゲーム設定を制限" + +msgid "Block GameID Change" +msgstr "ゲームIDの変更を制限" + +msgid "Block Global Settings" +msgstr "設定を全て制限" + +msgid "Block Gui Settings" +msgstr "基本設定を制限" + +msgid "Block HBC Menu" +msgstr "HBCメニューを制限" + +msgid "Block Hard Drive Settings" +msgstr "HDD設定を制限" + +msgid "Block IOS Reload" +msgstr "IOS再読み込み防止" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "ローダーモードボタンを制限" + +msgid "Block Loader Settings" +msgstr "ローダーの設定を制限" + +msgid "Block Parental Settings" +msgstr "使用制限設定を制限" + +msgid "Block Priiloader Override" +msgstr "Priiloader上書きを制限" + +msgid "Block Reset Settings" +msgstr "設定の初期化を制限" + +msgid "Block SD Reload Button" +msgstr "SD再読み込みボタンを制限" + +msgid "Block Sound Settings" +msgstr "サウンド設定を制限" + +msgid "Block Theme Downloader" +msgstr "テーマのダウンロードを制限" + +msgid "Block Theme Menu" +msgstr "テーマメニューを制限" + +msgid "Block Title Launcher" +msgstr "タイトル起動を制限" + +msgid "Block Updates" +msgstr "更新を制限" + +msgid "Boot Content" +msgstr "起動コンテンツ" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "起動しますか?" + +msgid "Both" +msgstr "IDとリージョンを表示" + +msgid "Both Ports" +msgstr "両方のポート" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "BNRファイルをキャッシュ" + +msgid "Cache BNR Files Path" +msgstr "BNRファイルキャッシュ" + +msgid "Cache Titles" +msgstr "ゲーム名のキャッシュ" + +msgid "Can't be formatted" +msgstr "初期化できません" + +msgid "Can't create directory" +msgstr "フォルダを作れません" + +#, c-format +msgid "Can't create file: %s" +msgstr "ファイルを作成できません: %s" + +#, c-format +msgid "Can't create path: %s" +msgstr "パスを作成できません: %s" + +msgid "Can't delete:" +msgstr "削除できません:" + +msgid "Can't mount or unknown disc format." +msgstr "マウントできないか不明なディスク形式です" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "ファイルを開けません: %s" + +#, c-format +msgid "Can't open file: %s" +msgstr "ファイルを開けません: %s" + +#, c-format +msgid "Can't read file: %s" +msgstr "ファイルを読み込めません: %s" + +msgid "Cancel" +msgstr "やめる" + +msgid "Cannot write to destination." +msgstr "出力先に書き込めません" + +msgid "Categories" +msgstr "カテゴリ" + +msgid "Categories:" +msgstr "カテゴリ:" + +msgid "Change Play Path" +msgstr "パスの変更" + +msgid "Channel Launcher" +msgstr "チャンネルランチャー" + +msgid "Channels" +msgstr "チャンネル" + +msgid "Cheatfile is blank" +msgstr "チートファイルがありません" + +msgid "Clear" +msgstr "クリア" + +msgid "Click to Download Covers" +msgstr "クリックでカバーをダウンロード" + +msgid "Click to change game ID" +msgstr "クリックでゲームIDを変更" + +msgid "Clock" +msgstr "時計の表示" + +msgid "Clock Scale Factor" +msgstr "時計のサイズ" + +msgid "Close" +msgstr "とじる" + +msgid "Code Download" +msgstr "コードをダウンロード" + +#, c-format +msgid "Coded by: %s" +msgstr "開発: %s" + +msgid "Coding:" +msgstr "開発者:" + +msgid "Connection to server timed out." +msgstr "接続がタイムアウトしました" + +msgid "Console" +msgstr "状態" + +msgid "Console Default" +msgstr "初期値" + +msgid "Console Locked" +msgstr "GXはロックされています" + +msgid "Console must be unlocked for this option." +msgstr "変更にはロックの解除が必要です" + +msgid "Console must be unlocked to be able to use this." +msgstr "これを使うにはロックの解除が必要です" + +msgid "Console should be unlocked to modify it." +msgstr "変更にはロックの解除が必要です" + +msgid "Continue" +msgstr "続行" + +msgid "Continue to install game?" +msgstr "このゲームをインストールしますか?" + +msgid "Continue?" +msgstr "続行しますか?" + +msgid "Controllevel" +msgstr "制限レベル" + +msgid "Copy" +msgstr "コピー" + +msgid "Copying Canceled" +msgstr "コピーを中止しました" + +msgid "Copying GC game..." +msgstr "GCゲームをコピー中..." + +msgid "Copying files..." +msgstr "ファイルをコピー中..." + +msgid "Correct Password" +msgstr "正しい暗証番号です" + +msgid "Could not connect to the server." +msgstr "サーバーに再接続できません" + +msgid "Could not create GCT file" +msgstr "GCTファイルを作成できませんでした" + +#, c-format +msgid "Could not create path: %s" +msgstr "パスを作成できません: %s" + +msgid "Could not extract files for:" +msgstr "書き出しできません:" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "wiitdb.xmlにこのゲームの情報が見つかりませんでした" + +msgid "Could not get free device space for game." +msgstr "空き容量を取得できませんでした" + +msgid "Could not initialize DIP module!" +msgstr "DIPモジュールを初期化できません!" + +msgid "Could not initialize network!" +msgstr "ネットに接続できませんでした!" + +msgid "Could not initialize network, time out!" +msgstr "ネットワークに接続できませんでした" + +msgid "Could not open Disc" +msgstr "ディスクを開けませんでした" + +msgid "Could not open the WiiTDB.xml file." +msgstr "wiitdb.xmlを開けませんでした" + +msgid "Could not open wiitdb.xml." +msgstr "wiitdb.xmlを開けませんでした" + +msgid "Could not save." +msgstr "保存できませんでした" + +msgid "Could not write file." +msgstr "ファイルを書き込めません" + +msgid "Could not write to:" +msgstr "書き込めません:" + +msgid "Cover Download" +msgstr "何をダウンロードしますか" + +msgid "Create" +msgstr "作成" + +msgid "Credits" +msgstr "提供・協力" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "カスタムバナー" + +msgid "Custom Paths" +msgstr "パスを変更" + +msgid "Customs" +msgstr "カスタム" + +msgid "Customs/Original" +msgstr "カスタムを優先" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "代替DOL" + +msgid "Debug" +msgstr "デバッグ" + +msgid "Debug Wait" +msgstr "デバッグ待機" + +msgid "Debugger Paused Start" +msgstr "デバッガ待機スタート" + +msgid "Dec" +msgstr "12月" + +msgid "Default" +msgstr "初期値" + +msgid "Default Gamesettings" +msgstr "設定を初期化" + +msgid "Default Settings" +msgstr "設定を初期化" + +msgid "Delete" +msgstr "削除しますか" + +msgid "Delete Cached Banner" +msgstr "キャッシュ済みバナーを削除" + +msgid "Delete Cheat GCT" +msgstr "GCTファイルを削除" + +msgid "Delete Cheat TXT" +msgstr "TXTコードを削除" + +msgid "Delete Cover Artwork" +msgstr "カバー画像を削除" + +msgid "Delete Disc Artwork" +msgstr "ディスク画像を削除" + +msgid "Delete category" +msgstr "カテゴリを削除" + +msgid "Deleting directories..." +msgstr "ディレクトリを削除中..." + +msgid "Deleting files..." +msgstr "ファイルを削除中..." + +msgid "Design:" +msgstr "デザイン:" + +msgid "Details" +msgstr "詳細" + +msgid "Developed by" +msgstr "開発者:" + +msgid "Developer:" +msgstr "開発者:" + +msgid "Devolution" +msgstr "Devolution" + +msgid "Devolution Loader Path" +msgstr "Devolutionローダー" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "Devolutionのloader.binが読み込めません" + +msgid "Directory does not exist!" +msgstr "フォルダがありません" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "使用するディスク画像" + +msgid "Disc Artwork Path" +msgstr "ディスク画像" + +msgid "Disc Default" +msgstr "ディスクの初期値" + +msgid "Disc Insert Detected" +msgstr "ディスクの挿入を検知しました" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "読み込みエラー" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "破棄" + +msgid "DiskFlip" +msgstr "ディスクの回転風" + +msgid "Display" +msgstr "ゲーム情報" + +msgid "Display as a carousel" +msgstr "回転トレイ風に表示" + +msgid "Display as a channel grid" +msgstr "チャンネルグリッドで表示" + +msgid "Display as a grid" +msgstr "格子風に表示" + +msgid "Display as a list" +msgstr "リスト表示" + +msgid "Display favorites only" +msgstr "お気に入りのみ表示" + +msgid "Do you want to apply it now?" +msgstr "適用しますか?" + +msgid "Do you want to apply this theme?" +msgstr "このテーマを使いますか?" + +msgid "Do you want to change language?" +msgstr "言語を変更しますか?" + +msgid "Do you want to continue with next game?" +msgstr "次のゲームに続行しますか?" + +msgid "Do you want to copy now?" +msgstr "コピーしますか?" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "ゲームをSDにコピーするか削除しますか?" + +msgid "Do you want to delete a game on SD?" +msgstr "SDのゲームを削除しますか?" + +msgid "Do you want to discard changes?" +msgstr "変更を破棄しますか?" + +msgid "Do you want to download this theme?" +msgstr "ダウンロードしますか?" + +msgid "Do you want to extract all the save games?" +msgstr "全てのセーブを書き出しますか?" + +msgid "Do you want to extract the save game?" +msgstr "セーブデータを書き出しますか?" + +msgid "Do you want to format:" +msgstr "初期化しますか?" + +msgid "Do you want to install selected games?" +msgstr "選択したゲームをインストールしますか?" + +msgid "Do you want to load the default theme?" +msgstr "標準のテーマを読み込みますか?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "ネットワークに再接続しますか?" + +msgid "Do you want to start the game now?" +msgstr "ゲームを起動しますか?" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "全てのFAT32領域のセクタで空き容量情報を同期しますか?" + +msgid "Do you wish to update/download all language files?" +msgstr "すべての言語をダウンロードしますか?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "ダウンロード" + +msgid "Download Now" +msgstr "ダウンロード" + +msgid "Download finished" +msgstr "ダウンロードが終了しました" + +msgid "Downloading 3D Covers" +msgstr "両面カバーをダウンロード中" + +msgid "Downloading Custom Banners" +msgstr "カスタムバナーをダウンロード中" + +msgid "Downloading Flat Covers" +msgstr "正面カバーをダウンロード中" + +msgid "Downloading Full HQ Covers" +msgstr "フルカバー(精細)をダウンロード中" + +msgid "Downloading Full LQ Covers" +msgstr "フルカバー(普通)をダウンロード中" + +msgid "Downloading custom Discarts" +msgstr "カスタムレーベルをダウンロード中" + +msgid "Downloading file..." +msgstr "ダウンロード中です..." + +msgid "Downloading image:" +msgstr "画像をダウンロード中" + +msgid "Downloading original Discarts" +msgstr "公式レーベルをダウンロード中" + +msgid "Downloading pagelist:" +msgstr "リストをダウンロード中:" + +msgid "Dump NAND to EmuNand" +msgstr "NANDをエミュNANDへダンプ" + +msgid "During zoom" +msgstr "ズーム中" + +msgid "Dutch" +msgstr "オランダ語" + +msgid "ERROR" +msgstr "エラー" + +msgid "ERROR:" +msgstr "エラー:" + +msgid "ERROR: Can't set up theme." +msgstr "テーマを適用できませんでした" + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "エミュNANDチャンネル" + +msgid "Emulated Nand" +msgstr "エミュNAND" + +msgid "English" +msgstr "英語" + +msgid "Enter Path" +msgstr "パスを入力" + +msgid "Error" +msgstr "エラー" + +msgid "Error !" +msgstr "エラー!" + +#, c-format +msgid "Error creating path: %s" +msgstr "パスの作成エラー: %s" + +msgid "Error opening downloaded file" +msgstr "ダウンロードしたファイルを開けません" + +msgid "Error reading Disc" +msgstr "読み込みに失敗しました" + +msgid "Error reading disc" +msgstr "ディスク読み込みエラー" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "ダウンロードに失敗: %i" + +msgid "Error while downloding file" +msgstr "ダウンロードに失敗しました" + +msgid "Error while opening the zip." +msgstr "zipファイルを開けません" + +msgid "Error while transfering data." +msgstr "転送中にエラーが発生しました" + +msgid "Error while updating USB Loader GX." +msgstr "更新中にエラーが発生しました" + +msgid "Error writing the data." +msgstr "データの書き込み中にエラーが発生しました" + +msgid "Error:" +msgstr "エラー:" + +msgid "Error: Not enough space on SD." +msgstr "エラー:SDの空き容量が不足しています" + +msgid "Errors occured." +msgstr "エラーが発生しました" + +msgid "Everything" +msgstr "全て" + +msgid "Exit" +msgstr "終了" + +msgid "Exit to where?" +msgstr "どこに移動しますか?" + +msgid "Export All Saves to EmuNand" +msgstr "全てのセーブをエミュNANDに転送" + +msgid "Export Miis to EmuNand" +msgstr "MiiをエミュNANDに転送" + +msgid "Export SYSCONF to EmuNand" +msgstr "SYSCONFをエミュNANDに転送" + +msgid "Extract Miis to the Emu NAND?" +msgstr "エミュNANDにMiiを書き出しますか?" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "エミュNANDにSYSCONFを書き出しますか?" + +msgid "Extract Save to EmuNand" +msgstr "セーブをエミュNANDに書き出す" + +msgid "Extracting file:" +msgstr "書き出し中:" + +msgid "Extracting files..." +msgstr "解凍中です…" + +msgid "Extracting files:" +msgstr "書き出し中:" + +msgid "Extracting nand files:" +msgstr "NANDファイルを書き出し中:" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "失敗" + +msgid "Failed copying file" +msgstr "コピー失敗" + +msgid "Failed formating" +msgstr "初期化に失敗しました" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "全てのファイルを書き出せません。セーブがありません" + +msgid "Failed to extract." +msgstr "解凍に失敗しました" + +msgid "Failed to initialize the USB storage device." +msgstr "USBデバイスを初期化できませんでした" + +msgid "Failed to open partition" +msgstr "領域を開けませんでした" + +msgid "Failed to read ticket." +msgstr "チケットを読み込めません" + +msgid "Failed to read tmd file." +msgstr "TMDファイルを読み込めません" + +msgid "Failed to read wad header." +msgstr "WADヘッダを読み込めません" + +msgid "Failed updating" +msgstr "更新に失敗しました" + +msgid "Favorite Level" +msgstr "お気に入りレベル" + +msgid "Features" +msgstr "機能" + +msgid "Features Settings" +msgstr "機能設定" + +msgid "Feb" +msgstr "2月" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "ファイルが見つかりません" + +msgid "File read/write error." +msgstr "ファイルの読み書きエラー" + +msgid "Files extracted successfully." +msgstr "ファイルを書き出しました" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "ファイルサイズが%iバイトです" + +msgid "Filesize is 0 Byte." +msgstr "ファイルサイズが0バイトです" + +msgid "Flat Covers" +msgstr "正面カバー" + +msgid "Flip-X" +msgstr "ゲームリストの回転" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "文字サイズの補正率" + +msgid "Force 16:9" +msgstr "16:9に強制" + +msgid "Force 4:3" +msgstr "4:3に強制" + +msgid "Force NTSC" +msgstr "NTSCに強制" + +msgid "Force NTSC480p" +msgstr "NTSC480pに強制" + +msgid "Force PAL480p" +msgstr "PAL480pに強制" + +msgid "Force PAL50" +msgstr "PAL50に強制" + +msgid "Force PAL60" +msgstr "PAL60に強制" + +msgid "Force Titles from Disc" +msgstr "ディスク内のゲーム名に強制" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "初期化" + +msgid "Formatting, please wait..." +msgstr "初期化中です、お待ち下さい..." + +msgid "Found missing images." +msgstr "不足画像が見つかりました" + +msgid "Frame" +msgstr "フレーム" + +msgid "Frame Projection Height" +msgstr "フレーム角の高さ" + +msgid "Frame Projection Width" +msgstr "フレーム角の幅" + +msgid "Frame Projection X-Offset" +msgstr "フレーム角のXオフセット" + +msgid "Frame Projection Y-Offset" +msgstr "フレーム角のyオフセット" + +msgid "Frames" +msgstr "フレーム" + +msgid "Free Space" +msgstr "空き" + +msgid "French" +msgstr "フランス語" + +msgid "Full" +msgstr "フル" + +msgid "Full Cover Path" +msgstr "フルカバー" + +msgid "Full Covers" +msgstr "フルカバー" + +msgid "Full Menu" +msgstr "完全なメニュー" + +msgid "Full covers Download" +msgstr "フルカバーのダウンロード" + +msgid "Full shutdown" +msgstr "シャットダウン" + +msgid "GAMEID_Gamename" +msgstr "ゲームID_ゲーム名" + +msgid "GC Banner Scale" +msgstr "GCバナーの大きさ" + +msgid "GC Games" +msgstr "GCゲーム" + +msgid "GC Install 32K Aligned" +msgstr "GCインストール時に32K整列" + +msgid "GC Install Compressed" +msgstr "GCインストール時の圧縮" + +msgid "GCT Cheatcodes Path" +msgstr "GCTチート" + +msgid "GCT File created" +msgstr "GCTファイルを作成しました" + +msgid "GUI Settings" +msgstr "基本設定" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "GCゲームの削除" + +msgid "Game Cube Install Menu" +msgstr "GCインストールメニュー" + +msgid "Game ID" +msgstr "IDのみ" + +msgid "Game IOS" +msgstr "使用するIOS" + +msgid "Game Language" +msgstr "ゲームの言語" + +msgid "Game Load" +msgstr "ゲームの起動方法" + +msgid "Game Lock" +msgstr "ロック" + +msgid "Game Only" +msgstr "ゲームのみ" + +msgid "Game Region" +msgstr "リージョンのみ" + +msgid "Game Size" +msgstr "容量" + +msgid "Game Sound Mode" +msgstr "サウンドモード" + +msgid "Game Sound Volume" +msgstr "サウンドの音量" + +msgid "Game Split Size" +msgstr "ゲームの分割サイズ" + +msgid "Game Window Mode" +msgstr "ゲームウインドウ表示" + +msgid "Game is already installed:" +msgstr "このゲームは既にインストールされています:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "ゲームのインストール領域" + +msgid "GameCube" +msgstr "ゲームキューブ" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "GCモード" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "ゲーム名 [ゲームID]" + +msgid "Games" +msgstr "ゲーム" + +msgid "Generating GXGameCategories.xml" +msgstr "GXGameCategories.xmlを作成中です" + +msgid "Genre:" +msgstr "ジャンル:" + +msgid "German" +msgstr "ドイツ語" + +msgid "Getting file list..." +msgstr "ファイルリストを取得中..." + +msgid "Getting game folder size..." +msgstr "フォルダサイズを取得中..." + +msgid "Global Settings" +msgstr "基本設定" + +msgid "Grid Scroll Speed" +msgstr "グリッドスクロール速度" + +msgid "HOME Menu" +msgstr "HOMEボタンメニュー" + +msgid "Hard Drive Settings" +msgstr "HDD設定" + +msgid "High Quality" +msgstr "高品質" + +msgid "High/Low" +msgstr "高/低" + +msgid "Homebrew Apps Path" +msgstr "Homebrewアプリ" + +msgid "Homebrew Channel" +msgstr "HBCへ" + +msgid "Homebrew Launcher" +msgstr "Homebrewランチャー" + +msgid "Hooktype" +msgstr "フックタイプ" + +msgid "Hour" +msgstr "時間" + +msgid "How do you want to update?" +msgstr "更新方法の選択" + +msgid "How to Shutdown?" +msgstr "終了方法の選択" + +msgid "Import Categories" +msgstr "カテゴリをインポート" + +msgid "Import operation successfully completed." +msgstr "インポートに成功しました" + +msgid "Importing categories" +msgstr "カテゴリをインポート中です" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "ファイルを受信中 %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "ファイルを受信中 %0.2fMB" + +msgid "Individual" +msgstr "個別" + +msgid "Initializing Network" +msgstr "接続中・・・" + +msgid "Insert Disk" +msgstr "ディスクを入れてください" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "ゲームディスクを入れてください!" + +msgid "Install" +msgstr "インストール" + +msgid "Install Canceled" +msgstr "インストールを中止しました" + +msgid "Install Directories" +msgstr "インストールフォルダ" + +msgid "Install Error!" +msgstr "インストールエラー!" + +msgid "Install Partitions" +msgstr "インストール領域" + +msgid "Install a game" +msgstr "ゲームをインストール" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "インストールが終了しました" + +msgid "Installing Game Cube Game..." +msgstr "GCゲームをインストール中..." + +msgid "Installing content" +msgstr "コンテンツをインストール中" + +msgid "Installing game:" +msgstr "ゲームをインストール中:" + +msgid "Installing title..." +msgstr "タイトルをインストール中..." + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "不正なIOS番号です。200-255までの番号を入力してください" + +msgid "Invalid wad file." +msgstr "不正なWADファイルです" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "この情報は開発者までお知らせください" + +msgid "Italian" +msgstr "イタリア語" + +msgid "Jan" +msgstr "1月" + +msgid "Japanese" +msgstr "日本語" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "7月" + +msgid "June" +msgstr "6月" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "キーボードのタイプ" + +msgid "Korean" +msgstr "韓国語" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "言語ファイル" + +msgid "Language change:" +msgstr "言語の変更" + +msgid "Languagefiles Path" +msgstr "言語ファイル" + +msgid "Languagepath changed." +msgstr "言語のパスを変更しました" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "エミュNANDチャンネルはd2x cIOSでないと動作しません!IOSをd2x cIOSに変更してください" + +msgid "Left" +msgstr "左ボタンで" + +msgid "Like SysMenu" +msgstr "Wiiメニュー風" + +msgid "List on Gamelaunch" +msgstr "ゲーム起動時にリスト" + +msgid "Load" +msgstr "はじめる" + +msgid "Load From SD/USB" +msgstr "SD/USBからロード" + +#, c-format +msgid "Load file from: %s ?" +msgstr "%sからファイルをロードしますか?" + +msgid "Load this DOL as alternate DOL?" +msgstr "このDOLを代替DOLとしてロードしますか?" + +msgid "Loader Settings" +msgstr "ローダーの設定" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "標準の言語に変更しますか" + +msgid "Loading standard music." +msgstr "初期設定に戻しますか" + +msgid "Lock Console" +msgstr "GXをロック" + +msgid "Lock USB Loader GX" +msgstr "ロックする" + +msgid "Locked" +msgstr "ロック中" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "フォルダ内でループ" + +msgid "Loop Music" +msgstr "ループさせる" + +msgid "Loop Sound" +msgstr "ループさせる" + +msgid "Low Quality" +msgstr "低品質" + +msgid "Low/High" +msgstr "低/高" + +msgid "MIOS (Default & Customs)" +msgstr "MIOS(公式&カスタム)" + +msgid "Main DOL" +msgstr "main.dol" + +msgid "Main GameCube Games Path" +msgstr "GCゲーム(メイン)" + +msgid "Main GameCube Path" +msgstr "ゲームキューブ" + +msgid "Main Path" +msgstr "メインパス" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "3月" + +msgid "Mark new games" +msgstr "Newマークの表示機能" + +msgid "May" +msgstr "5月" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "Wii伝言板の更新" + +msgid "Motion+ Video" +msgstr "モーション+説明ムービー" + +msgid "Mount DVD drive" +msgstr "DVDを起動" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "マルチ領域" + +msgid "Music Loop Mode" +msgstr "ループ機能" + +msgid "Music Volume" +msgstr "BGMの音量" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "NANDチャンネルエミュ" + +msgid "Nand Channels" +msgstr "Wii本体NANDチャンネル" + +msgid "Nand Emu Channel Path" +msgstr "NANDエミュチャンネル" + +msgid "Nand Emu Path" +msgstr "NANDエミュ" + +msgid "Nand Emulation" +msgstr "NANDエミュ" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "NANDエミュはd2x cIOSのみで動作します!" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "NANDエミュはFAT/FAT32領域のみで動作します!" + +msgid "Nand Saves Emulation" +msgstr "NANDセーブエミュ" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "非表示" + +msgid "Network is not initiated." +msgstr "ネットワークに接続されていません" + +msgid "Next" +msgstr "右" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "いいえ" + +msgid "No Cheatfile found" +msgstr "チートファイルが見つかりません" + +msgid "No DOL file found on disc." +msgstr "ディスク内に.DOLがありません" + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "分割しない" + +msgid "No URL or Path specified." +msgstr "URLかパスが指定されていません" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "使用できる領域が見つかりません" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "Wiinnertag.xmlが設定パスにみつかりません。テンプレファイルを作成しますか?" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "何も選ばれていません!(GCTファイルが削除された?)" + +msgid "No data could be read." +msgstr "読み込みに失敗しました" + +msgid "No disc inserted." +msgstr "ディスクが挿入されていません" + +msgid "No favorites selected." +msgstr "お気に入りはありません" + +msgid "No file missing!" +msgstr "必要ありません" + +msgid "No games found on the disc" +msgstr "ディスクにゲームが見つかりません" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "更新する言語ファイルがありません!新しい言語ファイルをダウンロードしますか?" + +msgid "No new updates." +msgstr "更新はありません" + +msgid "No themes found on the site." +msgstr "テーマが見つかりません" + +msgid "No themes found." +msgstr "テーマが見つかりません" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "なし" + +msgid "Normal" +msgstr "ワイド" + +msgid "Not Initialized" +msgstr "初期化されていません" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "ゲームディスクではありません" + +msgid "Not a valid URL" +msgstr "無効なURLです" + +msgid "Not a valid URL path" +msgstr "無効なパスです" + +msgid "Not a valid domain" +msgstr "無効なドメインです" + +msgid "Not enough free memory." +msgstr "空メモリが不足しています" + +msgid "Not enough free space on device." +msgstr "デバイスの空き容量が足りません" + +msgid "Not enough free space!" +msgstr "空き容量が不足しています!" + +msgid "Not enough memory for FST." +msgstr "FST用メモリが足りません" + +msgid "Not enough memory." +msgstr "メモリが足りません" + +msgid "Not required" +msgstr "必要なし" + +msgid "Not supported format!" +msgstr "対応していない形式です!" + +msgid "Nothing selected to delete." +msgstr "何も選ばれていません" + +msgid "Nothing selected to install." +msgstr "何も選ばれていません" + +msgid "Nov" +msgstr "11月" + +msgid "OFF" +msgstr "使わない" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "使う" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "改造コード" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "10月" + +msgid "Official Site:" +msgstr "公式サイト:" + +msgid "Offset" +msgstr "代替" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "ゲーム領域のみ" + +msgid "Only for Install" +msgstr "インストール中のみ" + +msgid "Original" +msgstr "公式" + +msgid "Original/Customs" +msgstr "公式を優先" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "使用制限の設定" + +msgid "Partial" +msgstr "部分的" + +msgid "Partition" +msgstr "使用する領域" + +msgid "Password" +msgstr "暗証番号" + +msgid "Password Changed" +msgstr "暗証番号の変更" + +msgid "Password has been changed" +msgstr "暗証番号を変更しました" + +msgid "Patch Country Strings" +msgstr "国コードパッチ" + +msgid "Path Changed" +msgstr "パスが変更されました" + +msgid "Permission denied." +msgstr "権限がありません" + +msgid "Pick from a list" +msgstr "リストから選択" + +msgid "Pixels" +msgstr "ピクセル" + +msgid "Play Count" +msgstr "プレイ回数" + +msgid "Play Next" +msgstr "次へ" + +msgid "Play Once" +msgstr "一度だけ再生" + +msgid "Play Previous" +msgstr "前へ" + +msgid "Playing Music:" +msgstr "再生中" + +msgid "Please wait" +msgstr "お待ちください" + +msgid "Please wait..." +msgstr "しばらくお待ちください" + +msgid "Power off the Wii" +msgstr "Wiiの電源を切る" + +msgid "Prev" +msgstr "左" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "プロセスが終了しました" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "ウインドウサイズ" + +msgid "Published by" +msgstr "発売元:" + +msgid "Quick Boot" +msgstr "クイック起動" + +msgid "Random Directory Music" +msgstr "フォルダ内でランダム再生" + +msgid "Real Nand" +msgstr "Wii本体NAND" + +msgid "Receiving file from:" +msgstr "ファイルを受信中:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "リージョンパッチ" + +msgid "Released" +msgstr "発売日" + +msgid "Reload SD" +msgstr "SDを再読み込み" + +msgid "Reloading game list now, please wait..." +msgstr "ゲームリストを再読み込み中、お待ちください..." + +msgid "Remember Unlock" +msgstr "ロック解除を記憶" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "更新を取り除く" + +msgid "Rename Game Title" +msgstr "ゲーム名を変更" + +msgid "Rename category" +msgstr "カテゴリの名前を変更" + +msgid "Reset" +msgstr "リセット" + +msgid "Reset BG Music" +msgstr "BGMをリセット" + +msgid "Reset Playcounter" +msgstr "プレイ回数をリセット" + +msgid "Reset to default BGM?" +msgstr "BGMを初期状態に戻しますか?" + +msgid "Restarting..." +msgstr "再起動します" + +msgid "Return" +msgstr "もどる" + +msgid "Return To" +msgstr "戻り先" + +msgid "Return to Wii Menu" +msgstr "Wiiメニューへもどる" + +msgid "Right" +msgstr "右ボタンで" + +msgid "Rotating Disc" +msgstr "ディスク回転" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "振動機能" + +msgid "SChinese" +msgstr "簡体中国語" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "SDカードにアクセス出来ません" + +msgid "SD GameCube Games Path" +msgstr "SD GCゲーム" + +msgid "SD GameCube Path" +msgstr "SD ゲームキューブ" + +msgid "SD Path" +msgstr "SD パス" + +msgid "SFX Volume" +msgstr "効果音の音量" + +msgid "Save" +msgstr "保存" + +msgid "Save Failed. No device inserted?" +msgstr "保存に失敗しました" + +msgid "Save Game List to" +msgstr "リストを保存しますか" + +msgid "Save List" +msgstr "リスト" + +msgid "Saved" +msgstr "保存しました" + +msgid "Savegame might not exist for this game." +msgstr "このゲームのセーブはありません" + +msgid "Screensaver" +msgstr "スクリーンセーバー" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "選択" + +msgid "Select DOL Offset" +msgstr "代替DOLの選択" + +msgid "Select a DOL" +msgstr "DOLを選択" + +msgid "Select a DOL from Game" +msgstr "ゲームからDOLを選択" + +msgid "Select game categories" +msgstr "ゲームカテゴリを選択" + +msgid "Select loader mode" +msgstr "ローダーモードを選択" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "タイトルの読み込み元を選んでください" + +msgid "Sept" +msgstr "9月" + +msgid "Set Search-Filter" +msgstr "検索" + +msgid "Settings" +msgstr "設定" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "カテゴリを表示" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "空き容量の表示" + +msgid "Show Play Count" +msgstr "プレイ回数の表示" + +msgid "Show SD" +msgstr "SDを表示" + +msgid "Shutdown System" +msgstr "シャットダウン" + +msgid "Shutdown Wii" +msgstr "シャットダウン" + +msgid "Skip Errors" +msgstr "エラーをスキップ" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "SNEEK映像パッチ" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "名前順に並び替え" + +msgid "Sort by number of players" +msgstr "プレイヤー数順に並び替え" + +msgid "Sort by rank" +msgstr "ランク順に並び替え" + +msgid "Sort order by most played" +msgstr "プレイ回数が多い順に並び替え" + +msgid "Sound" +msgstr "サウンド" + +msgid "Sound Settings" +msgstr "サウンド設定" + +msgid "Sound+BGM" +msgstr "サウンドとBGM" + +msgid "Sound+Quiet" +msgstr "サウンドのみ" + +msgid "Spanish" +msgstr "スペイン語" + +msgid "Special thanks to:" +msgstr "スペシャルサンクス:" + +msgid "Split each 2GB" +msgstr "2GBごとに分割" + +msgid "Split each 4GB" +msgstr "4GBごとに分割" + +msgid "Standby" +msgstr "スタンバイ" + +msgid "Start" +msgstr "はじめる" + +msgid "Success" +msgstr "成功" + +msgid "Success." +msgstr "成功しました" + +msgid "Success:" +msgstr "成功:" + +msgid "Successfully Saved" +msgstr "保存に成功しました" + +msgid "Successfully Updated" +msgstr "更新しました" + +msgid "Successfully copied" +msgstr "コピーしました" + +msgid "Successfully deleted:" +msgstr "削除に成功しました" + +msgid "Successfully extracted theme." +msgstr "テーマの解凍を完了しました." + +msgid "Successfully installed:" +msgstr "このゲームをインストールしました" + +msgid "Successfully updated." +msgstr "更新しました" + +msgid "Switching to channel list mode." +msgstr "チャンネルリストモードに変更します" + +msgid "Sync FAT32 FS Info" +msgstr "FAT32FS情報を同期" + +msgid "Synchronizing..." +msgstr "同期中です..." + +msgid "System Default" +msgstr "Wiiの初期値" + +msgid "TChinese" +msgstr "繁体中国語" + +msgid "TXT Cheatcodes Path" +msgstr "テキストチート" + +msgid "The .them file was not found in the zip." +msgstr ".themファイルがzip内にありません" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "MiiはエミュNAND(チャンネル)パスに書き出されます。すでに存在するファイルは上書きされます" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "SYSCONFはエミュNAND(チャンネル)パスに書き出されます。すでに存在するファイルは上書きされます" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "SDカードにアクセスしているとアプリがクラッシュします!" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "フォルダがありません。作成しますか?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "ファイルはエミュNANDセーブ&チャンネルパスに書き出されます。すでに存在するファイルは上書きされます" + +msgid "The game is on SD Card." +msgstr "ゲームはSDカードにあります" + +msgid "The game is on USB." +msgstr "ゲームはUSBにあります" + +msgid "The save game will be extracted to your emu nand path." +msgstr "セーブデータはエミュNANDパスに書き出されます" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "セーブはエミュNANDセーブ&チャンネルパスに書き出されます。すでに存在するファイルは上書きされます" + +msgid "The wad file was installed" +msgstr "wadがインストールされました" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "WADのインストールはエラー%iで失敗しました" + +msgid "Theme Downloader" +msgstr "テーマをダウンロード" + +msgid "Theme Menu" +msgstr "テーマ" + +msgid "Theme Path" +msgstr "テーマ" + +msgid "Theme Title:" +msgstr "テーマ名:" + +msgid "Themes by www.spiffy360.com" +msgstr "テーマ…www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "このIOSはBootMiiのIOSです" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "このIOSはタイトルリストにありませんでした" + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "このパスはSDにないといけません!" + +msgid "Time left:" +msgstr "残り時間:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "ランチャー" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "ゲーム名の日本語化" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "GCゲームをディスク起動するには設定でGCモードをMIOSにしてください" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "ヒントバルーンの遅延" + +msgid "Tooltips" +msgstr "ヒントバルーン" + +msgid "Transfer failed" +msgstr "転送に失敗しました" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "GXは保護されています" + +msgid "USB Port" +msgstr "USBポート" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "USBポートの切替機能は、Hermes cIOS使用時のみ有効です。" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "アンインストール" + +msgid "Uninstall Game" +msgstr "ゲームをアンインストール" + +msgid "Uninstall Menu" +msgstr "アンインストール" + +msgid "Uninstall all" +msgstr "全てアンインストール" + +msgid "Unknown" +msgstr "不明" + +msgid "Unlock USB Loader GX" +msgstr "ロックを解除" + +msgid "Unlocked" +msgstr "ロック無し" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "非対応の形式なのでTempTheme.zipを自己解凍してください" + +msgid "Update" +msgstr "更新" + +msgid "Update All" +msgstr "全て" + +msgid "Update DOL" +msgstr "DOLのみ" + +msgid "Update Files" +msgstr "すべて更新" + +msgid "Update Path" +msgstr "GXのdol" + +msgid "Update all Language Files" +msgstr "全言語ファイルを更新" + +msgid "Update failed" +msgstr "更新に失敗しました" + +msgid "Update successfull" +msgstr "更新しました" + +msgid "Updating Language Files:" +msgstr "言語ファイルを更新中:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "インストール済みディレクトリにZIPを転送しました" + +msgid "Use System Font" +msgstr "システムフォントを使う" + +msgid "Use global" +msgstr "基本設定を使う" + +msgid "VBI (Default)" +msgstr "VBI(デフォルト)" + +msgid "VIDTV Patch" +msgstr "映像パッチ" + +msgid "Version:" +msgstr "バージョン:" + +#, c-format +msgid "Version: %s" +msgstr "バージョン: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "映像の出力方法" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "ポインタの速度" + +msgid "WDM Files Path" +msgstr "WDMファイル" + +msgid "WIP Patches Path" +msgstr "WIPパッチ" + +msgid "Waiting..." +msgstr "待機中…" + +msgid "Warning" +msgstr "警告" + +msgid "Warning:" +msgstr "警告:" + +msgid "What do you want to do?" +msgstr "何をしますか?" + +msgid "What do you want to update?" +msgstr "更新の選択" + +msgid "What should be deleted for this game title:" +msgstr "このゲームの何を削除しますか:" + +msgid "What to extract from NAND?" +msgstr "何をNANDから書き出しますか?" + +msgid "Where should the game be installed to?" +msgstr "どこにインストールしますか?" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "ネットワーク対応" + +msgid "Widescreen Factor" +msgstr "ワイド画面の補正率" + +msgid "Widescreen Fix" +msgstr "普通" + +msgid "Wii Games" +msgstr "Wiiゲーム" + +msgid "Wii Menu" +msgstr "Wiiメニューへ" + +msgid "Wii Settings" +msgstr "データ管理" + +msgid "WiiTDB.xml" +msgstr "ゲーム名リスト" + +msgid "WiiTDB.xml is up to date." +msgstr "ゲーム名リストが更新されました" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "スロット点灯機能" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "Wiinnertag.xmlのパス" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Wiinnertagは自動ネット接続が有効になっている必要が有ります。有効にしますか?" + +msgid "Wiird Debugger" +msgstr "WiiRDデバッガ" + +#, c-format +msgid "Write error on file: %s" +msgstr "書き込みエラー: %s" + +msgid "Writing GXGameCategories.xml" +msgstr "GXGameCategories.xmlを書き込み中です" + +msgid "Wrong Password" +msgstr "暗証番号が違います" + +msgid "Yes" +msgstr "はい" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "rev17以前のcIOS249ではFAT32/NTFS/EXTに対応していません" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "領域を選択・初期化したりチャンネルリストモードを使えます" + +msgid "You cannot delete this category." +msgstr "このカテゴリは削除できません" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "DIOS MIOS Lite v1.2以降をインストールする必要があります" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "ズームの継続(速度)" + +msgid "and translators for language files updates" +msgstr "/ K-M & Trickart …日本語化" + +msgid "available" +msgstr "があります" + +msgid "does not exist!" +msgstr "存在しません!" + +msgid "does not exist! Loading game without cheats." +msgstr "存在しないので チートなしで起動します" + +msgid "files left" +msgstr "個で完了" + +msgid "for FAT/NTFS support" +msgstr "…FATとNTFSへの対応" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "GameTDB…カバー・ディスク画像の保管" + +msgid "for Ocarina" +msgstr "…Ocarinaを制作" + +msgid "for diverse patches" +msgstr "…様々なパッチを制作" + +msgid "for his awesome tool LibWiiGui" +msgstr "…LibWiiGuiを制作" + +msgid "for hosting the themes" +msgstr "…テーマを配布" + +msgid "for the USB Loader source" +msgstr "…ソースを制作" + +msgid "for their work on the wiki page" +msgstr "…wikiページでの編集作業" + +msgid "formatted!" +msgstr "初期化を完了しました!" + +msgid "free" +msgstr "空き" + +msgid "ms" +msgstr "ミリ秒" + +msgid "not set" +msgstr "セットされていません" + +msgid "of" +msgstr "中" + +msgid "seconds left" +msgstr "秒で完了" + +#~ msgid "Install WAD to EmuNand" +#~ msgstr "WADをエミュNANDへインストール" + +#~ msgid "WAD Installation" +#~ msgstr "WADインストール" + +#~ msgid "GameTDB Path" +#~ msgstr "ゲーム名リスト" + +#~ msgid "Anti" +#~ msgstr "アンチ" + +#~ msgid "Error 002 fix" +#~ msgstr "Error002対策" + +#~ msgid "Use Game Settings" +#~ msgstr "ゲーム設定を使う" + +#~ msgid "Main tester:" +#~ msgstr "メインテスター:" + +#~ msgid "USB Device not found." +#~ msgstr "USB機器が見つかりません" + +#~ msgid "Boot/Standard" +#~ msgstr "使用するcIOS" + +#~ msgid "DEVO MemCard Emulation" +#~ msgstr "DEVOメモカエミュ" + +#~ msgid "DML Auto" +#~ msgstr "DML 自動" + +#~ msgid "DML Debug" +#~ msgstr "DML デバッグ" + +#~ msgid "DML Force Widescreen" +#~ msgstr "DML 強制ワイド化" + +#~ msgid "DML Japanese Patch" +#~ msgstr "DML 日本向けパッチ" + +#~ msgid "DML LED Activity" +#~ msgstr "DML LED点灯" + +#~ msgid "DML NMM Mode" +#~ msgstr "DML NMM" + +#~ msgid "DML No Disc+" +#~ msgstr "DML ディスクなし+" + +#~ msgid "DML None" +#~ msgstr "DML なし" + +#~ msgid "DML PAD Hook" +#~ msgstr "DML PADフック" + +#~ msgid "DML Progressive Patch" +#~ msgstr "DML プログレッシブパッチ" + +#~ msgid "DML Video Mode" +#~ msgstr "DML 映像モード" + +#~ msgid "To run GameCube games with DIOS MIOS you need to place them on an USB FAT32 partition." +#~ msgstr "GCゲームをDIOS MIOSで起動するにはUSBをFAt32にしてゲームをおいてください" + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' to an USB FAT32 partition." +#~ msgstr "GCゲームをDIOS MIOSで起動するにはパスの設定でゲームキューブをusb:/にする必要があります" + +#~ msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Path." +#~ msgstr "GCゲームをDevolutionで起動するにはloader.binがDevolutionのパスにある必要があります" + +#~ msgid "You need to install Devolution or DIOS MIOS (Lite) to launch GameCube games from USB or SD card" +#~ msgstr "GCゲームをSDやUSB機器から起動するにはDevolutionかDIOS MIOS (Lite)をインストールしてください" + +#~ msgid "DML No Disc" +#~ msgstr "DML ディスクなし" + +#~ msgid "The No Disc setting is not used anymore by DIOS MIOS (Lite). Now you need to place a disc in your drive." +#~ msgstr "ディスクなし設定はDIOS MIOS(Lite)では使われていません。ドライブにディスクを入れてください" + +#~ msgid "The Force Widescreen setting requires DIOS MIOS v2.2 or more. This setting will be ignored." +#~ msgstr "強制ワイド化設定はDIOS MIOS v2.2以降が必要です。この設定は無視されます" + +#~ msgid "The GCT Cheatcodes Path and this game are not on the same partition. Run the game without Ocarina?" +#~ msgstr "GCTコードとこのゲームは同じ領域にありません。チートなしで起動しますか?" + +#~ msgid "The GCT Cheatcodes Path must be on SD card. Run the game without Ocarina?" +#~ msgstr "GCTコードのパスはSDカードにないといけません。チートなしで起動しますか?" + +#~ msgid "Custom Discarts" +#~ msgstr "カスタムレーベル" + +#~ msgid "DML Installed Version" +#~ msgstr "DMLのバージョン" + +#~ msgid "Full HQ Covers" +#~ msgstr "フルカバー(精細)" + +#~ msgid "Full LQ Covers" +#~ msgstr "フルカバー(普通)" + +#~ msgid "Original Discarts" +#~ msgstr "公式レーベル" + +#~ msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2 or a newer version. This setting will be ignored." +#~ msgstr "ディスクなし+機能はDIOS MIOS 2.2 update2以降が必要です。この設定は無視されます" + +#~ msgid "You need to install DIOS MIOS to run GameCube games from USB or DIOS MIOS Lite to run them from SD card" +#~ msgstr "GCゲームをUSBから起動するにはDIOS MIOSが、SDから起動するにはDMLが必要です" + +#~ msgid "v1.2 -> v2.1" +#~ msgstr "v1.2 ~ v2.1" + +#~ msgid "v2.2+" +#~ msgstr "v2.2以降" + +#~ msgid "GC Force Interlace" +#~ msgstr "GC インターレース強制" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "WBFS内のゲーム名を変更" + +#~ msgid "Do you want to discart changes?" +#~ msgstr "変更を破棄しますか?" + +#~ msgid "Successfully Updated thanks to www.techjawa.com" +#~ msgstr "更新しました www.techjawa.comに感謝!" + +#~ msgid "Beginning" +#~ msgstr "前方一致" + +#~ msgid "Content" +#~ msgstr "含む" + +#~ msgid "Loader Mode" +#~ msgstr "ローダーモード" + +#~ msgid "Search Mode" +#~ msgstr "検索方法" + +#~ msgid "for hosting the update files" +#~ msgstr "…更新ファイルを配布" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Wiiディスクを入れて下さい!" + +#~ msgid "Issue manager /" +#~ msgstr "問題管理者 /" + +#~ msgid "No cheats were selected" +#~ msgstr "何も選ばれていません" + +#~ msgid "Not a Wii Disc" +#~ msgstr "Wiiディスクではありません" + +#~ msgid "The files will be extracted to your emu nand path. Attention: All existing files will be overwritten." +#~ msgstr "ファイルはエミュNANDパスに書き出されます 注意:すでにあるファイルは上書きされます" + +#~ msgid "The save games will be extracted to your emu nand path. Attention: All existing saves will be overwritten." +#~ msgstr "セーブデータはエミュNANDパスに書き出されます 注意:すでにあるセーブは上書きされます" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> チケットを削除します" + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> チケットを削除 … 失敗!" + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> チケットを削除 … 成功!" + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> タイトルを削除 … 失敗!" + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> タイトルを削除 … 成功!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> タイトルコンテンツを削除します" + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> タイトルコンテンツを削除 … 失敗!" + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> タイトルコンテンツを削除 … 成功!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> タイトルを削除します" + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> インストールを終了します" + +#~ msgid ">> Installing content #" +#~ msgstr "インストール コンテンツ #" + +#~ msgid ">> Installing ticket..." +#~ msgstr "チケットをインストール中 …" + +#~ msgid ">> Installing title..." +#~ msgstr "タイトルをインストール中 …" + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> WADデータを読込み中 …" + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> WADデータの読込 … 失敗!" + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> WADデータの読込 … 成功!" + +#~ msgid "Done!" +#~ msgstr "完了!" + +#~ msgid "Error..." +#~ msgstr "エラー…" + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "インストールの完了...完了しました" + +#~ msgid "Installing content... Ok!" +#~ msgstr "コンテンツをインストール...成功!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "チケットをインストール...成功!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "タイトルをインストール...成功!" + +#~ msgid "Installing wad" +#~ msgstr "WADをインストールします" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "WADデータの読み込み...成功!" + +#~ msgid "Uninstalling wad" +#~ msgstr "WADをアンインストール" + +#~ msgid "The game installation is disabled under this IOS because of instability in usb write." +#~ msgstr "このIOSでのゲームの追加は不安定なため無効になっています" + +#~ msgid "You are currently using IOS" +#~ msgstr "使用中のIOS:IOS" + +#~ msgid "Nand Channel Emulation" +#~ msgstr "NANDチャンネルエミュ" + +#~ msgid "New Disc Detected" +#~ msgstr "新しいディスクが検出されました" + +#~ msgid "USB Device not found" +#~ msgstr "USB機器が見つかりません" + +#~ msgid "You need to select or format a partition" +#~ msgstr "領域を選択するか初期化してください" + +#~ msgid "GameTDB Files" +#~ msgstr "ゲーム名リスト" + +#~ msgid "GameTDB is up to date." +#~ msgstr "ゲーム名リストが更新されました" + +#~ msgid "Language File" +#~ msgstr "言語ファイル" + +#~ msgid "Are you sure you want to import game categories from WiiTDB?" +#~ msgstr "WiiTDBからカテゴリをインポートしますか?" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "ゲーム名の日本語化" + +#~ msgid "WiiTDB Files" +#~ msgstr "ゲーム名リスト" + +#~ msgid "WiiTDB Path" +#~ msgstr "ゲーム名リスト" + +#~ msgid "WiiTDB is up to date." +#~ msgstr "WiiTDBが更新されました" + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "WiiTDB…様々な画像を配布" diff --git a/Languages/korean.lang b/Languages/korean.lang new file mode 100644 index 0000000..df8267b --- /dev/null +++ b/Languages/korean.lang @@ -0,0 +1,2496 @@ +# USB Loader GX language source file. +# korean.lang - r1268 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-12-14 15:50+0100\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " 는(은) 다운로드 할 수 없습니다." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " 이(가) 저장되었습니다. 텍스트가 확인되지 않았습니다. 일부 코드는 서로 올바르게 작동하지 않을 수 있습니다. 문제가 발생하여 자세한 내용을 보려면 실제 문서 편집기에서 텍스트를 여십시오." + +msgid " is not on the server." +msgstr " 는(은) 서버에 없습니다." + +#, c-format +msgid "%i files not found on the server!" +msgstr "%i 파일이 서버에 없습니다!" + +#, c-format +msgid "%i missing files" +msgstr "%i 파일 누락" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "%i wad 파일을 처리하지 못했습니다!" + +#, c-format +msgid "%i wad found." +msgstr "%i wad 찾았습니다." + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "%s 는(은) ISO 포맷의 게임큐브 백업만 허용합니다." + +#, c-format +msgid "%s 는(은) AHB 액세스가 필요합니다! 홈브류 채널 또는 업데이트 된 채널 또는 포워더에서 USBLoaderGX를 시작하십시오." +msgstr "" + +msgid "--== Devolution" +msgstr "--== 데볼류션" + +msgid "--== Nintendont" +msgstr "--== 닌텐돈트" + +msgid "--== DIOS MIOS (Lite) " +msgstr "--== DIOS MIOS (라이트) " + +msgid "--== DM(L) + Nintendont" +msgstr "--== DM(L) + 닌텐돈트" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (모든 연령)" + +msgid "1 (Child 7+)" +msgstr "1 (7세 이상)" + +msgid "1 hour" +msgstr "1 시간" + +msgid "10 min" +msgstr "10 분" + +msgid "2 (Teen 12+)" +msgstr "2 (12세 이상)" + +msgid "20 min" +msgstr "20 분" + +msgid "2D Cover Path" +msgstr "2D 커버 경로" + +msgid "3 (Mature 16+)" +msgstr "3 (16세 이상)" + +msgid "3 min" +msgstr "3 분" + +msgid "30 min" +msgstr "30 분" + +msgid "3D Cover Path" +msgstr "3D 커버 경로" + +msgid "3D Covers" +msgstr "3D 커버" + +msgid "4 (Adults Only 18+)" +msgstr "4 (18세 이상)" + +msgid "5 min" +msgstr "5 분" + +msgid "=== GameCube Settings" +msgstr "=== 게임큐브 설정" + +msgid "AUTO" +msgstr "자동" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "카테고리 추가" + +msgid "Adjust Overscan X" +msgstr "오버스캔 X 조정" + +msgid "Adjust Overscan Y" +msgstr "오버스캔 Y 조정" + +msgid "After zoom" +msgstr "확대/축소 후" + +msgid "All" +msgstr "모두" + +msgid "All Partitions" +msgstr "모든 파티션" + +msgid "All files extracted." +msgstr "모든 파일이 추출되었습니다." + +msgid "All images downloaded successfully." +msgstr "모든 이미지가 성공적으로 다운로드되었습니다." + +msgid "All the features of USB Loader GX are unlocked." +msgstr "USB Loader GX의 모든 기능이 잠금 해제됩니다." + +msgid "All wad files processed successfully." +msgstr "모든 wad 파일이 성공적으로 처리되었습니다" + +msgid "Alternate DOL" +msgstr "대체 DOL" + +msgid "An example file was created here:" +msgstr "여기에 예제 파일이 생성되었습니다:" + +msgid "Animation Start" +msgstr "애니메이션 시작" + +msgid "App Language" +msgstr "응용 프로그램 언어" + +msgid "Apply" +msgstr "적용" + +msgid "Apr" +msgstr "4월" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "SD 카드에서 선택한 게임을 모두 삭제 하시겠습니까?" + +msgid "Are you sure you want to delete this category?" +msgstr "이 카테고리를 삭제 하시겠습니까?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "GameTDB에서 게임 카테고리를 가져 오시겠습니까?" + +msgid "Are you sure you want to install on SD?" +msgstr "SD에 설치 하시겠습니까?" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "USB Loader GX를 잠그시겠습니까?" + +msgid "Are you sure you want to remount SD?" +msgstr "SD를 다시 마운트 하시겠습니까?" + +msgid "Are you sure you want to reset?" +msgstr "리셋 하시겠습니까?" + +msgid "Are you sure?" +msgstr "확실합니까?" + +msgid "Aspect Ratio" +msgstr "화면 비율" + +msgid "Attention!" +msgstr "주의!" + +msgid "Attention: All savegames will be deleted." +msgstr "주의: 모든 저장게임이 삭제됩니다." + +msgid "Aug" +msgstr "8월" + +msgid "Author(s):" +msgstr "제작자" + +msgid "Auto" +msgstr "자동" + +msgid "Auto Boot" +msgstr "자동 부팅" + +msgid "AutoInit Network" +msgstr "자동초기화 네트워크" + +msgid "BCA Codes Path" +msgstr "BCA 코드 경로" + +msgid "Back" +msgstr "뒤로" + +msgid "Back to HBC or Wii Menu" +msgstr "홈브류 채널 또는 Wii 메뉴로 돌아가기" + +msgid "Backgroundmusic" +msgstr "" + +msgid "Banner Animation" +msgstr "배너 애니메이션" + +msgid "Banner Animation Settings" +msgstr "배너 애니메이션 설정" + +msgid "Banner On Channels" +msgstr "채널 배너" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "배너 그리드 레이아웃은 AHBPROT에서만 가능합니다! 새로운 홈브류 채널 버전을 설치하세요." + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "배너 창은 AHBPROT에서만 사용할 수 있습니다! 새로운 홈브류 채널 버전을 설치하세요." + +msgid "Big thanks to:" +msgstr "큰 감사:" + +msgid "Block Categories Menu" +msgstr "카테고리 메뉴 차단" + +msgid "Block Categories Modify" +msgstr "카테고리 수정 차단" + +msgid "Block Cover Downloads" +msgstr "커버 다운로드 차단" + +msgid "Block Custom Paths" +msgstr "사용자 정의 경로 차단" + +msgid "Block Feature Settings" +msgstr "기능 설정 차단" + +msgid "Block Game Install" +msgstr "게임 설치 차단" + +msgid "Block Game Settings" +msgstr "게임 설정 차단" + +msgid "Block GameID Change" +msgstr "GameID 변경 차단" + +msgid "Block Global Settings" +msgstr "글로벌 설정 차단" + +msgid "Block Gui Settings" +msgstr "Gui 설정 차단" + +msgid "Block HBC Menu" +msgstr "홈브류 채널 메뉴 차단" + +msgid "Block Hard Drive Settings" +msgstr "하드 드라이브 설정 차단" + +msgid "Block IOS Reload" +msgstr "IOS Reload 차딘" + +msgid "Block Loader Layout Button" +msgstr "로더 레이아웃 버튼 차단" + +msgid "Block Loader Mode Button" +msgstr "로더 모드 버튼 차단" + +msgid "Block Loader Settings" +msgstr "로더 설정 차단" + +msgid "Block Parental Settings" +msgstr "자녀 보호 설정 차단" + +msgid "Block Priiloader Override" +msgstr "프릴로더 무효화 차단" + +msgid "Block Reset Settings" +msgstr "리셋 설정 차단" + +msgid "Block SD Reload Button" +msgstr "SD Reload 버튼 차단" + +msgid "Block Sound Settings" +msgstr "사운드 설정 차단" + +msgid "Block Theme Downloader" +msgstr "테마 다운로더 차단" + +msgid "Block Theme Menu" +msgstr "테마 메뉴 차단" + +msgid "Block Title Launcher" +msgstr "타이틀 실행기 차단" + +msgid "Block Updates" +msgstr "업데이트 차단" + +msgid "Boot Content" +msgstr "콘텐트 차단" + +msgid "Boot Neek System Menu" +msgstr "Neek 시스템 메뉴 부팅" + +msgid "Boot?" +msgstr "부팅하겠습니까?" + +msgid "Both" +msgstr "둘 다" + +msgid "Both Ports" +msgstr "포트 둘 다" + +msgid "CC Rumble" +msgstr "CC 진동" + +msgid "Cache BNR Files" +msgstr "BNR 파일 캐쉬" + +msgid "Cache BNR Files Path" +msgstr "BNR 파일 경로 캐쉬" + +msgid "Cache Titles" +msgstr "타이틀 캐쉬" + +msgid "Can't be formatted" +msgstr "포맷을 지정할 수 없음" + +msgid "Can't create directory" +msgstr "디렉토리를 생성할 수 없음" + +#, c-format +msgid "Can't create file: %s" +msgstr "파일을 생성할 수 없음: %s" + +#, c-format +msgid "Can't create path: %s" +msgstr "경로를 생성할 수 없음: %s" + +msgid "Can't delete:" +msgstr "삭제할 수 없음:" + +msgid "Can't mount or unknown disc format." +msgstr "마운트 할 수 없거나 알 수 없는 디스크 포맷입니다." + +#, c-format +msgid "Can't open file for write: %s" +msgstr "쓰기 위해 파일을 열 수 없음: %s" + +#, c-format +msgid "Can't open file: %s" +msgstr "파일을 열 수 없음: %s" + +#, c-format +msgid "Can't read file: %s" +msgstr "파일을 읽을 수 없음: %s" + +msgid "Cancel" +msgstr "취소" + +msgid "Cannot write to destination." +msgstr "대상에 쓸 수 없습니다." + +msgid "Categories" +msgstr "카테고리" + +msgid "Categories:" +msgstr "카테고리:" + +msgid "Change Play Path" +msgstr "플레이 경로 변경" + +msgid "Channel Launcher" +msgstr "채널 실행기" + +msgid "Channels" +msgstr "채널" + +msgid "Cheatfile is blank" +msgstr "치트파일이 비어 있었음" + +msgid "Clear" +msgstr "정리" + +msgid "Click to Download Covers" +msgstr "커버를 다운로드하려면 클릭" + +msgid "Click to change game ID" +msgstr "게임 ID를 변경하려면 클릭" + +msgid "Clock" +msgstr "시계" + +msgid "Clock Scale Factor" +msgstr "시계 스케일 펙터" + +msgid "Close" +msgstr "닫기" + +msgid "Code Download" +msgstr "코드 다운로드" + +#, c-format +msgid "Coded by: %s" +msgstr "코드 작성자" + +msgid "Coding:" +msgstr "코딩:" + +msgid "Connection to server timed out." +msgstr "서버 연결이 시간 초과되었습니다." + +msgid "Console" +msgstr "콘솔" + +msgid "Console Default" +msgstr "콘솔 기본" + +msgid "Console Locked" +msgstr "콘솔 잠김" + +msgid "Console must be unlocked for this option." +msgstr "이 옵션을 사용하려면 콘솔의 잠금을 해제해야 합니다." + +msgid "Console must be unlocked to be able to use this." +msgstr "이 기능을 사용하려면 콘솔의 잠금을 해제해야 합니다." + +msgid "Console should be unlocked to modify it." +msgstr "콘솔을 잠금 해제하여 수정해야합니다." + +msgid "Continue" +msgstr "계속" + +msgid "Continue to install game?" +msgstr "계속 게임을 설치 하겠습니까?" + +msgid "Continue?" +msgstr "계속하겠습니까?" + +msgid "Controllevel" +msgstr "" + +msgid "Copy" +msgstr "복사" + +msgid "Copying Canceled" +msgstr "복사 취소" + +msgid "Copying GC game..." +msgstr "게임큐브 게임 복사 중 입니다..." + +msgid "Copying files..." +msgstr "파일 복사 중..." + +msgid "Correct Password" +msgstr "올바른 암호" + +msgid "Could not connect to the server." +msgstr "서버에 연결할 수 없습니다." + +msgid "Could not create GCT file" +msgstr "GCT 파일을 생성하지 못했습니다." + +#, c-format +msgid "Could not create path: %s" +msgstr "경로 미생성: %s" + +msgid "Could not extract files for:" +msgstr "파일을 추출 할 수 없음" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "wiitdb.xml에서 이 게임에 대한 정보를 찾을 수 없습니다." + +msgid "Could not get free device space for game." +msgstr "게임용 여유 장치 공간을 확보하지 못했습니다." + +msgid "Could not initialize DIP module!" +msgstr "DIP 모듈을 초기화 할 수 없습니다!" + +msgid "Could not initialize network!" +msgstr "네트워크를 초기화 할 수 없습니다!" + +msgid "Could not initialize network, time out!" +msgstr "네트워크를 초기화 할 수 없습니다. 시간 초과되었습니다." + +msgid "Could not open Disc" +msgstr "디스크를 열 수 없음" + +msgid "Could not open the WiiTDB.xml file." +msgstr "WiiTDB.xml 파일을 열 수 없습니다." + +msgid "Could not open wiitdb.xml." +msgstr "wiitdb.xml을 열 수 없습니다." + +msgid "Could not save." +msgstr "저장할 수 없습니다." + +msgid "Could not write file." +msgstr "파일을 쓸 수 없습니다." + +msgid "Could not write to:" +msgstr "쓸 수 없음:" + +msgid "Cover Download" +msgstr "커버 다운로드" + +msgid "Create" +msgstr "생성" + +msgid "Credits" +msgstr "크레딧" + +msgid "Crop Overscan" +msgstr "자르기 오버스캔" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "현재의 neek 파일은 neek2o가 아닙니다. 게임 자동 부팅이 비활성화 되었습니다." + +msgid "Custom Banners" +msgstr "사용자 정의 배너" + +msgid "Custom Paths" +msgstr "사용자 정의 경로" + +msgid "Customs" +msgstr "사용자 정의" + +msgid "Customs/Original" +msgstr "사용자 정의/오리지날" + +msgid "D Buttons" +msgstr "D 버튼" + +msgid "DOL Path" +msgstr "DOL 경로" + +msgid "Debug" +msgstr "디버그" + +msgid "Debug Wait" +msgstr "디버그 대기" + +msgid "Debugger Paused Start" +msgstr "디버거 일시 중지된 시작" + +msgid "Dec" +msgstr "12월" + +msgid "Default" +msgstr "기본" + +msgid "Default Gamesettings" +msgstr "기본 게임설정" + +msgid "Default Settings" +msgstr "기본 설정" + +msgid "Delete" +msgstr "삭제" + +msgid "Delete Cached Banner" +msgstr "캐쉬 배너 삭제" + +msgid "Delete Cheat GCT" +msgstr "치트 GCT 삭제" + +msgid "Delete Cheat TXT" +msgstr "치트 TXT 삭제" + +msgid "Delete Cover Artwork" +msgstr "커버 삽화 삭제" + +msgid "Delete Disc Artwork" +msgstr "디스크 삽화 삭제" + +msgid "Delete category" +msgstr "카테고리 삭제" + +msgid "Deleting directories..." +msgstr "디렉토리를 삭제하는 중 입니다..." + +msgid "Deleting files..." +msgstr "파일을 삭제하는 중 입니다..." + +msgid "Design:" +msgstr "디자인:" + +msgid "Details" +msgstr "세부 내용" + +msgid "Developed by" +msgstr "개발" + +msgid "Developer:" +msgstr "개발자" + +msgid "Devolution" +msgstr "데볼루션" + +msgid "Devolution Loader Path" +msgstr "데볼루션 로더 경로" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "데볼루션의 loader.bin 파일을 로드할 수 없습니다." + +msgid "Directory does not exist!" +msgstr "디렉토리가 존재하지 않습니다!" + +msgid "Disc 1" +msgstr "디스크 1" + +msgid "Disc 2" +msgstr "디스크 2" + +msgid "Disc Artwork Download" +msgstr "디스크 삽화 다운로드" + +msgid "Disc Artwork Path" +msgstr "디스크 삽화 경로" + +msgid "Disc Default" +msgstr "기본 디스크" + +msgid "Disc Insert Detected" +msgstr "디스크 접속 감지" + +msgid "Disc Read Delay" +msgstr "디스크 읽기 지연" + +msgid "Disc read error." +msgstr "디스크 읽기 오류입니다." + +msgid "Disc-Select Prompt" +msgstr "디스크-선택 프롬프트" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "DM(L) v2.6 이상에서 작동하려면 디스크2를 압축되지 않은 포맷으로 설치해야 합니다. 압축된 형식으로 설치 하겠습니까?" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "" + +msgid "Display" +msgstr "디스플레이" + +msgid "Display as a carousel" +msgstr "회전으로 표시" + +msgid "Display as a channel grid" +msgstr "채널 그리드로 표시" + +msgid "Display as a grid" +msgstr "그리드로 표시" + +msgid "Display as a list" +msgstr "목록으로 표시" + +msgid "Display favorites only" +msgstr "즐겨찾기만 표시" + +msgid "Do you want to apply it now?" +msgstr "지금 적용 하시겠습니까?" + +msgid "Do you want to apply this theme?" +msgstr "이 테마를 적용 하겠습니까?" + +msgid "Do you want to change language?" +msgstr "언어를 변경 하겠습니까?" + +msgid "Do you want to continue with next game?" +msgstr "다음 게임에 계속 하겠습니까?" + +msgid "Do you want to copy now?" +msgstr "지금 복사 하겠습니까?" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "게임을 SD로 복사하거나 SD에서 게임을 삭제 하겠습니까?" + +msgid "Do you want to delete a game on SD?" +msgstr "SD 게임을 삭제 하시겠습니까?" + +msgid "Do you want to discard changes?" +msgstr "변경 사항을 취소 하겠습니까?" + +msgid "Do you want to download this theme?" +msgstr "이 테마를 다운로드 하겠습니까?" + +msgid "Do you want to extract all the save games?" +msgstr "저장 게임을 모두 추출 하겠습니까?" + +msgid "Do you want to extract the save game?" +msgstr "세이브 게임을 추출 하겠습니까?" + +msgid "Do you want to format:" +msgstr "포맷 지정:" + +msgid "Do you want to install selected games?" +msgstr "선택한 게임을 설치 하겠습니까?" + +msgid "Do you want to load the default theme?" +msgstr "기본 테마를 로드 하겠습니까?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "파일을 이동 하겠습니까? 기존의 모든 항목이 삭제됩니다!" + +msgid "Do you want to re-init network?" +msgstr "네트워크를 다시 초기화 하겠습니까?" + +msgid "Do you want to start the game now?" +msgstr "지금 게임을 시작 하겠습니까?" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "모든 FAT32 파티션의 여유 공간 정보 섹터를 동기화 하겠습니까?" + +msgid "Do you wish to update/download all language files?" +msgstr "모든 언어 파일을 업데이트/다운로드 하겠습니까?" + +msgid "Dol Video Patch" +msgstr "Dol 비디오 패치" + +msgid "Download" +msgstr "다운로드" + +msgid "Download Now" +msgstr "지금 다운로드" + +msgid "Download finished" +msgstr "다운로드 종료" + +msgid "Downloading 3D Covers" +msgstr "3D 커버 다운로드" + +msgid "Downloading Custom Banners" +msgstr "사용자 정의 배너 다운로드" + +msgid "Downloading Flat Covers" +msgstr "평면 커버 다운로드" + +msgid "Downloading Full HQ Covers" +msgstr "전체 HQ 커버 다운로드" + +msgid "Downloading Full LQ Covers" +msgstr "전체 LQ 커버 다운로드" + +msgid "Downloading custom Discarts" +msgstr "사용자 정의를 다운로드" + +msgid "Downloading file..." +msgstr "파일 다운로드 중 입니다..." + +msgid "Downloading image:" +msgstr "이미지 다운로드" + +msgid "Downloading original Discarts" +msgstr "원본 디스크를 다운로드" + +msgid "Downloading pagelist:" +msgstr "페이지목록 다운:" + +msgid "Dump NAND to EmuNand" +msgstr "NAND를 EmuNand에 덤프" + +msgid "During zoom" +msgstr "확대/축소 중" + +msgid "Dutch" +msgstr "네덜란드어" + +msgid "ERROR" +msgstr "오류" + +msgid "ERROR:" +msgstr "오류" + +msgid "ERROR: Can't set up theme." +msgstr "오류: 테마를 설정할 수 없습니다" + +msgid "EmuNAND Wad Manager" +msgstr "EmuNAND Wad 매니저" + +msgid "EmuNand Channels" +msgstr "EmuNand 채널" + +msgid "Emulated Nand" +msgstr "에뮬레이트 된 낸드" + +msgid "English" +msgstr "영어" + +msgid "Enter Path" +msgstr "진입 경로" + +msgid "Error" +msgstr "오류" + +msgid "Error !" +msgstr "오류 !" + +#, c-format +msgid "Error creating path: %s" +msgstr "오류 생성 경로: %s" + +msgid "Error opening downloaded file" +msgstr "다운로드 한 파일을 열 때 오류 발생" + +msgid "Error reading Disc" +msgstr "디스크 읽기 오류" + +msgid "Error reading disc" +msgstr "디스크 읽기 오류" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "파일을 다운 로딩하는 동안 오류가 발생: %i" + +msgid "Error while downloding file" +msgstr "파일을 다운 로딩하는 동안 오류가 발생" + +msgid "Error while opening the zip." +msgstr "zip를 여는 중 오류가 발생했습니다." + +msgid "Error while transfering data." +msgstr "데이터를 전송하는 중 오류가 발생했습니다." + +msgid "Error while updating USB Loader GX." +msgstr "USB Loader GX를 업데이트하는 중 오류가 발생했습니다." + +msgid "Error writing the data." +msgstr "데이터를 쓰는 중 오류가 발생했습니다." + +msgid "Error:" +msgstr "오류:" + +msgid "Error: Not enough space on SD." +msgstr "오류: SD에 충분한 공간이 없습니다." + +msgid "Errors occured." +msgstr "오류가 발생했습니다." + +msgid "Everything" +msgstr "모두" + +msgid "Exit" +msgstr "종료" + +msgid "Exit to where?" +msgstr "어디서 종료하겠습니까?" + +msgid "Export All Saves to EmuNand" +msgstr "모든 저장 내용을 EmuNand로 내보내기" + +msgid "Export Miis to EmuNand" +msgstr "Mii를 EmuNand로 내보내기" + +msgid "Export SYSCONF to EmuNand" +msgstr "SYSCONF를 EmuNand로 내보내기" + +msgid "Extract Miis to the Emu NAND?" +msgstr "Emu NAND에 Mii를 추출하겠습니까?" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "Emu NAND에 SYSCONF를 추출하겠습니까?" + +msgid "Extract Save to EmuNand" +msgstr "EmuNand 저장 추출" + +msgid "Extracting file:" +msgstr "파일 추출:" + +msgid "Extracting files..." +msgstr "파일 추출 중 입니다..." + +msgid "Extracting files:" +msgstr "파일 추출:" + +msgid "Extracting nand files:" +msgstr "nand 파일 추출:" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "실패" + +msgid "Failed copying file" +msgstr "파일 복사 실패" + +msgid "Failed formating" +msgstr "포멧 실패" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "모든 파일 추출에 실패했습니다. Savegame이 없을 수 있습니다." + +msgid "Failed to extract." +msgstr "추출에 실패했습니다." + +msgid "Failed to initialize the USB storage device." +msgstr "USB 저장 장치를 초기화하는데 실패했습니다." + +msgid "Failed to open partition" +msgstr "파티션 열지를 실패했습니다." + +msgid "Failed to read ticket." +msgstr "티켓 읽기를 실패하였습니다." + +msgid "Failed to read tmd file." +msgstr "tmd 파일 읽기에 실패했습니다." + +msgid "Failed to read wad header." +msgstr "wad 헤더 읽기에 실패했습니다." + +msgid "Failed updating" +msgstr "업데이트 실패" + +msgid "Favorite Level" +msgstr "즐겨찿기 레벨" + +msgid "Features" +msgstr "기능" + +msgid "Features Settings" +msgstr "기능 설정" + +msgid "Feb" +msgstr "2월" + +msgid "File" +msgstr "파일" + +msgid "File not found." +msgstr "파일을 찾을 수 없습니다." + +msgid "File read/write error." +msgstr "파일 읽기/쓰기 오류입니다." + +msgid "Files extracted successfully." +msgstr "파일을 성공적으로 추출했습니다." + +#, c-format +msgid "Filesize is %i Byte." +msgstr "파일 크기는 %i Byte입니다." + +msgid "Filesize is 0 Byte." +msgstr "파일 크기는 0 Byte입니다." + +msgid "Flat Covers" +msgstr "평면 커버" + +msgid "Flip-X" +msgstr "" + +msgid "Folder" +msgstr "폴더" + +msgid "Font Scale Factor" +msgstr "폰트 스케일 펙터" + +msgid "Force 16:9" +msgstr "강제 16:9" + +msgid "Force 4:3" +msgstr "강제 4:3" + +msgid "Force NTSC" +msgstr "강제 NTSC" + +msgid "Force NTSC480p" +msgstr "강제 NTSC480p" + +msgid "Force PAL480p" +msgstr "강제 PAL480p" + +msgid "Force PAL50" +msgstr "강제 PAL50" + +msgid "Force PAL60" +msgstr "강제 PAL60" + +msgid "Force Titles from Disc" +msgstr "디스크에서 강제 타이틀" + +msgid "Force Widescreen" +msgstr "강제 와이드스크린" + +msgid "Format" +msgstr "포맷" + +msgid "Formatting, please wait..." +msgstr "포맷중입니다, 잠시 기다려 주세요..." + +msgid "Found missing images." +msgstr "누락된 이미지를 찾았습니다." + +msgid "Frame" +msgstr "프레임" + +msgid "Frame Projection Height" +msgstr "프레임 영상 높이" + +msgid "Frame Projection Width" +msgstr "프레임 영상 폭" + +msgid "Frame Projection X-Offset" +msgstr "프레임 영상 X-옵셋" + +msgid "Frame Projection Y-Offset" +msgstr "프레임 영상 Y-옵셋" + +msgid "Frames" +msgstr "프레임" + +msgid "Free Space" +msgstr "여유 공간" + +msgid "French" +msgstr "프랑스어" + +msgid "Full" +msgstr "전체" + +msgid "Full Cover Path" +msgstr "전체 커버 경로" + +msgid "Full Covers" +msgstr "전체 커버" + +msgid "Full Menu" +msgstr "전체 메뉴" + +msgid "Full covers Download" +msgstr "전체 커버 다운로드" + +msgid "Full shutdown" +msgstr "완전한 종료" + +msgid "GAMEID_Gamename" +msgstr "" + +msgid "GC Banner Scale" +msgstr "게임큐브 배너 스케일" + +msgid "GC Games" +msgstr "게임큐브 게임" + +msgid "GC Install 32K Aligned" +msgstr "게임큐브 설치 32K 정렬" + +msgid "GC Install Compressed" +msgstr "게임큐브 설치 압축" + +msgid "GCT Cheatcodes Path" +msgstr "GCT 치트코드 경로" + +msgid "GCT File created" +msgstr "GCT 파일 생성됨" + +msgid "GUI Settings" +msgstr "GUI 설정" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "게임큐브 게임 삭제" + +msgid "Game Cube Install Menu" +msgstr "게임큐브 설치 메뉴" + +msgid "Game ID" +msgstr "게임 ID" + +msgid "Game IOS" +msgstr "게임 IOS" + +msgid "Game Language" +msgstr "게임 언어" + +msgid "Game Load" +msgstr "게임 로드" + +msgid "Game Lock" +msgstr "게임 잠금" + +msgid "Game Only" +msgstr "게임 전용" + +msgid "Game Region" +msgstr "게임 지역" + +msgid "Game Size" +msgstr "게임 크기" + +msgid "Game Sound Mode" +msgstr "게임 사운드 모드" + +msgid "Game Sound Volume" +msgstr "게임 사운드 볼륨" + +msgid "Game Split Size" +msgstr "게임 분할 크기" + +msgid "Game Window Mode" +msgstr "게임 윈도우 모드" + +msgid "Game is already installed:" +msgstr "게임이 이미 설치:" + +msgid "Game's IOS" +msgstr "게임의 IOS" + +msgid "Game/Install Partition" +msgstr "게임/파티션 설치" + +msgid "GameCube" +msgstr "게임큐브" + +msgid "GameCube Controller" +msgstr "게임큐브 콘트롤러" + +msgid "GameCube Mode" +msgstr "게임큐브 모드" + +msgid "GameCube Source" +msgstr "게임큐브 소스" + +msgid "Gamename [GAMEID]" +msgstr "게임이름 [GAMEID]" + +msgid "Games" +msgstr "게임" + +msgid "Generating GXGameCategories.xml" +msgstr "GXGameCategories.xml 생성" + +msgid "Genre:" +msgstr "장르:" + +msgid "German" +msgstr "독일어" + +msgid "Getting file list..." +msgstr "파일 목록 가져는 중 입니다..." + +msgid "Getting game folder size..." +msgstr "게임 폴더 크기 가져 오는 중 입니다..." + +msgid "Global Settings" +msgstr "글로벌 설정" + +msgid "Grid Scroll Speed" +msgstr "그리드 스크롤 속도" + +msgid "HOME Menu" +msgstr "홈 메뉴" + +msgid "Hard Drive Settings" +msgstr "하드 드라이브 설정" + +msgid "High Quality" +msgstr "높은 품질" + +msgid "High/Low" +msgstr "높음/낮음" + +msgid "Homebrew Apps Path" +msgstr "홈브류 응용 프로그램 경로" + +msgid "Homebrew Channel" +msgstr "홈브류 채널" + +msgid "Homebrew Launcher" +msgstr "홈브류 실행기" + +msgid "Hooktype" +msgstr "후크타입" + +msgid "Hour" +msgstr "시간" + +msgid "How do you want to update?" +msgstr "어떻게 업데이트 하겠습니까?" + +msgid "How to Shutdown?" +msgstr "어떻게 종료하겠습니까?" + +msgid "Import Categories" +msgstr "카테고리 가져오기" + +msgid "Import operation successfully completed." +msgstr "가져오기 작업이 성공적으로 완료되었습니다." + +msgid "Importing categories" +msgstr "카테고리 가져오기" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "수신 파일 %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "수신 파일 %0.2fMB" + +msgid "Individual" +msgstr "개인" + +msgid "Initializing Network" +msgstr "네트워크 초기화" + +msgid "Insert Disk" +msgstr "디스크 넣기" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "Wii 또는 Gamecube 디스크를 넣으세요!" + +msgid "Install" +msgstr "설치" + +msgid "Install Canceled" +msgstr "설치 취소" + +msgid "Install Directories" +msgstr "디렉토리 설치" + +msgid "Install Error!" +msgstr "설치 오류입니다!" + +msgid "Install Partitions" +msgstr "파티션 설치" + +msgid "Install a game" +msgstr "게임 설치" + +msgid "Install error - Cleaning incomplete data." +msgstr "설치 오류 - 불완전한 데이터 정리" + +msgid "Install finished" +msgstr "설치 완료" + +msgid "Installing Game Cube Game..." +msgstr "게임큐브 게임 설치 중 입니다..." + +msgid "Installing content" +msgstr "콘텐츠 설치" + +msgid "Installing game:" +msgstr "게임 설치:" + +msgid "Installing title..." +msgstr "타이틀 설치 중 입니다..." + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "잘못된 IOS 번호가 입력되었습니다. 상속의 경우 -1, 200-255의 숫자여야 합니다" + +msgid "Invalid wad file." +msgstr "잘못된 wad 파일입니다." + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "우리에게 도움이 될 만한 정보가 있는 것으로 보입니다. 이 정보를 개발팀에 전달하십시오." + +msgid "Italian" +msgstr "이탈리아어" + +msgid "Jan" +msgstr "1월" + +msgid "Japanese" +msgstr "일본어" + +msgid "Japanese Patch" +msgstr "일본어 경로" + +msgid "Joypad" +msgstr "조이패드" + +msgid "July" +msgstr "7월" + +msgid "June" +msgstr "6월" + +msgid "KPAD Read" +msgstr "KPAD 읽기" + +msgid "Keyboard" +msgstr "키보드" + +msgid "Korean" +msgstr "한국어" + +msgid "LED Activity" +msgstr "LED 활성화" + +msgid "Language Files" +msgstr "언어 파일" + +msgid "Language change:" +msgstr "언어 변경:" + +msgid "Languagefiles Path" +msgstr "Languagefiles 경로" + +msgid "Languagepath changed." +msgstr "Languagepath 변경되었습니다." + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "에뮬레이트 된 nand를 사용하여 Wii 게임을 시작하면 d2x cIOS에서만 작동합니다! 게임 IOS를 d2x cIOS로 먼저 변경하십시오." + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "에뮬레이트 된 nand 채널 시작은 d2x cIOS에서만 작동합니다! 게임 IOS를 d2x cIOS로 먼저 변경하십시오." + +msgid "Left" +msgstr "왼쪽" + +msgid "Like SysMenu" +msgstr "SysMenu 처럼" + +msgid "List on Gamelaunch" +msgstr "Gamelaunch 목록" + +msgid "Load" +msgstr "로드" + +msgid "Load From SD/USB" +msgstr "SD/USB에서 로드" + +#, c-format +msgid "Load file from: %s ?" +msgstr "로드 파일: %s?" + +msgid "Load this DOL as alternate DOL?" +msgstr "이 DOL을 대체 DOL로 로드 하겠습니까?" + +msgid "Loader Settings" +msgstr "로더 설정" + +msgid "Loader's IOS" +msgstr "로더의 IOS" + +msgid "Loading standard language." +msgstr "표준 언어가 로딩됩니다." + +msgid "Loading standard music." +msgstr "표준 음악이 로딩됩니다." + +msgid "Lock Console" +msgstr "콘솔 잠금" + +msgid "Lock USB Loader GX" +msgstr "USB Loader GX 잠금" + +msgid "Locked" +msgstr "잠금" + +msgid "Log to file" +msgstr "파일에 기록" + +msgid "Loop Directory" +msgstr "디렉토리 반복" + +msgid "Loop Music" +msgstr "음악 반복" + +msgid "Loop Sound" +msgstr "사운드 반복" + +msgid "Low Quality" +msgstr "낮은 품질" + +msgid "Low/High" +msgstr "낮음/높음" + +msgid "MIOS (Default & Customs)" +msgstr "MIOS (기본 & 사용자 정의)" + +msgid "Main DOL" +msgstr "메인 DOL" + +msgid "Main GameCube Games Path" +msgstr "메인 게임큐브 게임 경로" + +msgid "Main GameCube Path" +msgstr "메인 게임큐브 경로" + +msgid "Main Path" +msgstr "메인 경로" + +msgid "Manual (40~120)" +msgstr "매뉴얼 (40~120)" + +msgid "Mar" +msgstr "3월" + +msgid "Mark new games" +msgstr "새 게임 표시" + +msgid "May" +msgstr "5월" + +msgid "Memory Card Blocks Size" +msgstr "메모리 카드 블록 크기" + +msgid "Memory Card Emulation" +msgstr "메모리 카드 에뮬레이션" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "2043 블록으로 구성된 메모리 카드에는 Nintendont에 문제가 있습니다. 자신의 책임하에 사용하십시오." + +msgid "Messageboard Update" +msgstr "게시판 업데이트" + +msgid "Motion+ Video" +msgstr "모션+ 비디오" + +msgid "Mount DVD drive" +msgstr "DVD 드라이브 마운트" + +msgid "Mount USB at launch" +msgstr "시작시 USB 마운트" + +msgid "Move File" +msgstr "파일 이동" + +msgid "Multiple Partitions" +msgstr "멀티 파티션" + +msgid "Music Loop Mode" +msgstr "음악 반복 모드" + +msgid "Music Volume" +msgstr "음악 볼륨" + +msgid "NMM Mode" +msgstr "MMM 모드" + +msgid "Nand Chan. Emulation" +msgstr "Nand Chan. 에뮬레이션" + +msgid "Nand Channels" +msgstr "낸드 채널" + +msgid "Nand Emu Channel Path" +msgstr "낸드 에뮤 채널 경로" + +msgid "Nand Emu Path" +msgstr "낸드 에뮤 경로" + +msgid "Nand Emulation" +msgstr "낸드 에뮬레이션" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "Nand 에뮬레이션은 D2X cIOS에서만 사용할 수 있습니다!" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "Nand 에뮬레이션은 FAT/FAT32 파티션에서만 작동합니다!" + +msgid "Nand Saves Emulation" +msgstr "Nand는 에뮬레이션을 저장" + +msgid "Native Controller" +msgstr "실제 컨트롤러" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "Neek NAND 경로 선택에 실패했습니다." + +msgid "Neek kernel file not found." +msgstr "Neek 커널 파일을 찾을 수 없습니다." + +msgid "Neek kernel loading failed." +msgstr "Neek 커널 로드에 실패했습니다." + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "Neek2o는 SD에서 '에뮬레이트 된 NAND 채널 경로'를 지원하지 않습니다! 대신 Uneek2o를 설치하십시오." + +msgid "Neither" +msgstr "어느 쪽이든" + +msgid "Network is not initiated." +msgstr "네트워크가 초기화되지 않았습니다." + +msgid "Next" +msgstr "다음" + +msgid "Nintendont" +msgstr "닌텐돈트" + +msgid "Nintendont Loader Path" +msgstr "닌텐돈트 로더 경로" + +msgid "No" +msgstr "아니오" + +msgid "No Cheatfile found" +msgstr "Cheatfile을 찾을 수 없음" + +msgid "No DOL file found on disc." +msgstr "디스크에 DOL 파일이 없습니다." + +msgid "No Disc+" +msgstr "디스크+ 없음" + +msgid "No Splitting" +msgstr "분할 안 함" + +msgid "No URL or Path specified." +msgstr "URL 또는 경로가 지정되지 않았습니다." + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "WBFS 또는 FAT/NTFS/EXT 파티션 없음" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "구성 경로에 Wiinnertag.xml이 없습니다. 예제 파일을 생성 하겠습니까?" + +msgid "No change" +msgstr "변경 없음" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "치트는 선택되지 않았습니다! GCT 파일을 삭제해야 합니까?" + +msgid "No data could be read." +msgstr "데이터를 읽을 수 없습니다." + +msgid "No disc inserted." +msgstr "디스크가 들어있지 않습니다." + +msgid "No favorites selected." +msgstr "선택한 즐겨찾기가 없습니다." + +msgid "No file missing!" +msgstr "누락된 파일이 없습니다!" + +msgid "No games found on the disc" +msgstr "디스크에서 게임을 찾지 못했습니다." + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "장치에서 업데이트 할 언어 파일이 없습니다! 새 언어 파일을 다운로드 하시겠습니까?" + +msgid "No new updates." +msgstr "새로운 업데이트가 없습니다." + +msgid "No themes found on the site." +msgstr "사이트에서 테마를 찾을 수 없습니다." + +msgid "No themes found." +msgstr "테마가 없습니다." + +msgid "No wad file found in this folder." +msgstr "이 폴더에는 wad 파일이 없습니다." + +msgid "NoSSL only" +msgstr "NoSSL 전용" + +msgid "None" +msgstr "없음" + +msgid "Normal" +msgstr "보통" + +msgid "Not Initialized" +msgstr "초기화되지 않음" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "Wii 또는 게임큐브 디스크가 아님" + +msgid "Not a valid URL" +msgstr "유효한 URL이 아닙니다." + +msgid "Not a valid URL path" +msgstr "유효한 URL 경로가 아닙니다." + +msgid "Not a valid domain" +msgstr "유효한 도메인이 아닙니다." + +msgid "Not enough free memory." +msgstr "충분한 여유 공간이 없습니다." + +msgid "Not enough free space on device." +msgstr "장치에 여유 공간이 충분하지 않습니다." + +msgid "Not enough free space!" +msgstr "여유 공간이 충분하지 않습니다!" + +msgid "Not enough memory for FST." +msgstr "FST에 대한 메모리가 충분하지 않습니다." + +msgid "Not enough memory." +msgstr "메모리가 충분하지 않습니다." + +msgid "Not required" +msgstr "필요 없음" + +msgid "Not supported format!" +msgstr "지원되지 않는 포맷!" + +msgid "Nothing selected to delete." +msgstr "선택되어 삭제된 것이 없습니다." + +msgid "Nothing selected to install." +msgstr "선택되어 설치된 것이 없습니다." + +msgid "Nov" +msgstr "11월" + +msgid "OFF" +msgstr "끔" + +msgid "OK" +msgstr "확인" + +msgid "ON" +msgstr "켬" + +msgid "ON (Multi)" +msgstr "켬 (멀티)" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "오카리나" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "오카리나는 아직 neek2o에서 지원되지 않습니다. 어쨓든 게임을 시작합니까?" + +msgid "Oct" +msgstr "10월" + +msgid "Official Site:" +msgstr "공식 사이트:" + +msgid "Offset" +msgstr "옵셋" + +msgid "Ok" +msgstr "확인" + +msgid "One Line A" +msgstr "한 줄 A" + +msgid "One Line B" +msgstr "한 줄 B" + +msgid "Only Game Partition" +msgstr "게임 파티션 전용" + +msgid "Only for Install" +msgstr "설치 전용" + +msgid "Original" +msgstr "오리지날" + +msgid "Original/Customs" +msgstr "오리지날/사용자 정의" + +msgid "PAD Hook" +msgstr "패드 후크" + +msgid "PAL50 Patch" +msgstr "PAL50 패치" + +msgid "Parental Control" +msgstr "자녀 보호" + +msgid "Partial" +msgstr "부분" + +msgid "Partition" +msgstr "파티션" + +msgid "Password" +msgstr "비밀번호" + +msgid "Password Changed" +msgstr "비밀번호 변경됨" + +msgid "Password has been changed" +msgstr "비밀번호가 변경되었습니다." + +msgid "Patch Country Strings" +msgstr "패치 국가 문자열" + +msgid "Path Changed" +msgstr "경로가 변경됨" + +msgid "Permission denied." +msgstr "허가가 거부되었습니다." + +msgid "Pick from a list" +msgstr "목록에서 선택" + +msgid "Pixels" +msgstr "픽셀" + +msgid "Play Count" +msgstr "플레이 횟수" + +msgid "Play Next" +msgstr "다음 플레이" + +msgid "Play Once" +msgstr "한 번 플레이" + +msgid "Play Previous" +msgstr "이전 플레이" + +msgid "Playing Music:" +msgstr "재생 음악:" + +msgid "Please wait" +msgstr "기다려주십시오." + +msgid "Please wait..." +msgstr "잠시만 기다려주십시오 ..." + +msgid "Power off the Wii" +msgstr "Wii 전원 끄기" + +msgid "Prev" +msgstr "이전" + +msgid "Private Server" +msgstr "사설 서버" + +msgid "Process finished." +msgstr "프로세스가 완료되었습니다." + +msgid "Progressive Patch" +msgstr "프로그레시브 패치" + +msgid "Prompts Buttons" +msgstr "프롬프트 버튼" + +msgid "Published by" +msgstr "출시" + +msgid "Quick Boot" +msgstr "빠른 부팅" + +msgid "Random Directory Music" +msgstr "랜덤 디렉토리 음악" + +msgid "Real Nand" +msgstr "실제 낸드" + +msgid "Receiving file from:" +msgstr "수신 파일:" + +msgid "Region Free" +msgstr "지역 무효화" + +msgid "Region Patch" +msgstr "지역 패치" + +msgid "Released" +msgstr "릴리즈" + +msgid "Reload SD" +msgstr "SD 재로드" + +msgid "Reloading game list now, please wait..." +msgstr "게임 목록을 다시 불러오고 있습니다. 잠시만 기다려주십시오..." + +msgid "Remember Unlock" +msgstr "잠금 해제 기억" + +msgid "Remove Read Speed Limit" +msgstr "읽기 속도 제한 제거" + +msgid "Remove update" +msgstr "업데이트 제거" + +msgid "Rename Game Title" +msgstr "게임 타이틀 이름 바꾸기" + +msgid "Rename category" +msgstr "카테고리 이름 바꾸기" + +msgid "Reset" +msgstr "리셋" + +msgid "Reset BG Music" +msgstr "배경 음악 리셋" + +msgid "Reset Playcounter" +msgstr "Playcounter 리셋" + +msgid "Reset to default BGM?" +msgstr "기본 BGM으로 리셋 하겠습니까?" + +msgid "Restarting..." +msgstr "다시 시작하는 중..." + +msgid "Return" +msgstr "돌아가기" + +msgid "Return To" +msgstr "로 돌아가기" + +msgid "Return to Wii Menu" +msgstr "Wii 메뉴로 돌아가기" + +msgid "Right" +msgstr "오른쪽" + +msgid "Rotating Disc" +msgstr "회전식 디스크" + +msgid "Round" +msgstr "라운드" + +msgid "Rumble" +msgstr "진동" + +msgid "SChinese" +msgstr "간체 중국어" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "SD 카드에 액세스 할 수 없습니다." + +msgid "SD GameCube Games Path" +msgstr "SD 게임큐브 게임 경로" + +msgid "SD GameCube Path" +msgstr "SD 게임큐브 경로" + +msgid "SD Path" +msgstr "SD 경로" + +msgid "SFX Volume" +msgstr "SFX 볼륨" + +msgid "Save" +msgstr "저장" + +msgid "Save Failed. No device inserted?" +msgstr "저장 실패했습니다. 장치를 연결하지 않았습니까?" + +msgid "Save Game List to" +msgstr "저장 대상 게임 목록" + +msgid "Save List" +msgstr "목록 저장" + +msgid "Saved" +msgstr "저장" + +msgid "Savegame might not exist for this game." +msgstr "이 게임에는 Savegame이 없을 수도 있습니다." + +msgid "Screensaver" +msgstr "화면보호기" + +msgid "Screenshot" +msgstr "스크린샷" + +msgid "Select" +msgstr "선택" + +msgid "Select DOL Offset" +msgstr "DOL 옵셋 선택" + +msgid "Select a DOL" +msgstr "DOL 선택" + +msgid "Select a DOL from Game" +msgstr "게임에서 DOL 선택" + +msgid "Select game categories" +msgstr "게임 카테고리 선택" + +msgid "Select loader mode" +msgstr "로더 모드 선택" + +msgid "Select the NAND Emu Path to use." +msgstr "사용할 낸드 에뮤 경로를 선택하십시오." + +msgid "Select titles sources." +msgstr "타이틀 소스 선택" + +msgid "Sept" +msgstr "9월" + +msgid "Set Search-Filter" +msgstr "검색-필터 설정" + +msgid "Settings" +msgstr "설정" + +msgid "Settings File" +msgstr "파일 설정" + +msgid "Show Categories" +msgstr "카테고리 보기" + +msgid "Show Favorite on banner" +msgstr "배너에서 즐겨착기 보기" + +msgid "Show Free Space" +msgstr "여유 공간 보기" + +msgid "Show Play Count" +msgstr "플레이 횟수 보기" + +msgid "Show SD" +msgstr "SD 보기" + +msgid "Shutdown System" +msgstr "시스템 종료" + +msgid "Shutdown Wii" +msgstr "Wii 종료" + +msgid "Skip Errors" +msgstr "오류 건너뛰기" + +msgid "Skip IPL" +msgstr "IPL 건너뛰기" + +msgid "Sneek Video Patch" +msgstr "Sneek 비디오 경로" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "죄송합니다. http://wii.spiffy360.com에 사용자 등록이 필요하기 때문에 테마 다운로더 메뉴가 더 이상 작동하지 않습니다." + +msgid "Sort alphabetically" +msgstr "알파벳 순서로 정렬" + +msgid "Sort by number of players" +msgstr "플레이어 수 정렬" + +msgid "Sort by rank" +msgstr "순위별로 정렬" + +msgid "Sort order by most played" +msgstr "가장 많이 플레이 한 순서대로 정렬" + +msgid "Sound" +msgstr "사운드" + +msgid "Sound Settings" +msgstr "사운드 설정" + +msgid "Sound+BGM" +msgstr "사운드+BGM" + +msgid "Sound+Quiet" +msgstr "사운드+무음" + +msgid "Spanish" +msgstr "스페인어" + +msgid "Special thanks to:" +msgstr "특별 감사:" + +msgid "Split each 2GB" +msgstr "각 2GB 분할" + +msgid "Split each 4GB" +msgstr "각 4GB 분할" + +msgid "Standby" +msgstr "대기" + +msgid "Start" +msgstr "시작" + +msgid "Success" +msgstr "성공" + +msgid "Success." +msgstr "성공하였습니다." + +msgid "Success:" +msgstr "성공:" + +msgid "Successfully Saved" +msgstr "성공적으로 저장" + +msgid "Successfully Updated" +msgstr "성공적으로 업데이트" + +msgid "Successfully copied" +msgstr "성공적으로 복사" + +msgid "Successfully deleted:" +msgstr "성공적으로 삭제:" + +msgid "Successfully extracted theme." +msgstr "테마를 성공적으로 추출했습니다." + +msgid "Successfully installed:" +msgstr "성공적으로 설치:" + +msgid "Successfully updated." +msgstr "성공적으로 업데이트되었습니다." + +msgid "Switching to channel list mode." +msgstr "채널 목록 모드로 전환 중입니다." + +msgid "Sync FAT32 FS Info" +msgstr "FAT32 FS 정보 동기화" + +msgid "Synchronizing..." +msgstr "동기화 중..." + +msgid "System Default" +msgstr "기본 시스템" + +msgid "TChinese" +msgstr "번체 중국어" + +msgid "TXT Cheatcodes Path" +msgstr "TXT 치트코드 경로" + +msgid "The .them file was not found in the zip." +msgstr ".them 파일이 zip에서 발견되지 않았습니다." + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "강제 와이드 스크린 설정에는 DIOS MIOS v2.1 이상이 필요합니다. 이 설정은 무시됩니다." + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Mii는 사용자의 Emu nand 경로와 Emu nand 채널 경로로 추출됩니다. 주의: 기존 파일은 모두 덮어쓰여집니다." + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "디스크+ 없음 설정에는 DIOS MIOS 2.2 업데이트2가 필요합니다. 이 설정은 무시됩니다." + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "SYSCONF 파일은 에뮬레이션 경로와 에뮬 및 채널 경로로 추출됩니다. 주의: 기존 파일은 모두 덮어쓰여집니다." + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "현재 SD 카드에 대한 읽기/쓰기 액세스가 있는 경우 응용 프로그램이 중단될 수 있습니다!" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "입력된 디렉토리가 존재하지 않습니다. 그것을 만들고 싶습니까?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "파일이 에뮬레이션 및 채널 경로로 추출됩니다. 주의: 기존 파일은 모두 덮어여집니다." + +msgid "The game is on SD Card." +msgstr "게임은 SD 카드에 있습니다." + +msgid "The game is on USB." +msgstr "게임은 USB에 있습니다." + +msgid "The save game will be extracted to your emu nand path." +msgstr "저장 게임이 emu nand 경로로 추출됩니다." + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "게임 저장이 에뮬레이션 및 채널 경로로 추출됩니다. 주의: 기존 파일은 모두 덮어쓰여집니다." + +msgid "The wad file was installed" +msgstr "wad 파일 설치" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "오류 %i이(가) 발생하여 설치에 실패" + +msgid "Theme Downloader" +msgstr "테마 다운로더" + +msgid "Theme Menu" +msgstr "테마 메뉴" + +msgid "Theme Path" +msgstr "테마 경로" + +msgid "Theme Title:" +msgstr "테마 타이틀:" + +msgid "Themes by www.spiffy360.com" +msgstr "www.spiffy360.com의 테마" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "이 IOS는 BootMii IOS입니다. 확실한 경우 BootMii가 아니며 이 경고를 무시하는 것 외에 다른 것을 설치하십시오." + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "이 IOS는 타이틀 목록에 없습니다. 이 경고가 무시하는 것보다 설치가 확실한 경우." + +msgid "This Nintendont version does not support games on USB." +msgstr "이 닌텐돈트 버전은 USB 게임을 지원하지 않습니다." + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "이 닌텐돈트 버전은 올바르게 지원되지 않습니다. 자동 부팅이 비활성화 되었습니다." + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "이 게임에는 여러 개의 디스크가 있습니다. 실행할 디스크를 선택하십시오." + +msgid "This path must be on SD!" +msgstr "이 경로는 SD에 있어야 합니다!" + +msgid "Time left:" +msgstr "시간 남음:" + +msgid "Timer Fix" +msgstr "타이머 수정" + +msgid "Title Launcher" +msgstr "타이틀 실행기" + +msgid "Titles Path" +msgstr "타이틀 경로" + +msgid "Titles from GameTDB" +msgstr "GameTDB의 타이틀" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "디스크에서 게임큐브 게임을 실행하려면 게임 설정에서 게임큐브 모드를 MIOS로 설정해야 합니다." + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "%s로 게임큐브 게임을 실행하려면 USB FAT32 파티션에 게임큐브 게임을 배치해야 합니다." + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "%s로 게임큐브 게임을 실행하려면 첫번째 기본 FAT32 파티션에서 '메인 게임큐브 경로'를 설정해야 합니다." + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "%s로 게임큐브 게임을 실행하려면 하드 드라이브의 첫번째 기본 파티션에 '메인 게임큐브 경로'를 설정해야 합니다." + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "%s로 게임큐브 게임을 실행하려면 '메인 게임큐브 경로'를 USB FAT32 파티션으로 설정해야 합니다." + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "%s로 게임큐브 게임을 실행하려면 512 바이트/섹터 하드 드라이브를 사용해야 합니다." + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "%s로 게임큐브 게임을 실행하려면 32k 바이트/클러스터 이하의 파티션을 사용해야 합니다." + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "데볼류션으로 게임큐브 게임을 실행하려면 데볼류션 로더 경로에 loader.bin 파일이 있어야합니다." + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "닌텐돈트로 게임큐브 게임을 실행하려면 닌텐돈트 로더 경로에 boot.dol 파일이 있어야 합니다." + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "%s와(과) 함께 HID를 사용하려면 %s 파일이 필요합니다." + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "neek를 사용하려면 하드 드라이브의 첫 번째 주 파티션에 '에뮬레이트 된 NAND 채널 경로'를 설정해야 합니다." + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "neek를 사용하려면 '에뮬레이트 된 NAND 채널 경로'를 FAT32 파티션으로 설정해야 합니다." + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "neek를 사용하려면 512 바이트/섹터 하드 드라이브를 사용해야 합니다." + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "%s에 오카리나를 사용하려면 %s 파일이 필요합니다." + +msgid "Tooltip Delay" +msgstr "툴팁 지연" + +msgid "Tooltips" +msgstr "툴팁" + +msgid "Transfer failed" +msgstr "전송 실패" + +msgid "Triforce Arcade Mode" +msgstr "트라이포스 아케이드 모드" + +msgid "Two Lines" +msgstr "두 줄" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "USB 장치가 초기화되지 않았습니다." + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX가 보호되어 있습니다." + +msgid "USB Port" +msgstr "USB 포트" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "USB 포트 변경은 Hermes cIOS에서만 지원됩니다." + +msgid "USB-HID Controller" +msgstr "USB-HID 컨트롤러" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "USBloaderGX가 닌텐돈트 boot.dol 파일을 확인할 수 없습니다. 이 boot.dol을 어쨓든 시작하겠습니까?" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "USBloaderGX는 닌텐돈트 구성 파일을 기록할 수 없습니다. 어쨓든 닌텐돈트를 시작하겠습니까?" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "USBloaderGX r1218은 닌텐돈트 알파 v0.1에 필요합니다. 닌텐돈트 boot.dol 버전을 업데이트하십시오." + +msgid "Uninstall" +msgstr "제거" + +msgid "Uninstall Game" +msgstr "게임 제거" + +msgid "Uninstall Menu" +msgstr "메뉴 제거" + +msgid "Uninstall all" +msgstr "모두 제거" + +msgid "Unknown" +msgstr "미확인" + +msgid "Unlock USB Loader GX" +msgstr "USB 로더 GX 잠금 해제" + +msgid "Unlocked" +msgstr "잠금 해제" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "지원되지 않는 형식인 경우 수동으로 TempTheme.zip를 추출하십시오." + +msgid "Update" +msgstr "업데이트" + +msgid "Update All" +msgstr "모두 업데이트" + +msgid "Update DOL" +msgstr "DOL 업데이트" + +msgid "Update Files" +msgstr "파일 업데이트" + +msgid "Update Path" +msgstr "경로 업데이트" + +msgid "Update all Language Files" +msgstr "모든 언어 파일 업데이트" + +msgid "Update failed" +msgstr "업데이트 실패" + +msgid "Update successfull" +msgstr "업데이트 성공" + +msgid "Updating Language Files:" +msgstr "언어 파일 업데이트:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "홈브류 디렉토리에 업로드 된 ZIP 파일을 업로드했습니다." + +msgid "Use System Font" +msgstr "시스템 폰트 사용" + +msgid "Use global" +msgstr "글로벌 사용" + +msgid "VBI (Default)" +msgstr "VBI (기본)" + +msgid "VIDTV Patch" +msgstr "VIDTV 패치" + +msgid "Version:" +msgstr "버전:" + +#, c-format +msgid "Version: %s" +msgstr "버전: %s" + +msgid "Video Deflicker" +msgstr "비디오 디플리커" + +msgid "Video Mode" +msgstr "비디오 모드" + +msgid "Video Scale Value" +msgstr "비디오 스케일 볼륨" + +msgid "Video offset" +msgstr "비디오 옵셋" + +msgid "Video scale" +msgstr "비디오 스케일" + +msgid "Virtual Pointer Speed" +msgstr "가상 포인터 속도" + +msgid "WDM Files Path" +msgstr "WDM 파일 경로" + +msgid "WIP Patches Path" +msgstr "WIP 패치 경로" + +msgid "Waiting..." +msgstr "기다리는 중 입니다..." + +msgid "Warning" +msgstr "경고" + +msgid "Warning:" +msgstr "경고:" + +msgid "What do you want to do?" +msgstr "뭐엇을 하고 싶습니까?" + +msgid "What do you want to update?" +msgstr "무엇을 업데이트 하겠습니까?" + +msgid "What should be deleted for this game title:" +msgstr "이 게임 타이틀에서 삭제해야 할 항목:" + +msgid "What to extract from NAND?" +msgstr "낸드에서 추출할 대상은 무엇입니까?" + +msgid "Where should the game be installed to?" +msgstr "게임을 어디에 설치해야 합니까?" + +msgid "Where to dump NAND?" +msgstr "낸드를 덤프할 곳은 어디입니까?" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "어떤 장치를 닌텐돈트 파일에 사용하겠습니까?" + +msgid "Which mode do you want to use?" +msgstr "어떤 모드를 사용 하겠습니까?" + +msgid "WiFi Features" +msgstr "와이파이 기능" + +msgid "Widescreen Factor" +msgstr "와이드스크린 펙터" + +msgid "Widescreen Fix" +msgstr "와이드스크린 수정" + +msgid "Wii Games" +msgstr "Wii 게임" + +msgid "Wii Menu" +msgstr "Wii 메뉴" + +msgid "Wii Settings" +msgstr "Wii 설정" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "WiiTDB.xml이 최신 상태입니다." + +msgid "WiiU Widescreen" +msgstr "WiiU 와이드스크린" + +msgid "Wiilight" +msgstr "" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "우승자태그" + +msgid "Wiinnertag Path" +msgstr "우승자태그 경로" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "우승자태그를 사용하려면 응용 프로그램 시작시 자동 네트워크 연결을 사용하도록 설정해야 합니다. 지금 사용 하시겠습니까?" + +msgid "Wiird Debugger" +msgstr "Wiird 디버거" + +#, c-format +msgid "Write error on file: %s" +msgstr "파일에 오류 쓰기: %s" + +msgid "Writing GXGameCategories.xml" +msgstr "GXGameCategories.xml 작성하기" + +msgid "Wrong Password" +msgstr "잘못된 비밀번호" + +msgid "Yes" +msgstr "예" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "cIOS 249 Rev.18 이하인 FAT32/NTFS/EXT 파티션을 선택하려고 합니다. 지원되지 않습니다. 위험을 감수하십시오." + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "파티션을 선택 또는 포맷하거나 채널 로더 모드를 사용할 수 있습니다." + +msgid "You cannot delete this category." +msgstr "이 카테고리는 삭제할 수 없습니다." + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "EmuNAND를 하위 폴더에서 로드하려면 neek2o가 필요합니다." + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "DIOS MIOS 라이트 v1.2 또는 최신 버전을 설치해야 합니다." + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "추가 게임큐브 로더를 설치하거나 다른 게임큐브 모드를 선택하여 USB 또는 SD 카드에서 게임큐브 게임을 시작해야 합니다." + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "현재 게임큐브 파티션은 호환되지 않습니다. 닌텐돈트를 업데이트 하십시오." + +msgid "Zoom Duration (Speed)" +msgstr "확대/축소 지속시간 (속도)" + +msgid "and translators for language files updates" +msgstr "그리고 언어 파일 업데이트를 위한 번역가" + +msgid "available" +msgstr "가능한" + +msgid "does not exist!" +msgstr "존재하지 않습니다!" + +msgid "does not exist! Loading game without cheats." +msgstr "존재하지 않습니다! 치트없이 게임 로드" + +msgid "files left" +msgstr "파일 남음" + +msgid "for FAT/NTFS support" +msgstr "FAT/NTFS 지원" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "GameTDB 및 호스팅 커버/디스크 이미지" + +msgid "for Ocarina" +msgstr "오카리나" + +msgid "for diverse patches" +msgstr "다양한 패치" + +msgid "for his awesome tool LibWiiGui" +msgstr "그의 멋진 도구 LibWiiGui" + +msgid "for hosting the themes" +msgstr "테마 호스팅" + +msgid "for the USB Loader source" +msgstr "USB 로더 소스" + +msgid "for their work on the wiki page" +msgstr "wiki 페이지에서의 작업" + +msgid "formatted!" +msgstr "포맷되었습니다!" + +msgid "free" +msgstr "여유" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "설정 안됨" + +msgid "of" +msgstr "의" + +msgid "seconds left" +msgstr "초 남음" \ No newline at end of file diff --git a/Languages/norwegian.lang b/Languages/norwegian.lang new file mode 100644 index 0000000..9b21dfd --- /dev/null +++ b/Languages/norwegian.lang @@ -0,0 +1,2655 @@ +# USB Loader GX language source file. +# norwegian.lang - r1097 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:05+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: raschi\n" +"Language-Team: raschi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " kan ikke lastes ned." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " har blitt lagret. Teksten har ikke blitt verifisert. Noe av koden vil kanskje ikke fungere riktig. Hvis du får problemer, åpne teksten i et ekte redigeringsprogram for mer informasjon." + +msgid " is not on the server." +msgstr " finnes ikke på serveren." + +#, c-format +msgid "%i files not found on the server!" +msgstr "%i filer ikke funnet på server!" + +#, c-format +msgid "%i missing files" +msgstr "%i filer mangler" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Alle)" + +msgid "1 (Child 7+)" +msgstr "1 (Barn 7+)" + +msgid "1 hour" +msgstr "1 time" + +msgid "10 min" +msgstr "" + +msgid "2 (Teen 12+)" +msgstr "2 (Ungdom 12+)" + +msgid "20 min" +msgstr "" + +msgid "2D Cover Path" +msgstr "2D Cover sti" + +msgid "3 (Mature 16+)" +msgstr "3 (Ungdom 16+)" + +msgid "3 min" +msgstr "" + +msgid "30 min" +msgstr "" + +msgid "3D Cover Path" +msgstr "3D Cover sti" + +msgid "3D Covers" +msgstr "3D cover" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Voksen 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "Legg til kategori" + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "Alle" + +msgid "All Partitions" +msgstr "Alle partisjoner" + +msgid "All files extracted." +msgstr "" + +msgid "All images downloaded successfully." +msgstr "Alle bilder lastet ned ok." + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Alle funksjonene til USB Loader GX er opplåst." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Alternativ DOL" + +msgid "An example file was created here:" +msgstr "En eksempelfil ble opprettet her:" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "Program språk" + +msgid "Apply" +msgstr "Bruk" + +msgid "Apr" +msgstr "" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "Er du sikker på at du vil slette denne kategorien?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "Er du sikker på at du vil låse USB Loader GX?" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "Er du sikker på at du vil restarte?" + +msgid "Are you sure?" +msgstr "Er du sikker?" + +msgid "Aspect Ratio" +msgstr "" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "" + +msgid "Author(s):" +msgstr "" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "Autostart nettverk" + +msgid "BCA Codes Path" +msgstr "BCA kode sti" + +msgid "Back" +msgstr "Tilbake" + +msgid "Back to HBC or Wii Menu" +msgstr "Tilbake til HBC eller Wii meny" + +msgid "Backgroundmusic" +msgstr "Bakgrunnsmusikk" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "Stor takk til:" + +msgid "Block Categories Menu" +msgstr "Blokkér kategorimeny" + +msgid "Block Categories Modify" +msgstr "Blokkér kategorimodifisering" + +msgid "Block Cover Downloads" +msgstr "Blokkér covernedlasting" + +msgid "Block Custom Paths" +msgstr "Blokkér egendefinerte stier" + +msgid "Block Feature Settings" +msgstr "Blokkér funksjonsinnstillinger" + +msgid "Block Game Install" +msgstr "Blokkér spillinstallering" + +msgid "Block Game Settings" +msgstr "Blokkér spillinnstillinger" + +msgid "Block GameID Change" +msgstr "Blokkér endring av SpillID" + +msgid "Block Global Settings" +msgstr "Blokkér globale innstillinger" + +msgid "Block Gui Settings" +msgstr "Blokkér GUI innstillinger" + +msgid "Block HBC Menu" +msgstr "Blokkér HBC meny" + +msgid "Block Hard Drive Settings" +msgstr "Blokkér harddisk innstillinger" + +msgid "Block IOS Reload" +msgstr "Blokkér IOS Reload" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "Blokkér loader innstillinger" + +msgid "Block Parental Settings" +msgstr "Blokkér foreldrekontroll" + +msgid "Block Priiloader Override" +msgstr "" + +msgid "Block Reset Settings" +msgstr "Blokkér reset innstillinger" + +msgid "Block SD Reload Button" +msgstr "Blokkér SD reload knapp" + +msgid "Block Sound Settings" +msgstr "Blokkér lydinnstillinger" + +msgid "Block Theme Downloader" +msgstr "Blokkér temanedlaster" + +msgid "Block Theme Menu" +msgstr "Blokkér temameny" + +msgid "Block Title Launcher" +msgstr "Blokkér title launcher" + +msgid "Block Updates" +msgstr "Blokkér oppdateringer" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "Start?" + +msgid "Both" +msgstr "Begge" + +msgid "Both Ports" +msgstr "Begge porter" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "Cache titler" + +msgid "Can't be formatted" +msgstr "Kan ikke formateres" + +msgid "Can't create directory" +msgstr "Kan ikke opprette mappe" + +#, c-format +msgid "Can't create file: %s" +msgstr "" + +#, c-format +msgid "Can't create path: %s" +msgstr "Kan ikke opprette sti: %s" + +msgid "Can't delete:" +msgstr "Kan ikke slette:" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "" + +#, c-format +msgid "Can't read file: %s" +msgstr "" + +msgid "Cancel" +msgstr "Avbryt" + +msgid "Cannot write to destination." +msgstr "Kan ikke skrive til mål." + +msgid "Categories" +msgstr "Kategorier" + +msgid "Categories:" +msgstr "Kategorier:" + +msgid "Change Play Path" +msgstr "Endre spill sti" + +msgid "Channel Launcher" +msgstr "" + +msgid "Channels" +msgstr "" + +msgid "Cheatfile is blank" +msgstr "Juksefil er tom" + +msgid "Clear" +msgstr "Fjern" + +msgid "Click to Download Covers" +msgstr "Klikk for å laste ned cover" + +msgid "Click to change game ID" +msgstr "Klikk for å endre spill ID" + +msgid "Clock" +msgstr "Klokke" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "Lukk" + +msgid "Code Download" +msgstr "Kode nedlasting" + +#, c-format +msgid "Coded by: %s" +msgstr "Kodet av: %s" + +msgid "Coding:" +msgstr "Koding:" + +msgid "Connection to server timed out." +msgstr "Servertilkobling timet ut." + +msgid "Console" +msgstr "Konsoll" + +msgid "Console Default" +msgstr "Konsoll Standard" + +msgid "Console Locked" +msgstr "Konsoll låst" + +msgid "Console must be unlocked for this option." +msgstr "Konsoll må være opplåst for denne innstillingen." + +msgid "Console must be unlocked to be able to use this." +msgstr "Konsoll må være opplåst for å bruke dette." + +msgid "Console should be unlocked to modify it." +msgstr "Konsoll må være opplåst for å modifisere." + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "Fortsett å installere spill?" + +msgid "Continue?" +msgstr "" + +msgid "Controllevel" +msgstr "Kontrollnivå" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "Riktig passord" + +msgid "Could not connect to the server." +msgstr "Kan ikke koble til server." + +msgid "Could not create GCT file" +msgstr "Kan ikke opprette GCT fil" + +#, c-format +msgid "Could not create path: %s" +msgstr "Kan ikke opprette sti: %s" + +msgid "Could not extract files for:" +msgstr "" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "Kan ikke finne info for dette spillet i wiitdb.xml." + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "Kan ikke initialisere DIP modul!" + +msgid "Could not initialize network!" +msgstr "Kan ikke initialisere nettverk!" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "Kan ikke åpne plate" + +msgid "Could not open the WiiTDB.xml file." +msgstr "Kan ikke åpne WiiTDB.xml fil." + +msgid "Could not open wiitdb.xml." +msgstr "Kan ikke åpne wiitdb.xml." + +msgid "Could not save." +msgstr "Kan ikke lagre." + +msgid "Could not write file." +msgstr "" + +msgid "Could not write to:" +msgstr "Kan ikke skrive til:" + +msgid "Cover Download" +msgstr "Cover nedlasting" + +msgid "Create" +msgstr "Opprett" + +msgid "Credits" +msgstr "Medvirkende" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "Egendefinerte stier" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "Custom/Original" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "DOL sti" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "Des" + +msgid "Default" +msgstr "Standard" + +msgid "Default Gamesettings" +msgstr "Standard innstillinger" + +msgid "Default Settings" +msgstr "Standard innstillinger" + +msgid "Delete" +msgstr "Slett" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "Slett juksefil GCT" + +msgid "Delete Cheat TXT" +msgstr "Slett juksefil TXT" + +msgid "Delete Cover Artwork" +msgstr "Slett cover" + +msgid "Delete Disc Artwork" +msgstr "Slett platebilde" + +msgid "Delete category" +msgstr "Slett kategori" + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "" + +msgid "Details" +msgstr "Detaljer" + +msgid "Developed by" +msgstr "Utviklet av" + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "Mappe finnes ikke!" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "Platebilde nedlasting" + +msgid "Disc Artwork Path" +msgstr "Platebilde sti" + +msgid "Disc Default" +msgstr "Spill Standard" + +msgid "Disc Insert Detected" +msgstr "" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "Snu plate" + +msgid "Display" +msgstr "Vis" + +msgid "Display as a carousel" +msgstr "Vis som karusell" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "Vis som rutemønster" + +msgid "Display as a list" +msgstr "Vis som liste" + +msgid "Display favorites only" +msgstr "Vis kun favoritter" + +msgid "Do you want to apply it now?" +msgstr "Vil du legge til nå?" + +msgid "Do you want to apply this theme?" +msgstr "Vil du aktivere dette temaet?" + +msgid "Do you want to change language?" +msgstr "Vil du endre språk?" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "Vil du laste ned dette temaet?" + +msgid "Do you want to extract all the save games?" +msgstr "" + +msgid "Do you want to extract the save game?" +msgstr "" + +msgid "Do you want to format:" +msgstr "Vil du formatere:" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "Vil du laste standard tema?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "Vil du synkronisere ledig plass info sektor på alle FAT32 partisjoner?" + +msgid "Do you wish to update/download all language files?" +msgstr "Vil du oppdatere/laste ned alle språkfiler?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "Last ned" + +msgid "Download Now" +msgstr "Last ned nå" + +msgid "Download finished" +msgstr "Nedlasting ferdig" + +msgid "Downloading 3D Covers" +msgstr "Laster ned 3D cover" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "Laster ned 2D cover" + +msgid "Downloading Full HQ Covers" +msgstr "Laster ned HQ fullcover" + +msgid "Downloading Full LQ Covers" +msgstr "Laster ned LQ fullcover" + +msgid "Downloading custom Discarts" +msgstr "Laster ned custom platebilde" + +msgid "Downloading file..." +msgstr "Laster ned fil..." + +msgid "Downloading image:" +msgstr "Laster ned bilde:" + +msgid "Downloading original Discarts" +msgstr "Laster ned originale platebilde" + +msgid "Downloading pagelist:" +msgstr "Laster ned sideliste:" + +msgid "Dump NAND to EmuNand" +msgstr "" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "Nederlandsk" + +msgid "ERROR" +msgstr "FEIL" + +msgid "ERROR:" +msgstr "FEIL:" + +msgid "ERROR: Can't set up theme." +msgstr "FEIL: Kan ikke laste tema." + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "" + +msgid "Emulated Nand" +msgstr "" + +msgid "English" +msgstr "Engelsk" + +msgid "Enter Path" +msgstr "" + +msgid "Error" +msgstr "Feil" + +msgid "Error !" +msgstr "Feil !" + +#, c-format +msgid "Error creating path: %s" +msgstr "Feil ved oppretting av sti: %s" + +msgid "Error opening downloaded file" +msgstr "Feil ved åpning av nedlastet fil" + +msgid "Error reading Disc" +msgstr "Feil ved lesing av plate" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "Feil ved nedlasting av fil: %i" + +msgid "Error while downloding file" +msgstr "Feil ved nedlasting av fil" + +msgid "Error while opening the zip." +msgstr "Feil ved åpning av zip." + +msgid "Error while transfering data." +msgstr "Feil ved overføring av data." + +msgid "Error while updating USB Loader GX." +msgstr "Feil ved oppdatering av USB Loader GX." + +msgid "Error writing the data." +msgstr "Feil ved skriving av data." + +msgid "Error:" +msgstr "Feil:" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "" + +msgid "Everything" +msgstr "" + +msgid "Exit" +msgstr "Avslutt" + +msgid "Exit to where?" +msgstr "Avslutt til?" + +msgid "Export All Saves to EmuNand" +msgstr "" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "" + +msgid "Extracting file:" +msgstr "" + +msgid "Extracting files..." +msgstr "Pakker ut filer..." + +msgid "Extracting files:" +msgstr "" + +msgid "Extracting nand files:" +msgstr "" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "Feilet" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "Feil ved formatering" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "" + +msgid "Failed to extract." +msgstr "Utpakking feilet." + +msgid "Failed to initialize the USB storage device." +msgstr "" + +msgid "Failed to open partition" +msgstr "Feil ved åpning av partisjon" + +msgid "Failed to read ticket." +msgstr "" + +msgid "Failed to read tmd file." +msgstr "" + +msgid "Failed to read wad header." +msgstr "" + +msgid "Failed updating" +msgstr "Feil ved oppdatering" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "Funksjoner" + +msgid "Features Settings" +msgstr "Funksjonsinnstillinger" + +msgid "Feb" +msgstr "" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Fil ikke funnet." + +msgid "File read/write error." +msgstr "" + +msgid "Files extracted successfully." +msgstr "" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "Filstørrelse er %i Byte." + +msgid "Filesize is 0 Byte." +msgstr "Filstørrelse er 0 Byte." + +msgid "Flat Covers" +msgstr "2D cover" + +msgid "Flip-X" +msgstr "" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "Tekst størrelsesfaktor" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "Tving NTSC" + +msgid "Force NTSC480p" +msgstr "Tving NTSC480p" + +msgid "Force PAL480p" +msgstr "Tving PAL480p" + +msgid "Force PAL50" +msgstr "Tving PAL50" + +msgid "Force PAL60" +msgstr "Tving PAL60" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Formatér" + +msgid "Formatting, please wait..." +msgstr "Formaterer, vennligst vent..." + +msgid "Found missing images." +msgstr "Funnet manglende bilder." + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "Ledig plass" + +msgid "French" +msgstr "Fransk" + +msgid "Full" +msgstr "" + +msgid "Full Cover Path" +msgstr "Fullcover sti" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "Skru helt av" + +msgid "GAMEID_Gamename" +msgstr "SPILLID_Spillnavn" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "GCT Juksekode sti" + +msgid "GCT File created" +msgstr "GCT fil opprettet" + +msgid "GUI Settings" +msgstr "GUI innstillinger" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "Spill ID" + +msgid "Game IOS" +msgstr "Spill IOS" + +msgid "Game Language" +msgstr "Språk" + +msgid "Game Load" +msgstr "Lasting av spill" + +msgid "Game Lock" +msgstr "Lås spill" + +msgid "Game Only" +msgstr "Kun spill" + +msgid "Game Region" +msgstr "Region" + +msgid "Game Size" +msgstr "Spill størrelse" + +msgid "Game Sound Mode" +msgstr "Spillyd modus" + +msgid "Game Sound Volume" +msgstr "Spillyd volum" + +msgid "Game Split Size" +msgstr "Spill splittestørrelse" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "Spillet er allerede installert:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "Spill/installer partisjon" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "Spillnavn [SPILLID]" + +msgid "Games" +msgstr "Spill" + +msgid "Generating GXGameCategories.xml" +msgstr "Genererer GXGameCategories.xml" + +msgid "Genre:" +msgstr "Sjanger:" + +msgid "German" +msgstr "Tysk" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "Globale innstillinger" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "HOME Meny" + +msgid "Hard Drive Settings" +msgstr "Harddisk innstillinger" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "Homebrew Apps sti" + +msgid "Homebrew Channel" +msgstr "HBC" + +msgid "Homebrew Launcher" +msgstr "Homebrew Laster" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "Timer" + +msgid "How do you want to update?" +msgstr "Hvordan vil du oppdatere?" + +msgid "How to Shutdown?" +msgstr "Hvordan skru av?" + +msgid "Import Categories" +msgstr "Importer kategorier" + +msgid "Import operation successfully completed." +msgstr "Vellykket importering." + +msgid "Importing categories" +msgstr "Importerer kategorier" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Laster ned fil %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Laster ned fil %0.2fMB" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "Initialiserer nettverk" + +msgid "Insert Disk" +msgstr "Sett inn plate" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "Installér" + +msgid "Install Canceled" +msgstr "" + +msgid "Install Directories" +msgstr "Installer mapper" + +msgid "Install Error!" +msgstr "Installasjonsfeil!" + +msgid "Install Partitions" +msgstr "Installer partisjoner" + +msgid "Install a game" +msgstr "Installér et spill" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "" + +msgid "Installing game:" +msgstr "Installerer spill:" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Det ser ut til at du har informasjon som kan være nyttig for oss. Vennligst videresend denne informasjonen til utviklerteamet." + +msgid "Italian" +msgstr "Italiensk" + +msgid "Jan" +msgstr "" + +msgid "Japanese" +msgstr "Japansk" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "Jul" + +msgid "June" +msgstr "Jun" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Tastatur" + +msgid "Korean" +msgstr "Koreansk" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "" + +msgid "Language change:" +msgstr "Endre språk:" + +msgid "Languagefiles Path" +msgstr "Språkfil sti" + +msgid "Languagepath changed." +msgstr "Språksti endret." + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Left" +msgstr "Venstre" + +msgid "Like SysMenu" +msgstr "Lik Systemmeny" + +msgid "List on Gamelaunch" +msgstr "Liste ved starting av spill" + +msgid "Load" +msgstr "Start" + +msgid "Load From SD/USB" +msgstr "Start fra SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Start fil fra: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Last denne DOL som alternativ DOL?" + +msgid "Loader Settings" +msgstr "Loader innstillinger" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "Laster standard språk." + +msgid "Loading standard music." +msgstr "Laster standard musikk." + +msgid "Lock Console" +msgstr "Lås konsoll" + +msgid "Lock USB Loader GX" +msgstr "Lås USB Loader GX" + +msgid "Locked" +msgstr "Låst" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "Loop mappe" + +msgid "Loop Music" +msgstr "Loop musikk" + +msgid "Loop Sound" +msgstr "Loop lyd" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "" + +msgid "Mark new games" +msgstr "Merk nye spill" + +msgid "May" +msgstr "Mai" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "Messageboard oppdatering" + +msgid "Motion+ Video" +msgstr "Motion+ film" + +msgid "Mount DVD drive" +msgstr "Last DVD stasjon" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "Flere partisjoner" + +msgid "Music Loop Mode" +msgstr "Musikk loop modus" + +msgid "Music Volume" +msgstr "Musikk volum" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "" + +msgid "Nand Channels" +msgstr "" + +msgid "Nand Emu Channel Path" +msgstr "" + +msgid "Nand Emu Path" +msgstr "" + +msgid "Nand Emulation" +msgstr "" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Ingen" + +msgid "Network is not initiated." +msgstr "Nettverk er ikke initialisert." + +msgid "Next" +msgstr "Neste" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "Nei" + +msgid "No Cheatfile found" +msgstr "Ingen juksefil funnet" + +msgid "No DOL file found on disc." +msgstr "Ingen DOL fil funnet på plate." + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "Ingen splitt" + +msgid "No URL or Path specified." +msgstr "Ingen URL eller sti spesifisert." + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "Ingen WBFS eller FAT/NTFS/EXT partisjon funnet" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "Ingen Wiinnertag.xml funnet. Vil du opprette en eksempelfil?" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "Ingen data kan leses." + +msgid "No disc inserted." +msgstr "" + +msgid "No favorites selected." +msgstr "Ingen favoritter valgt." + +msgid "No file missing!" +msgstr "Ingen filer mangler!" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "" + +msgid "No new updates." +msgstr "Ingen nye oppdateringer." + +msgid "No themes found on the site." +msgstr "Ingen temaer funnet på websiden." + +msgid "No themes found." +msgstr "Ingen temaer funnet." + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "Ingen" + +msgid "Normal" +msgstr "" + +msgid "Not Initialized" +msgstr "" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "Ikke en gyldig URL" + +msgid "Not a valid URL path" +msgstr "Ikke en gyldig URL sti" + +msgid "Not a valid domain" +msgstr "Ikke et gyldig domene" + +msgid "Not enough free memory." +msgstr "Ikke nok ledig minne." + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "Ikke nok ledig plass!" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "Ikke nok minne." + +msgid "Not required" +msgstr "Ikke nødvendig" + +msgid "Not supported format!" +msgstr "Ikke et støttet format!" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "" + +msgid "OFF" +msgstr "AV" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "PÅ" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Okt" + +msgid "Official Site:" +msgstr "Offisiell nettside:" + +msgid "Offset" +msgstr "" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "Kun spill partisjon" + +msgid "Only for Install" +msgstr "Kun for installering" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Original/Custom" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Foreldrekontroll" + +msgid "Partial" +msgstr "" + +msgid "Partition" +msgstr "Partisjon" + +msgid "Password" +msgstr "Passord" + +msgid "Password Changed" +msgstr "Passord endret" + +msgid "Password has been changed" +msgstr "Passord har blitt endret" + +msgid "Patch Country Strings" +msgstr "Patch land strenger" + +msgid "Path Changed" +msgstr "Sti endret" + +msgid "Permission denied." +msgstr "Ingen tilgang." + +msgid "Pick from a list" +msgstr "Velg fra liste" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Ganger spilt" + +msgid "Play Next" +msgstr "Spill neste" + +msgid "Play Once" +msgstr "Spill en gang" + +msgid "Play Previous" +msgstr "Spill forrige" + +msgid "Playing Music:" +msgstr "Spiller musikk:" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "Vennligst vent..." + +msgid "Power off the Wii" +msgstr "Skru av Wii" + +msgid "Prev" +msgstr "Forrige" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Dialog knapper" + +msgid "Published by" +msgstr "Publisert av" + +msgid "Quick Boot" +msgstr "Hurtig start" + +msgid "Random Directory Music" +msgstr "Tilfeldig musikk fra mappe" + +msgid "Real Nand" +msgstr "" + +msgid "Receiving file from:" +msgstr "Mottar fil fra:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "" + +msgid "Released" +msgstr "Utgitt" + +msgid "Reload SD" +msgstr "Les SD på nytt" + +msgid "Reloading game list now, please wait..." +msgstr "" + +msgid "Remember Unlock" +msgstr "" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "Fjern oppdatering" + +msgid "Rename Game Title" +msgstr "" + +msgid "Rename category" +msgstr "Gi nytt navn til kategori" + +msgid "Reset" +msgstr "Tilbakestill" + +msgid "Reset BG Music" +msgstr "Tilbakestill BG musikk" + +msgid "Reset Playcounter" +msgstr "Nullstill teller" + +msgid "Reset to default BGM?" +msgstr "Tilbakestill til standard BGM?" + +msgid "Restarting..." +msgstr "Starter på nytt..." + +msgid "Return" +msgstr "Gå tilbake" + +msgid "Return To" +msgstr "Gå tilbake til" + +msgid "Return to Wii Menu" +msgstr "Tilbake til Wii meny" + +msgid "Right" +msgstr "Høyre" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Vibrasjon" + +msgid "SChinese" +msgstr "S.Kinesisk" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "Effekt volum" + +msgid "Save" +msgstr "Lagre" + +msgid "Save Failed. No device inserted?" +msgstr "Feil ved lagring. Ingen enhet koblet til?" + +msgid "Save Game List to" +msgstr "Lagre spilliste som" + +msgid "Save List" +msgstr "Lagre liste" + +msgid "Saved" +msgstr "Lagret" + +msgid "Savegame might not exist for this game." +msgstr "" + +msgid "Screensaver" +msgstr "Skjermbeskytter" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "Velg" + +msgid "Select DOL Offset" +msgstr "Velg DOL offset" + +msgid "Select a DOL" +msgstr "Velg en DOL fil" + +msgid "Select a DOL from Game" +msgstr "Velg en DOL fra spill" + +msgid "Select game categories" +msgstr "Velg spillkategorier" + +msgid "Select loader mode" +msgstr "" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "" + +msgid "Sept" +msgstr "Sep" + +msgid "Set Search-Filter" +msgstr "Angi søkefilter" + +msgid "Settings" +msgstr "Innstillinger" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "Vis kategorier" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "Vis ledig plass" + +msgid "Show Play Count" +msgstr "" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "Skru helt av" + +msgid "Shutdown Wii" +msgstr "Skru av Wii" + +msgid "Skip Errors" +msgstr "" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Sortér alfabetisk" + +msgid "Sort by number of players" +msgstr "Sortér etter antall spillere" + +msgid "Sort by rank" +msgstr "Sortér etter rangering" + +msgid "Sort order by most played" +msgstr "Sortér etter ganger spilt" + +msgid "Sound" +msgstr "Lyd" + +msgid "Sound Settings" +msgstr "Lyd innstillinger" + +msgid "Sound+BGM" +msgstr "Lyd+BGM" + +msgid "Sound+Quiet" +msgstr "Lyd+Stille" + +msgid "Spanish" +msgstr "Spansk" + +msgid "Special thanks to:" +msgstr "Spesielt takk til:" + +msgid "Split each 2GB" +msgstr "Splitt ved 2GB" + +msgid "Split each 4GB" +msgstr "Splitt ved 4GB" + +msgid "Standby" +msgstr "Hvilemodus" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "Suksess" + +msgid "Success." +msgstr "" + +msgid "Success:" +msgstr "Suksess:" + +msgid "Successfully Saved" +msgstr "Vellykket lagring" + +msgid "Successfully Updated" +msgstr "Vellykket oppdatering" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "Vellykket sletting:" + +msgid "Successfully extracted theme." +msgstr "Vellykket utpakking av tema." + +msgid "Successfully installed:" +msgstr "Vellykket installering:" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "" + +msgid "Sync FAT32 FS Info" +msgstr "Synkroniser FAT32 FS info" + +msgid "Synchronizing..." +msgstr "Synkroniserer..." + +msgid "System Default" +msgstr "System Standard" + +msgid "TChinese" +msgstr "T.Kinesisk" + +msgid "TXT Cheatcodes Path" +msgstr "TXTjuksekode sti" + +msgid "The .them file was not found in the zip." +msgstr "Filen .them ble ikke funnet i zip." + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "Valgt mappe finnes ikke. Vil du opprette den?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "WAD filen ble installert" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "WAD innstallering feilet med feilmelding %i" + +msgid "Theme Downloader" +msgstr "Tema Nedlaster" + +msgid "Theme Menu" +msgstr "Tema meny" + +msgid "Theme Path" +msgstr "Tema sti" + +msgid "Theme Title:" +msgstr "Tema tittel:" + +msgid "Themes by www.spiffy360.com" +msgstr "Tema fra www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "Dette IOS er vanligvis BootMii IOS. Hvis du er sikker på at dette ikke er BootMii, kan du ignorere denne advarselen." + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "Dette IOS ble ikke funnet i tittel listen. Hvis du er sikker på at du har det installert, kan du ignorere denne advarselen." + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "Tid igjen:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Tittel Laster" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "Verktøystips" + +msgid "Transfer failed" +msgstr "Overføring feilet" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX er beskyttet" + +msgid "USB Port" +msgstr "USB port" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "Endring av USB port er kun støttet under Hermes cIOS." + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "" + +msgid "Uninstall Game" +msgstr "Avinstallér spill" + +msgid "Uninstall Menu" +msgstr "Avinstallér Meny" + +msgid "Uninstall all" +msgstr "Avistallér alle" + +msgid "Unknown" +msgstr "Ukjent" + +msgid "Unlock USB Loader GX" +msgstr "Lås opp USB Loader GX" + +msgid "Unlocked" +msgstr "Opplåst" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "Ikke støttet format. Prøv å pakk ut TempTheme.zip manuelt." + +msgid "Update" +msgstr "Oppdater" + +msgid "Update All" +msgstr "Oppdater alt" + +msgid "Update DOL" +msgstr "Oppdater DOL" + +msgid "Update Files" +msgstr "Oppdater filer" + +msgid "Update Path" +msgstr "Oppdatering sti" + +msgid "Update all Language Files" +msgstr "Oppdater alle språkfiler" + +msgid "Update failed" +msgstr "Mislykket oppdatering" + +msgid "Update successfull" +msgstr "Vellykket oppdatering" + +msgid "Updating Language Files:" +msgstr "Oppdaterer språkfiler:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Opplastet ZIP fil installert i homebrew mappen." + +msgid "Use System Font" +msgstr "" + +msgid "Use global" +msgstr "Bruk global" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "" + +msgid "Version:" +msgstr "Versjon:" + +#, c-format +msgid "Version: %s" +msgstr "Versjon: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Video modus" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "" + +msgid "WDM Files Path" +msgstr "WDM sti" + +msgid "WIP Patches Path" +msgstr "WIP patches sti" + +msgid "Waiting..." +msgstr "Venter..." + +msgid "Warning" +msgstr "Advarsel" + +msgid "Warning:" +msgstr "Advarsel:" + +msgid "What do you want to do?" +msgstr "" + +msgid "What do you want to update?" +msgstr "Hva vil du oppdatere?" + +msgid "What should be deleted for this game title:" +msgstr "Hva skal slettes for denne spilltittel:" + +msgid "What to extract from NAND?" +msgstr "" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "WiFi egenskaper" + +msgid "Widescreen Factor" +msgstr "Widescreen faktor" + +msgid "Widescreen Fix" +msgstr "Widescreen fiks" + +msgid "Wii Games" +msgstr "" + +msgid "Wii Menu" +msgstr "Wii Meny" + +msgid "Wii Settings" +msgstr "Wii Innstillinger" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "Wii DVD lys" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "Wiinnertag sti" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Wiinnertag krever at du aktiverer automatisk nettverkstilkobling ved oppstart. Vil du aktivere denne nå?" + +msgid "Wiird Debugger" +msgstr "" + +#, c-format +msgid "Write error on file: %s" +msgstr "" + +msgid "Writing GXGameCategories.xml" +msgstr "Oppretter GXGameCategories.xml" + +msgid "Wrong Password" +msgstr "Feil passord" + +msgid "Yes" +msgstr "Ja" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "Du prøver å velge en FAT32/NTFS/EXT partisjon med cIOS 249 rev < 18. Dette er ikke støttet. Fortsett på eget ansvar." + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "" + +msgid "You cannot delete this category." +msgstr "Du kan ikke slette denne kategori." + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "og oversettere for språkfiler" + +msgid "available" +msgstr "tilgjengelig" + +msgid "does not exist!" +msgstr "finnes ikke!" + +msgid "does not exist! Loading game without cheats." +msgstr "finnes ikke! Laster spill uten juksekode." + +msgid "files left" +msgstr "filer gjenstår" + +msgid "for FAT/NTFS support" +msgstr "for FAT/NTFS støtte" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "" + +msgid "for Ocarina" +msgstr "" + +msgid "for diverse patches" +msgstr "for diverse patcher" + +msgid "for his awesome tool LibWiiGui" +msgstr "for hans råe verktøy LibWiiGui" + +msgid "for hosting the themes" +msgstr "for hosting av tema" + +msgid "for the USB Loader source" +msgstr "for kilden til USB Loader" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "formatert!" + +msgid "free" +msgstr "ledig" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "ikke satt" + +msgid "of" +msgstr "av" + +msgid "seconds left" +msgstr "sekunder gjenstår" + +#~ msgid "Error 002 fix" +#~ msgstr "Error 002 fiks" + +#~ msgid "Main tester:" +#~ msgstr "Hovedtester:" + +#~ msgid "Boot/Standard" +#~ msgstr "Boot/Standard" + +#~ msgid "Custom Discarts" +#~ msgstr "Cust. platebilde" + +#~ msgid "Full HQ Covers" +#~ msgstr "HQ fullcover" + +#~ msgid "Full LQ Covers" +#~ msgstr "LQ fullcover" + +#~ msgid "Original Discarts" +#~ msgstr "Orig. platebilde" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "Gi nytt navn til spill på WBFS" + +#~ msgid "Successfully Updated thanks to www.techjawa.com" +#~ msgstr "Vellykket oppdatering takket være www.techjawa.com" + +#~ msgid "for hosting the update files" +#~ msgstr "for hosting av oppdateringer" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Sett inn en Wii plate!" + +#~ msgid "Issue manager /" +#~ msgstr "Problem manager /" + +#~ msgid "No cheats were selected" +#~ msgstr "Ingen juksefiler valgt" + +#~ msgid "Not a Wii Disc" +#~ msgstr "Ikke en Wii plate" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> Sletter tickets..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> Sletter tickets...FEIL! " + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> Sletter tickets...OK! " + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> Sletter tittel ...FEIL! " + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> Sletter tittel ...OK!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> Sletter tittel innhold..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> Sletter tittel innhold...FEIL! " + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> Sletter tittel innhold...OK!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> Sletter tittel..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> Fullfører installasjon..." + +#~ msgid ">> Installing content #" +#~ msgstr ">> Installerer innhold #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> Installerer ticket..." + +#~ msgid ">> Installing title..." +#~ msgstr ">> Installerer tittel..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> Leser WAD data..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> Leser WAD data...FEIL! " + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> Leser WAD data...OK!" + +#~ msgid "Done!" +#~ msgstr "Ferdig!" + +#~ msgid "Error..." +#~ msgstr "Feil..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "Sluttfører installasjon... OK!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "Installerer innhold... OK!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "Installerer ticket... OK!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "Installerer tittel... OK!" + +#~ msgid "Installing wad" +#~ msgstr "Installerer WAD" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "Leser WAD data... OK!" + +#~ msgid "Uninstalling wad" +#~ msgstr "Avinstallerer WAD" + +#~ msgid "The game installation is disabled under this IOS because of instability in usb write." +#~ msgstr "Spillinstallasjon er deaktivert under dette IOS pga ustabilitet ved skriving til USB." + +#~ msgid "You are currently using IOS" +#~ msgstr "Du bruker IOS" + +#~ msgid "New Disc Detected" +#~ msgstr "Ny plate oppdaget" + +#~ msgid "USB Device not found" +#~ msgstr "USB enhet ikke funnet" + +#~ msgid "You need to select or format a partition" +#~ msgstr "Du må velge en partisjon" + +#~ msgid "Language File" +#~ msgstr "Språk Fil" + +#~ msgid "Are you sure you want to import game categories from WiiTDB?" +#~ msgstr "Er du sikker på at du vil importere kategorier fra WiiTDB?" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Titler fra WiiTDB" + +#~ msgid "WiiTDB Files" +#~ msgstr "WiiTDB filer" + +#~ msgid "WiiTDB Path" +#~ msgstr "WiiTDB sti" + +#~ msgid "WiiTDB is up to date." +#~ msgstr "WiiTDB er oppdatert." + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "for WiiTDB og hosting av bilder" diff --git a/Languages/polish.lang b/Languages/polish.lang new file mode 100644 index 0000000..a5123cb --- /dev/null +++ b/Languages/polish.lang @@ -0,0 +1,2931 @@ +# USB Loader GX language source file. +# polish.lang - r899 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:05+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: ziom666 (zadania_prog@vp.pl)\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " nie udalo sie pobrac" + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " zapisano. Plik tekstowy nie zostal zweryfikowany. Niektore z kodow, moga nie dzialac wlaeciwie z innymi. W razie problemow otworz plik tekstowy w edytorze na komputerze" + +msgid " is not on the server." +msgstr " nie istnieje na serwerze" + +#, c-format +msgid "%i files not found on the server!" +msgstr "" + +#, c-format +msgid "%i missing files" +msgstr "" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (dla kazdego)" + +msgid "1 (Child 7+)" +msgstr "1 (dziecko 7+)" + +msgid "1 hour" +msgstr "1 godzina" + +msgid "10 min" +msgstr "" + +msgid "2 (Teen 12+)" +msgstr "2 (mlodziez 12+)" + +msgid "20 min" +msgstr "" + +msgid "2D Cover Path" +msgstr "Sciezka okladek 2D" + +msgid "3 (Mature 16+)" +msgstr "3 (dojrzaly 16+)" + +msgid "3 min" +msgstr "" + +msgid "30 min" +msgstr "" + +msgid "3D Cover Path" +msgstr "Sciezka okladek 3D" + +msgid "3D Covers" +msgstr "Okladki 3D" + +msgid "4 (Adults Only 18+)" +msgstr "4 (tylko dla doroslych 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "automatycznie" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "" + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "" + +msgid "All Partitions" +msgstr "" + +msgid "All files extracted." +msgstr "" + +msgid "All images downloaded successfully." +msgstr "" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "USB Loader GX odblokowany" + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Alternatywny DOL" + +msgid "An example file was created here:" +msgstr "" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "Jezyk" + +msgid "Apply" +msgstr "" + +msgid "Apr" +msgstr "Kwiecien" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "" + +msgid "Are you sure?" +msgstr "Na pewno?" + +msgid "Aspect Ratio" +msgstr "" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "Sierpien" + +msgid "Author(s):" +msgstr "" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "Autoinicjalizacja sieci" + +msgid "BCA Codes Path" +msgstr "Sciezka kodow BCA" + +msgid "Back" +msgstr "Cofnij" + +msgid "Back to HBC or Wii Menu" +msgstr "Powrot do HBC/Wii Menu" + +msgid "Backgroundmusic" +msgstr "Muzyka w tle" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "Podziekowania dla" + +msgid "Block Categories Menu" +msgstr "" + +msgid "Block Categories Modify" +msgstr "" + +msgid "Block Cover Downloads" +msgstr "" + +msgid "Block Custom Paths" +msgstr "" + +msgid "Block Feature Settings" +msgstr "" + +msgid "Block Game Install" +msgstr "" + +msgid "Block Game Settings" +msgstr "" + +msgid "Block GameID Change" +msgstr "" + +msgid "Block Global Settings" +msgstr "" + +msgid "Block Gui Settings" +msgstr "" + +msgid "Block HBC Menu" +msgstr "" + +msgid "Block Hard Drive Settings" +msgstr "" + +msgid "Block IOS Reload" +msgstr "Blokoj przeladowanie IOS" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "" + +msgid "Block Parental Settings" +msgstr "" + +msgid "Block Priiloader Override" +msgstr "" + +msgid "Block Reset Settings" +msgstr "" + +msgid "Block SD Reload Button" +msgstr "" + +msgid "Block Sound Settings" +msgstr "" + +msgid "Block Theme Downloader" +msgstr "" + +msgid "Block Theme Menu" +msgstr "" + +msgid "Block Title Launcher" +msgstr "" + +msgid "Block Updates" +msgstr "" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "" + +msgid "Both" +msgstr "Oba" + +msgid "Both Ports" +msgstr "" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "" + +msgid "Can't be formatted" +msgstr "Nie mozna sformatowac" + +msgid "Can't create directory" +msgstr "Nie mozna utworzyc folderu" + +#, c-format +msgid "Can't create file: %s" +msgstr "" + +#, c-format +msgid "Can't create path: %s" +msgstr "" + +msgid "Can't delete:" +msgstr "Nie mozna usunac" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "" + +#, c-format +msgid "Can't read file: %s" +msgstr "" + +msgid "Cancel" +msgstr "Anuluj" + +msgid "Cannot write to destination." +msgstr "" + +msgid "Categories" +msgstr "" + +msgid "Categories:" +msgstr "" + +msgid "Change Play Path" +msgstr "" + +msgid "Channel Launcher" +msgstr "" + +msgid "Channels" +msgstr "Kanaly" + +msgid "Cheatfile is blank" +msgstr "Plik z kodami pusty" + +msgid "Clear" +msgstr "" + +msgid "Click to Download Covers" +msgstr "Kliknij aby pobrac okladki" + +msgid "Click to change game ID" +msgstr "Kliknij zeby zmienic ID gry" + +msgid "Clock" +msgstr "Zegar" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "Zamknij" + +msgid "Code Download" +msgstr "Pobierz kody" + +#, c-format +msgid "Coded by: %s" +msgstr "" + +msgid "Coding:" +msgstr "" + +msgid "Connection to server timed out." +msgstr "" + +msgid "Console" +msgstr "Konsola" + +msgid "Console Default" +msgstr "Domyslne ustawienia konsoli" + +msgid "Console Locked" +msgstr "Konsola zablokowana" + +msgid "Console must be unlocked for this option." +msgstr "" + +msgid "Console must be unlocked to be able to use this." +msgstr "" + +msgid "Console should be unlocked to modify it." +msgstr "Aby zmodyfikowac, odblokuj konsole" + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "Kontynuowac instalacje?" + +msgid "Continue?" +msgstr "" + +msgid "Controllevel" +msgstr "Poziom kontroli" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "Haslo poprawne" + +msgid "Could not connect to the server." +msgstr "" + +msgid "Could not create GCT file" +msgstr "Nie udalo sie stworzyc pliku GCT" + +#, c-format +msgid "Could not create path: %s" +msgstr "" + +msgid "Could not extract files for:" +msgstr "" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "" + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "Nie zainicjalizowano modulu DIP!" + +msgid "Could not initialize network!" +msgstr "Nie zainicjalizowano sieci!" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "Nie udalo sie otworzyc dysku" + +msgid "Could not open the WiiTDB.xml file." +msgstr "" + +msgid "Could not open wiitdb.xml." +msgstr "" + +msgid "Could not save." +msgstr "Nie mozna zapisac" + +msgid "Could not write file." +msgstr "" + +msgid "Could not write to:" +msgstr "" + +msgid "Cover Download" +msgstr "Pobierz okladki" + +msgid "Create" +msgstr "Utworz" + +msgid "Credits" +msgstr "" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "Sciezki" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "Sciezka plikow .DOL" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "Grudzien" + +msgid "Default" +msgstr "Ustawienia domyslne" + +msgid "Default Gamesettings" +msgstr "Domyslne ustawienia gier" + +msgid "Default Settings" +msgstr "Domyslne ustawienia" + +msgid "Delete" +msgstr "Usun" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "Usun plik z kodami GCT" + +msgid "Delete Cheat TXT" +msgstr "Usun plik z kodami TXT" + +msgid "Delete Cover Artwork" +msgstr "Usun obrazki box" + +msgid "Delete Disc Artwork" +msgstr "Usun obrazki plyt" + +msgid "Delete category" +msgstr "" + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "Projekt:" + +msgid "Details" +msgstr "" + +msgid "Developed by" +msgstr "" + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "Katalog nie istnieje!" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "Pobierz obrazki" + +msgid "Disc Artwork Path" +msgstr "Sciezka do obrazkow plyt" + +msgid "Disc Default" +msgstr "Domyslny dysk" + +msgid "Disc Insert Detected" +msgstr "" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "Obrot plytami" + +msgid "Display" +msgstr "Wyswietl" + +msgid "Display as a carousel" +msgstr "Wyswietl jako karuzele" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "Wyswietl jako siatke" + +msgid "Display as a list" +msgstr "Wyswietl jako liste" + +msgid "Display favorites only" +msgstr "" + +msgid "Do you want to apply it now?" +msgstr "Czy chcesz to teraz zastosowac?" + +msgid "Do you want to apply this theme?" +msgstr "" + +msgid "Do you want to change language?" +msgstr "Zmienic jezyk?" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "Pobrac temat?" + +msgid "Do you want to extract all the save games?" +msgstr "" + +msgid "Do you want to extract the save game?" +msgstr "" + +msgid "Do you want to format:" +msgstr "Sformatowac:" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "" + +msgid "Do you wish to update/download all language files?" +msgstr "Zaktualizowac wszystkie pliki jezykowe?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "Pobierz" + +msgid "Download Now" +msgstr "Pobierz teraz" + +msgid "Download finished" +msgstr "Zakonczono pobieranie" + +msgid "Downloading 3D Covers" +msgstr "" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "" + +msgid "Downloading Full HQ Covers" +msgstr "" + +msgid "Downloading Full LQ Covers" +msgstr "" + +msgid "Downloading custom Discarts" +msgstr "" + +msgid "Downloading file..." +msgstr "" + +msgid "Downloading image:" +msgstr "Pobieranie obrazka:" + +msgid "Downloading original Discarts" +msgstr "" + +msgid "Downloading pagelist:" +msgstr "" + +msgid "Dump NAND to EmuNand" +msgstr "" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "holenderski" + +msgid "ERROR" +msgstr "Blad" + +msgid "ERROR:" +msgstr "Blad:" + +msgid "ERROR: Can't set up theme." +msgstr "Blad: nie mozna ustawic tematu" + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "" + +msgid "Emulated Nand" +msgstr "" + +msgid "English" +msgstr "angielski" + +msgid "Enter Path" +msgstr "" + +msgid "Error" +msgstr "Blad" + +msgid "Error !" +msgstr "Blad !" + +#, c-format +msgid "Error creating path: %s" +msgstr "" + +msgid "Error opening downloaded file" +msgstr "" + +msgid "Error reading Disc" +msgstr "Blad odczytu plyty" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "" + +msgid "Error while downloding file" +msgstr "" + +msgid "Error while opening the zip." +msgstr "" + +msgid "Error while transfering data." +msgstr "Blad podczas transferu danych" + +msgid "Error while updating USB Loader GX." +msgstr "" + +msgid "Error writing the data." +msgstr "" + +msgid "Error:" +msgstr "Blad:" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "" + +msgid "Everything" +msgstr "" + +msgid "Exit" +msgstr "" + +msgid "Exit to where?" +msgstr "" + +msgid "Export All Saves to EmuNand" +msgstr "" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "" + +msgid "Extracting file:" +msgstr "" + +msgid "Extracting files..." +msgstr "Rozpakowywanie plikow..." + +msgid "Extracting files:" +msgstr "" + +msgid "Extracting nand files:" +msgstr "" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "Nie udalo sie sformatowac" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "" + +msgid "Failed to extract." +msgstr "Nie udalo sie rozpakowac" + +msgid "Failed to initialize the USB storage device." +msgstr "" + +msgid "Failed to open partition" +msgstr "Nie udalo sie otworzyc partycji" + +msgid "Failed to read ticket." +msgstr "" + +msgid "Failed to read tmd file." +msgstr "" + +msgid "Failed to read wad header." +msgstr "" + +msgid "Failed updating" +msgstr "" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "" + +msgid "Features Settings" +msgstr "" + +msgid "Feb" +msgstr "Luty" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Nie znaleziono pliku." + +msgid "File read/write error." +msgstr "" + +msgid "Files extracted successfully." +msgstr "" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "" + +msgid "Filesize is 0 Byte." +msgstr "" + +msgid "Flat Covers" +msgstr "" + +msgid "Flip-X" +msgstr "Obrot na osi X" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "" + +msgid "Force NTSC480p" +msgstr "" + +msgid "Force PAL480p" +msgstr "" + +msgid "Force PAL50" +msgstr "" + +msgid "Force PAL60" +msgstr "" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Sformatuj" + +msgid "Formatting, please wait..." +msgstr "Formatowanie, prosze czekac..." + +msgid "Found missing images." +msgstr "" + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "Wolnego miejsca" + +msgid "French" +msgstr "francuski" + +msgid "Full" +msgstr "" + +msgid "Full Cover Path" +msgstr "" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "" + +msgid "GAMEID_Gamename" +msgstr "" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "Sciezka kodow GCT" + +msgid "GCT File created" +msgstr "Utworzono plik GCT" + +msgid "GUI Settings" +msgstr "Ustawienia interfejsu graficznego" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "ID gry" + +msgid "Game IOS" +msgstr "" + +msgid "Game Language" +msgstr "Jezyk gry" + +msgid "Game Load" +msgstr "Zaladuj gre" + +msgid "Game Lock" +msgstr "" + +msgid "Game Only" +msgstr "" + +msgid "Game Region" +msgstr "Region" + +msgid "Game Size" +msgstr "Rozmiar gry" + +msgid "Game Sound Mode" +msgstr "Tryb dzwieku gry" + +msgid "Game Sound Volume" +msgstr "Gloscnosc dzwieku gry" + +msgid "Game Split Size" +msgstr "" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "Gra jest juz zainstalowana:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "" + +msgid "Games" +msgstr "Liczba gier" + +msgid "Generating GXGameCategories.xml" +msgstr "" + +msgid "Genre:" +msgstr "" + +msgid "German" +msgstr "niemiecki" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "Menu" + +msgid "Hard Drive Settings" +msgstr "" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "Sciezka plikacji homebrew" + +msgid "Homebrew Channel" +msgstr "" + +msgid "Homebrew Launcher" +msgstr "" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "Godzina" + +msgid "How do you want to update?" +msgstr "Wybierz rodzaj aktualizacji" + +msgid "How to Shutdown?" +msgstr "Wybierz rodzaj zamkniecia" + +msgid "Import Categories" +msgstr "" + +msgid "Import operation successfully completed." +msgstr "" + +msgid "Importing categories" +msgstr "" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Przychodzacy plik %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Przychodzacy plik %0.2fMB" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "Inicjalizacja sieci" + +msgid "Insert Disk" +msgstr "Wloz plyte" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "Zainstaluj" + +msgid "Install Canceled" +msgstr "" + +msgid "Install Directories" +msgstr "" + +msgid "Install Error!" +msgstr "Blad instalacji" + +msgid "Install Partitions" +msgstr "" + +msgid "Install a game" +msgstr "Zainstaluj gre" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "" + +msgid "Installing game:" +msgstr "Instalowanie gry:" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "" + +msgid "Italian" +msgstr "wloski" + +msgid "Jan" +msgstr "Styczen" + +msgid "Japanese" +msgstr "japonski" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "lipiec" + +msgid "June" +msgstr "czerwiec" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Klawiatura" + +msgid "Korean" +msgstr "koreanski" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "" + +msgid "Language change:" +msgstr "Zmien jezyk" + +msgid "Languagefiles Path" +msgstr "" + +msgid "Languagepath changed." +msgstr "Sciezka do plikow jezykowych zmieniona" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Left" +msgstr "Lewo" + +msgid "Like SysMenu" +msgstr "Podobnie do menu systemowego" + +msgid "List on Gamelaunch" +msgstr "" + +msgid "Load" +msgstr "Zaladuj" + +msgid "Load From SD/USB" +msgstr "Zaladuj z SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Zaladowac plik z: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Zaladowac ten DOL jako alternatywnt?" + +msgid "Loader Settings" +msgstr "" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "ladowanie standardowego jezyka." + +msgid "Loading standard music." +msgstr "ladowanie standardowej muzyki" + +msgid "Lock Console" +msgstr "Zablokuj konsole" + +msgid "Lock USB Loader GX" +msgstr "" + +msgid "Locked" +msgstr "Zablokowano" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "" + +msgid "Loop Music" +msgstr "" + +msgid "Loop Sound" +msgstr "Zapetl dzwieki" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "Marzec" + +msgid "Mark new games" +msgstr "Oznacz nowe gry" + +msgid "May" +msgstr "Maj" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "" + +msgid "Motion+ Video" +msgstr "" + +msgid "Mount DVD drive" +msgstr "Uruchom naped DVD" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "" + +msgid "Music Loop Mode" +msgstr "" + +msgid "Music Volume" +msgstr "Poziom glosnosci" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "" + +msgid "Nand Channels" +msgstr "" + +msgid "Nand Emu Channel Path" +msgstr "" + +msgid "Nand Emu Path" +msgstr "" + +msgid "Nand Emulation" +msgstr "" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "zadne" + +msgid "Network is not initiated." +msgstr "" + +msgid "Next" +msgstr "nastepny" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "Nie" + +msgid "No Cheatfile found" +msgstr "Nie znaleziono plikow z kodami" + +msgid "No DOL file found on disc." +msgstr "Brak plikow DOL na dysku" + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "" + +msgid "No URL or Path specified." +msgstr "" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "Blad odczytu" + +msgid "No disc inserted." +msgstr "" + +msgid "No favorites selected." +msgstr "" + +msgid "No file missing!" +msgstr "Brak plikow do pobrania" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "" + +msgid "No new updates." +msgstr "Posiadasz aktualna wersje" + +msgid "No themes found on the site." +msgstr "Nie znaleziono tematow na tej stronie" + +msgid "No themes found." +msgstr "" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "" + +msgid "Normal" +msgstr "Standardowe" + +msgid "Not Initialized" +msgstr "" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "" + +msgid "Not a valid URL path" +msgstr "" + +msgid "Not a valid domain" +msgstr "" + +msgid "Not enough free memory." +msgstr "Brak wystarczajacej wolnej pamieci" + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "Brak wystarczajacej wolnej pamieci" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "" + +msgid "Not required" +msgstr "" + +msgid "Not supported format!" +msgstr "Nieobslugiwany format" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "Listopad" + +msgid "OFF" +msgstr "Wylacz" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "Wlacz" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Pazdziernik" + +msgid "Official Site:" +msgstr "Strona oficjalna:" + +msgid "Offset" +msgstr "" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "" + +msgid "Only for Install" +msgstr "Tylko dla instalacji" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Mieszane" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Kontrola rodzicielska" + +msgid "Partial" +msgstr "" + +msgid "Partition" +msgstr "Partycja" + +msgid "Password" +msgstr "Haslo" + +msgid "Password Changed" +msgstr "Haslo zmieniono" + +msgid "Password has been changed" +msgstr "Haslo zostalo zmienione" + +msgid "Patch Country Strings" +msgstr "" + +msgid "Path Changed" +msgstr "" + +msgid "Permission denied." +msgstr "" + +msgid "Pick from a list" +msgstr "Wybierz z listy" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Licznik" + +msgid "Play Next" +msgstr "" + +msgid "Play Once" +msgstr "" + +msgid "Play Previous" +msgstr "" + +msgid "Playing Music:" +msgstr "" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "Prosze czekac..." + +msgid "Power off the Wii" +msgstr "Wylacz Wii" + +msgid "Prev" +msgstr "Poprzedni" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "" + +msgid "Published by" +msgstr "" + +msgid "Quick Boot" +msgstr "Szybkie ladowanie" + +msgid "Random Directory Music" +msgstr "" + +msgid "Real Nand" +msgstr "" + +msgid "Receiving file from:" +msgstr "Otrzymywanie pliku z:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "" + +msgid "Released" +msgstr "" + +msgid "Reload SD" +msgstr "Przeladuj SD" + +msgid "Reloading game list now, please wait..." +msgstr "" + +msgid "Remember Unlock" +msgstr "" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "" + +msgid "Rename Game Title" +msgstr "" + +msgid "Rename category" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Reset BG Music" +msgstr "" + +msgid "Reset Playcounter" +msgstr "Zrestartuj licznik" + +msgid "Reset to default BGM?" +msgstr "" + +msgid "Restarting..." +msgstr "Restartowanie..." + +msgid "Return" +msgstr "Powrot" + +msgid "Return To" +msgstr "" + +msgid "Return to Wii Menu" +msgstr "Powrot do Wii Menu" + +msgid "Right" +msgstr "Prawo" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Wibracje" + +msgid "SChinese" +msgstr "uproszczony chinski" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "Poziom glosnosci SFX" + +msgid "Save" +msgstr "Zapisz" + +msgid "Save Failed. No device inserted?" +msgstr "" + +msgid "Save Game List to" +msgstr "Zapisz liste gier do" + +msgid "Save List" +msgstr "" + +msgid "Saved" +msgstr "Zapisano" + +msgid "Savegame might not exist for this game." +msgstr "" + +msgid "Screensaver" +msgstr "Wygaszacz ekranu" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "Wybierz" + +msgid "Select DOL Offset" +msgstr "" + +msgid "Select a DOL" +msgstr "Wybierz plik DOL" + +msgid "Select a DOL from Game" +msgstr "" + +msgid "Select game categories" +msgstr "" + +msgid "Select loader mode" +msgstr "" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "" + +msgid "Sept" +msgstr "Wrzesien" + +msgid "Set Search-Filter" +msgstr "Ustaw filtr wyszukiwania" + +msgid "Settings" +msgstr "Ustawienia" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "" + +msgid "Show Play Count" +msgstr "" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "Wylacz" + +msgid "Shutdown Wii" +msgstr "" + +msgid "Skip Errors" +msgstr "" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Sortuj alfabetycznie" + +msgid "Sort by number of players" +msgstr "" + +msgid "Sort by rank" +msgstr "Sortuj wzgledem rankingu" + +msgid "Sort order by most played" +msgstr "Sortuj wg. liczby uruchomien" + +msgid "Sound" +msgstr "Dzwiek" + +msgid "Sound Settings" +msgstr "" + +msgid "Sound+BGM" +msgstr "Dzwieki i muzyka w tle" + +msgid "Sound+Quiet" +msgstr "Dzwieki i cisza" + +msgid "Spanish" +msgstr "hiszpanski" + +msgid "Special thanks to:" +msgstr "Specjalne podziekowania" + +msgid "Split each 2GB" +msgstr "" + +msgid "Split each 4GB" +msgstr "" + +msgid "Standby" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "Sukces" + +msgid "Success." +msgstr "" + +msgid "Success:" +msgstr "Sukces:" + +msgid "Successfully Saved" +msgstr "Pomyslnie zapisano" + +msgid "Successfully Updated" +msgstr "Pomyslnie zaktualizowano" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "Pomyslnie usunieto" + +msgid "Successfully extracted theme." +msgstr "Pomyslnie rozpakowano temat." + +msgid "Successfully installed:" +msgstr "Pomyslnie zainstalowano:" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "" + +msgid "Sync FAT32 FS Info" +msgstr "" + +msgid "Synchronizing..." +msgstr "" + +msgid "System Default" +msgstr "Domyslne ustawienia systemowe" + +msgid "TChinese" +msgstr "chinski" + +msgid "TXT Cheatcodes Path" +msgstr "Sciezka kodow TXT" + +msgid "The .them file was not found in the zip." +msgstr "" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "Katalog nie istnieje. Utworzyc?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "" + +msgid "Theme Downloader" +msgstr "Pobieranie tematow" + +msgid "Theme Menu" +msgstr "" + +msgid "Theme Path" +msgstr "Sciezka skorek" + +msgid "Theme Title:" +msgstr "Tytul:" + +msgid "Themes by www.spiffy360.com" +msgstr "" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "" + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "Czas pozostaly" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Uruchom tytul" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "Chmurki z podpowiedziami" + +msgid "Transfer failed" +msgstr "" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX zabezpieczony" + +msgid "USB Port" +msgstr "" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "Odinstaluj" + +msgid "Uninstall Game" +msgstr "Odinstaluj gre" + +msgid "Uninstall Menu" +msgstr "Odinstaluj Menu" + +msgid "Uninstall all" +msgstr "" + +msgid "Unknown" +msgstr "" + +msgid "Unlock USB Loader GX" +msgstr "" + +msgid "Unlocked" +msgstr "Odblokowano" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "" + +msgid "Update" +msgstr "Aktualizacja" + +msgid "Update All" +msgstr "Zaktualizuj wszystko" + +msgid "Update DOL" +msgstr "Zaktualizuj Dol" + +msgid "Update Files" +msgstr "Zaktualizuj pliki" + +msgid "Update Path" +msgstr "Sciezka aktualizacji" + +msgid "Update all Language Files" +msgstr "Zaktualizuj wszystkie pliki jezykowe" + +msgid "Update failed" +msgstr "Nie udalo sie zaktualizowac" + +msgid "Update successfull" +msgstr "" + +msgid "Updating Language Files:" +msgstr "Aktualizacja plikow jezykowych:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Wyslany plik ZIP zainstalowano w katalogu homebrew" + +msgid "Use System Font" +msgstr "" + +msgid "Use global" +msgstr "" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "" + +msgid "Version:" +msgstr "" + +#, c-format +msgid "Version: %s" +msgstr "Wersja: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Tryb video" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "" + +msgid "WDM Files Path" +msgstr "" + +msgid "WIP Patches Path" +msgstr "Sciezka patchy WIP" + +msgid "Waiting..." +msgstr "Oczekiwanie..." + +msgid "Warning" +msgstr "" + +msgid "Warning:" +msgstr "" + +msgid "What do you want to do?" +msgstr "" + +msgid "What do you want to update?" +msgstr "Rodzaj aktualizacji" + +msgid "What should be deleted for this game title:" +msgstr "" + +msgid "What to extract from NAND?" +msgstr "" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "Opcje WiFi" + +msgid "Widescreen Factor" +msgstr "" + +msgid "Widescreen Fix" +msgstr "Popraw ekran panoramiczny" + +msgid "Wii Games" +msgstr "" + +msgid "Wii Menu" +msgstr "" + +msgid "Wii Settings" +msgstr "Opcje Wii" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "Dioda Wii" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "" + +msgid "Wiird Debugger" +msgstr "" + +#, c-format +msgid "Write error on file: %s" +msgstr "" + +msgid "Writing GXGameCategories.xml" +msgstr "" + +msgid "Wrong Password" +msgstr "Bledne haslo" + +msgid "Yes" +msgstr "Tak" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "" + +msgid "You cannot delete this category." +msgstr "" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "" + +msgid "available" +msgstr "dostepne" + +msgid "does not exist!" +msgstr "nie istnieje!" + +msgid "does not exist! Loading game without cheats." +msgstr "nie istnieje! ladowanie gry bez kodow." + +msgid "files left" +msgstr "pozostalo" + +msgid "for FAT/NTFS support" +msgstr "za pomoc przy FAT/NTFS" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "" + +msgid "for Ocarina" +msgstr "dla Ocarina" + +msgid "for diverse patches" +msgstr "za rozne poprawki" + +msgid "for his awesome tool LibWiiGui" +msgstr "za jego niesamowite narzedzie LibWiiGui" + +msgid "for hosting the themes" +msgstr "za hosting tematow" + +msgid "for the USB Loader source" +msgstr "za zrodla USB Loader" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "sformatowano" + +msgid "free" +msgstr "wolnego" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "nie ustawiono" + +msgid "of" +msgstr "z" + +msgid "seconds left" +msgstr "sekund pozostalo" + +#~ msgid "Anti" +#~ msgstr "Anty" + +#~ msgid "Error 002 fix" +#~ msgstr "Poprawka bledu 002" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "Zmien tytul gry na WBFS" + +#~ msgid "for hosting the update files" +#~ msgstr "za hostowanie plikow aktualizacji" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Wloz plyte Wii!" + +#~ msgid "No cheats were selected" +#~ msgstr "Nie wybrano zadnych kodow" + +#~ msgid "Not a Wii Disc" +#~ msgstr "To nie jest plyta Wii" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> Usuwanie ticketu..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> Usuwanie ticketu...ERROR! " + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> Usuwanie ticketu...Ok! " + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> Usuwanie tytulu ...ERROR! " + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> Usuwanie tytulu ...Ok!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> Usuwanie title contents..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> Usuwanie title contents...ERROR! " + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> Usuwanie title contents...Ok!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> Usuwanie tytulu..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> Konczenie instalacji" + +#~ msgid ">> Installing content #" +#~ msgstr ">> Instalowanie zawartoSci #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> Instalowanie ticketu..." + +#~ msgid ">> Installing title..." +#~ msgstr ">> Instalowanie tytulu..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> Odczyt danych WAD..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> Odczyt danych WAD...ERROR! " + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> Odczyt danych WAD...Ok!" + +#~ msgid "Done!" +#~ msgstr "Zakonczono!" + +#~ msgid "Error..." +#~ msgstr "Blad..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "Konczenie instalacji...Ok!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "Instalowanie zawartosci...Ok!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "Instalowanie ticketu... Ok!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "Instalowanie tytulu... Ok!" + +#~ msgid "Installing wad" +#~ msgstr "Instalowanie wad" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "Odczyt danych WAD...Ok!" + +#~ msgid "Uninstalling wad" +#~ msgstr "Odinstalowywanie wad" + +#~ msgid "New Disc Detected" +#~ msgstr "Wykryto nowy dysk" + +#~ msgid "USB Device not found" +#~ msgstr "Nie znaleziono urzadzenia USB" + +#~ msgid "You need to select or format a partition" +#~ msgstr "Musisz wybrac, lub sformatowac partycje" + +#~ msgid "Language File" +#~ msgstr "Plik jezykowy" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Tytuly z pliku WiiTDB" + +#~ msgid "WiiTDB Files" +#~ msgstr "WiiTDB" + +#~ msgid "WiiTDB Path" +#~ msgstr "Sciezka WiiTDBPath" + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "za WiiTDB i hostowanie okladek/obrazkow plyt" + +#~ msgid "Install partitions" +#~ msgstr "Zainstaluj partycje" + +#~ msgid " Wad Saved as:" +#~ msgstr " Wad zapisano jako:" + +#~ msgid "Delete ?" +#~ msgstr "Usunac ?" + +#~ msgid "Keep" +#~ msgstr "Trzymaj" + +#~ msgid "Author:" +#~ msgstr "Autor: " + +#~ msgid "Download Boxart image?" +#~ msgstr "Pobrac obrazki box?" + +#~ msgid "Download Discart image?" +#~ msgstr "Pobrac obrazki plyt?" + +#~ msgid "Downloading file" +#~ msgstr "Pobieranie pliku" + +#~ msgid "Missing files" +#~ msgstr "Brakuje plikow" + +#~ msgid "files not found on the server!" +#~ msgstr "nie znaleziono na serwerze" + +#~ msgid "Disc Images" +#~ msgstr "Obrazki plyt" + +#~ msgid "Only Customs" +#~ msgstr "Tylko nieoryginalne" + +#~ msgid "Only Original" +#~ msgstr "Tylko oryginalne" + +#~ msgid "Do you really want to delete:" +#~ msgstr "Na pewno usunac: " + +#~ msgid "Do you want to use the alternate DOL that is known to be correct?" +#~ msgstr "Uzyc alternatywnego pliku DOL?" + +#~ msgid "BETA revisions" +#~ msgstr "Wersje beta" + +#~ msgid "Unlock console to use this option." +#~ msgstr "Odblokuj konsole, aby uzyc tej opcji" + +#~ msgid "Full Shutdown" +#~ msgstr "Pelne zamkniecie" + +#~ msgid "GXtheme.cfg not found in any subfolder." +#~ msgstr "Nie znaleziono pliku GXtheme.cfg" + +#~ msgid "If you don't have WiFi, press 1 to get an URL to get your WiiTDB.zip" +#~ msgstr "JeSli nie masz WiFi, wcisnij 1 aby otrzymac adres skad pobrac WiiTDB.zip" + +#~ msgid "Paste it into your browser to get your WiiTDB.zip." +#~ msgstr "Wklej adres do przegladarki, aby pobrac WiiTDB.zip" + +#~ msgid "Shutdown to Idle" +#~ msgstr "Przelacz w stan oczekiwania" + +#~ msgid "Your URL has been saved in %sWiiTDB_URL.txt." +#~ msgstr "Adres zostal zapisany w pliku %sWiiTDB_URL.txt." + +#~ msgid "Can't create file" +#~ msgstr "Nie mozna utworzyc pliku" + +#~ msgid "Connection lost..." +#~ msgstr "Utracono polaczenie..." + +#~ msgid "Download failed." +#~ msgstr "Nie udalo sie pobrac" + +#~ msgid "Download request failed." +#~ msgstr "Prosba pobierania nieudana" + +#~ msgid "Downloading Page List:" +#~ msgstr "Pobieranie listy stron:" + +#~ msgid "Theme Download Path" +#~ msgstr "Sciezka tematow" + +#~ msgid "Transfer failed." +#~ msgstr "Niepowodzenie." + +#~ msgid "Unsupported format, try to extract manually." +#~ msgstr "Niewspierany format, sprobuj rozpakowac recznie" + +#~ msgid "and translaters for language files updates" +#~ msgstr "i tlumaczon za aktualizacjie plikow jezykowych" + +#~ msgid "Insert an SD-Card to save." +#~ msgstr "Wloz karte SD, aby zapisac" + +#~ msgid "Insert an SD-Card to use this option." +#~ msgstr "Wloz karte SD, aby uzyc tej opcji" + +#~ msgid "No SD-Card inserted!" +#~ msgstr "Nie wlozono karty SD!" + +#~ msgid "Waiting for USB Device" +#~ msgstr "Oczekiwanie na urzadzenie USB" + +#~ msgid "Back to Loader" +#~ msgstr "Powrot do HBC" + +#~ msgid "FAT: Use directories" +#~ msgstr "FAT: uzyj katalogow" + +#~ msgid "All partitions" +#~ msgstr "Wszystkie partycje" + +#~ msgid "Game partition" +#~ msgstr "Partycje z grami" + +#~ msgid "Install 1:1 Copy" +#~ msgstr "Zainstaluj kopie 1:1" + +#~ msgid "An Error occured" +#~ msgstr "Wystapil blad" + +#~ msgid "Are you sure you want to enable Parent Control?" +#~ msgstr "Czy na pewno wlaczyc kontrole rodzicielska?" + +#~ msgid "AutoPatch" +#~ msgstr "Automatyczny patch" + +#~ msgid "Checking for Updates" +#~ msgstr "Sprawdzanie aktualizacji" + +#~ msgid "Downloading" +#~ msgstr "Trwa pobieranie" + +#~ msgid "Invalid PIN code" +#~ msgstr "Bledny kod PIN" + +#~ msgid "Parental Control disabled" +#~ msgstr "Kontrola rodzicielska wylaczona" + +#~ msgid "The wad file was installed. But It could not be deleted from the SD card." +#~ msgstr "Zainstalowano plik wad, ale nie mozna go usunac z karty SD" + +#~ msgid "The wad installation failed with error %ld" +#~ msgstr "Instalacja wad zakonczona bledek %ld" + +#~ msgid "Unable to open the wad that was just downloaded (%s)." +#~ msgstr "Nie udalo sie zainstalowac dopiero co pobranego pliku (%s)" + +#~ msgid "Unlock Parental Control" +#~ msgstr "Odblokuj kontrole rodzicielska" + +#~ msgid "Update to" +#~ msgstr "Aktualizuj do" + +#~ msgid "Updating" +#~ msgstr "Aktualizowanie" + +#~ msgid "Updating Language Files..." +#~ msgstr "Aktualizacja plikow jezykowych..." + +#~ msgid "Updating WiiTDB.zip" +#~ msgstr "Aktualizacja WiiTDB.zip" + +#~ msgid "You don't have Parental Control enabled. If you wish to use Parental Control, enable it in the Wii Settings." +#~ msgstr "Nie masz wlaczonej kontroli rodzicielskiej. Jesli chcesz jej uzywac, uruchom ja w ustawieniach Wii." + +#~ msgid "%s : %s May not boot correctly if your System Menu is not up to date." +#~ msgstr "%s : %s Moze nie ladowac sie poprawnie, jesli nie masz aktualnego menu systemowego" + +#~ msgid "BCA Codes Path changed" +#~ msgstr "Zmieniono sciezke kodow BCA" + +#~ msgid "Back to Wii Menu" +#~ msgstr "Powrit do Wii Menu" + +#~ msgid "Checking existing artwork" +#~ msgstr "Sprawdzam istniejace prace graficzne" + +#~ msgid "Confirm" +#~ msgstr "Potwierdz" + +#~ msgid "Could not find a WBFS partition." +#~ msgstr "Nie znaleziono partycji WBFS" + +#~ msgid "Could not open WBFS partition" +#~ msgstr "Nie udalo sie otworzyc partycji WBFS" + +#~ msgid "Could not read the disc." +#~ msgstr "Nie mozna odczytac dysku" + +#~ msgid "Could not set USB." +#~ msgstr "Nie mozna ustawic USB" + +#~ msgid "Cover Path Changed" +#~ msgstr "Sciezka do okladek zostala zmieniona" + +#~ msgid "DOL path changed" +#~ msgstr "Zmieniono sciezke plikow .DOL" + +#~ msgid "Disc Path Changed" +#~ msgstr "Sciezka do dysku zmieniona" + +#~ msgid "Display favorites" +#~ msgstr "Pokaz ulubione" + +#~ msgid "Do you want to retry for 30 secs?" +#~ msgstr "Powtorzyc za 30 sec?" + +#~ msgid "Enable Parental Control" +#~ msgstr "Wlacz kontrole rodzicielska" + +#~ msgid "Force" +#~ msgstr "Wymuc" + +#~ msgid "GCT Cheatcodes Path changed" +#~ msgstr "Sciezka kodow GCT zmienona" + +#~ msgid "Homebrew Appspath changed" +#~ msgstr "Sciezka aplikacji homebrew zmieniona" + +#~ msgid "Insert an SD-Card to download images." +#~ msgstr "Wloz karte SD, aby pobrac obrazki" + +#~ msgid "Install not possible" +#~ msgstr "Nie mozna zainstalowac" + +#~ msgid "Most likely it has dimensions that are not evenly divisible by 4." +#~ msgstr "Prawdopodobnie rozdzielczosc nie jest podzielna przez 4" + +#~ msgid "Network init error" +#~ msgstr "Problem inicjalizacji sieci" + +#~ msgid "No .dol or .elf files found." +#~ msgstr "Nie znaleziono plikow .dol ani .elf" + +#~ msgid "No Favorites" +#~ msgstr "Brak ulubionych" + +#~ msgid "No USB Device" +#~ msgstr "Nie wykryto urzadzenia USB" + +#~ msgid "No USB Device found." +#~ msgstr "Nie wykryto urzadzenia USB" + +#~ msgid "No WBFS or FAT/NTFS partition found" +#~ msgstr "Nie znaleziono partycji WBFS, ani FAT/NTFS" + +#~ msgid "Normal Covers" +#~ msgstr "Standardowe okladki" + +#~ msgid "Not Found" +#~ msgstr "Nie znaleziono" + +#~ msgid "Not a DOL/ELF file." +#~ msgstr "To nie jest plik DOL/ELF" + +#~ msgid "Save Failed" +#~ msgstr "Nie udalo sie zapisac" + +#~ msgid "Selected DOL" +#~ msgstr "Wybrano plik DOL" + +#~ msgid "Standard" +#~ msgstr "Standardowe" + +#~ msgid "TXT Cheatcodes Path changed" +#~ msgstr "Sciezka kodow TXT zmienona" + +#~ msgid "Theme Download Path changed" +#~ msgstr "Zmieniono sciezke tematow" + +#~ msgid "Theme Path Changed" +#~ msgstr "Zmieniono sciezke skorek" + +#~ msgid "USB Loader GX will only run with Hermes CIOS rev 4! Please make sure you have revision 4 installed!" +#~ msgstr "USB Loader GX dziala tylko z Hermes CIOS rev 4! Upewnij sie czy masz zainstalowana wersje 4!" + +#~ msgid "Update Path changed." +#~ msgstr "Zmieniono Sciezke aktualizacji" + +#~ msgid "WIP Patches Path changed" +#~ msgstr "Zmieniono sciezke patchy WIP" + +#~ msgid "WiiTDB Path changed." +#~ msgstr "Sciezka WiiTDBPath zmieniona" + +#~ msgid "You are about to delete " +#~ msgstr "Zamierzasz usunac" + +#~ msgid "You are choosing to display favorites and you do not have any selected." +#~ msgstr "WybraleS wySwietlenie usubionych, ale zadnych nie wybraleS" + +#~ msgid "You are using NTFS filesystem. Due to possible write errors to a NTFS partition, installing a game is not possible." +#~ msgstr "Uzywasz partycji NTFS. Instalacja gier na tej partycji nie jest mozliwa." + +#~ msgid "You have attempted to load a bad image" +#~ msgstr "Probujesz zaladowac zly obraz" + +#~ msgid "does not exist! You Messed something up, Idiot." +#~ msgstr "Nie istnieje! Cos zepsules" + +#~ msgid "file left" +#~ msgstr "pozostalo" diff --git a/Languages/portuguese_br.lang b/Languages/portuguese_br.lang new file mode 100644 index 0000000..4a63654 --- /dev/null +++ b/Languages/portuguese_br.lang @@ -0,0 +1,2523 @@ +# USB Loader GX language source file. +# portuguese_br.lang - r1262 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:05+0200\n" +"PO-Revision-Date: 2011-11-03 11:00+0000\n" +"Last-Translator: Codemaster(TheCodemastr) \n" +"Language-Team: Sky8000, pplucky\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: Português Brasileiro\n" + +msgid " could not be downloaded." +msgstr " não foi baixado" + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " foi salvo. O texto não foi verificado e pode não funcionar. Se achar problemas, abra-o com um editor de texto para obter mais informações" + +msgid " is not on the server." +msgstr " não está no servidor" + +#, c-format +msgid "%i files not found on the server!" +msgstr "%i arquivos não encontrados no servidor!" + +#, c-format +msgid "%i missing files" +msgstr "%i arquivos faltando" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "%i arquivos não processados!" + +#, c-format +msgid "%i wad found." +msgstr "%i arquivo(s) WAD encontrados" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "%s só aceita jogos de GameCube no formato ISO" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "%s requer AHB. Inicie o USBLoader GX pelo Homebrew Channel ou por um forwarder atualizado" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Todos)" + +msgid "1 (Child 7+)" +msgstr "1 (Crianças 7+)" + +msgid "1 hour" +msgstr "1 hora" + +msgid "10 min" +msgstr "" + +msgid "2 (Teen 12+)" +msgstr "2 (Adolescente 12+)" + +msgid "20 min" +msgstr "" + +msgid "2D Cover Path" +msgstr "Capas 2D" + +msgid "3 (Mature 16+)" +msgstr "3 (Adulto 16+)" + +msgid "3 min" +msgstr "" + +msgid "30 min" +msgstr "" + +msgid "3D Cover Path" +msgstr "Capas 3D" + +msgid "3D Covers" +msgstr "Capas 3D" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Adultos 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "" + +msgid "=== GameCube Settings" +msgstr "=== Opções do GameCube" + +msgid "AUTO" +msgstr "" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "Adicionar" + +msgid "Adjust Overscan X" +msgstr "Ajuste Margem X" + +msgid "Adjust Overscan Y" +msgstr "Ajuste Margem Y" + +msgid "After zoom" +msgstr "Depois do zoom" + +msgid "All" +msgstr "Todas" + +msgid "All Partitions" +msgstr "Todas as Partições" + +msgid "All files extracted." +msgstr "Todos os arquivos foram extraídos" + +msgid "All images downloaded successfully." +msgstr "As imagens foram baixadas com sucesso" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Todas as funcionalidades foram desbloqueadas" + +msgid "All wad files processed successfully." +msgstr "Todos os arquivos foram processados" + +msgid "Alternate DOL" +msgstr "DOL alternativo" + +msgid "An example file was created here:" +msgstr "Arquivo de exemplo criado aqui:" + +msgid "Animation Start" +msgstr "Início da Animação" + +msgid "App Language" +msgstr "Idioma" + +msgid "Apply" +msgstr "Aplicar" + +msgid "Apr" +msgstr "Abr" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "Tem certeza que quer apagar os jogos selecionados do Cartão SD?" + +msgid "Are you sure you want to delete this category?" +msgstr "Tem certeza que quer apagar esta categoria?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "Tem certeza que quer importar as categorias de jogos da GameTDB?" + +msgid "Are you sure you want to install on SD?" +msgstr "Deseja mesmo instalar no cartão SD?" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "Tem certeza que quer bloquear o USB Loader GX?" + +msgid "Are you sure you want to remount SD?" +msgstr "Tem certeza que quer recarregar o cartão SD?" + +msgid "Are you sure you want to reset?" +msgstr "Tem certeza que quer reiniciar?" + +msgid "Are you sure?" +msgstr "Tem certeza?" + +msgid "Aspect Ratio" +msgstr "Aspecto" + +msgid "Attention!" +msgstr "Atenção!" + +msgid "Attention: All savegames will be deleted." +msgstr "Atenção: Todos os seus arquivos de save serão apagados" + +msgid "Aug" +msgstr "Ago" + +msgid "Author(s):" +msgstr "Autor(es):" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "Auto-iniciar Rede" + +msgid "BCA Codes Path" +msgstr "Códigos BCA" + +msgid "Back" +msgstr "Voltar" + +msgid "Back to HBC or Wii Menu" +msgstr "Voltar ao HBC ou Menu Wii" + +msgid "Backgroundmusic" +msgstr "Música de fundo" + +msgid "Banner Animation" +msgstr "Animação do Banner" + +msgid "Banner Animation Settings" +msgstr "Banners" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "A visualização em grade só está disponível com AHBPROT! Considere atualizar seu Homebrew Channel" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "A visualização em janelas de banners só está disponível com AHBPROT! Considere atualizar seu Homebrew Channel" + +msgid "Big thanks to:" +msgstr "Agradecimentos:" + +msgid "Block Categories Menu" +msgstr "Bloquear Menu Categorias" + +msgid "Block Categories Modify" +msgstr "Bloq. Modificar. Categorias" + +msgid "Block Cover Downloads" +msgstr "Bloq. Download de Capas" + +msgid "Block Custom Paths" +msgstr "Bloq. Menu Caminhos" + +msgid "Block Feature Settings" +msgstr "Bloq. Menu Funcionalidades" + +msgid "Block Game Install" +msgstr "Bloq. Instalação Jogo" + +msgid "Block Game Settings" +msgstr "Bloq. Opções do Jogo" + +msgid "Block GameID Change" +msgstr "Bloq. Mudança ID Jogo" + +msgid "Block Global Settings" +msgstr "Bloq. Defin. Globais" + +msgid "Block Gui Settings" +msgstr "Bloq. Defin. Interface" + +msgid "Block HBC Menu" +msgstr "Bloq. Menu HBC" + +msgid "Block Hard Drive Settings" +msgstr "Bloq. Menu Armazenamento" + +msgid "Block IOS Reload" +msgstr "Bloq. IOS Reload" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "Bloq. Alteração de Modo" + +msgid "Block Loader Settings" +msgstr "Bloq. Menu Loader" + +msgid "Block Parental Settings" +msgstr "Bloq. Controle dos Pais" + +msgid "Block Priiloader Override" +msgstr "Bloq. Alterar Priiloader" + +msgid "Block Reset Settings" +msgstr "Bloq. Opções Reinício" + +msgid "Block SD Reload Button" +msgstr "Bloq. Botão SD" + +msgid "Block Sound Settings" +msgstr "Bloq. Menu Áudio" + +msgid "Block Theme Downloader" +msgstr "Bloq. Download Temas" + +msgid "Block Theme Menu" +msgstr "Bloq. Menu Temas" + +msgid "Block Title Launcher" +msgstr "Bloq. Gestor de Títulos" + +msgid "Block Updates" +msgstr "Bloq. Atualizações" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "Carregar?" + +msgid "Both" +msgstr "Ambos" + +msgid "Both Ports" +msgstr "Ambas Portas" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "Cache de Banners" + +msgid "Cache BNR Files Path" +msgstr "Caminho Cache" + +msgid "Cache Titles" +msgstr "Títulos em Cache" + +msgid "Can't be formatted" +msgstr "Não pode ser formatado" + +msgid "Can't create directory" +msgstr "Não foi possível criar a pasta" + +#, c-format +msgid "Can't create file: %s" +msgstr "Não foi possível criar arquivo: %s" + +#, c-format +msgid "Can't create path: %s" +msgstr "Não foi possível criar caminho: %s" + +msgid "Can't delete:" +msgstr "Não foi possível apagar:" + +msgid "Can't mount or unknown disc format." +msgstr "Disco em formato desconhecido." + +#, c-format +msgid "Can't open file for write: %s" +msgstr "Não foi possível escrever o arquivo %s" + +#, c-format +msgid "Can't open file: %s" +msgstr "Não foi possível abrir o arquivo: %s" + +#, c-format +msgid "Can't read file: %s" +msgstr "Não foi possível ler o arquivo: %s" + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Cannot write to destination." +msgstr "Não foi possível escrever no destino" + +msgid "Categories" +msgstr "Categorias" + +msgid "Categories:" +msgstr "Categorias:" + +msgid "Change Play Path" +msgstr "Alterar Caminho de Músicas" + +msgid "Channel Launcher" +msgstr "Lançador de Canais" + +msgid "Channels" +msgstr "Canais" + +msgid "Cheatfile is blank" +msgstr "Arquivo de cheat vazio" + +msgid "Clear" +msgstr "Limpar" + +msgid "Click to Download Covers" +msgstr "Clique para descarregar capas" + +msgid "Click to change game ID" +msgstr "Clique para alterar o ID do jogo" + +msgid "Clock" +msgstr "Relógio" + +msgid "Clock Scale Factor" +msgstr "Tamanho Fonte Relógio" + +msgid "Close" +msgstr "Fechar" + +msgid "Code Download" +msgstr "Download de Código" + +#, c-format +msgid "Coded by: %s" +msgstr "Programado por: %s" + +msgid "Coding:" +msgstr "Desenvolvimento:" + +msgid "Connection to server timed out." +msgstr "Time out na ligação ao servidor" + +msgid "Console" +msgstr "" + +msgid "Console Default" +msgstr "Opções Padrão" + +msgid "Console Locked" +msgstr "Console Bloqueado" + +msgid "Console must be unlocked for this option." +msgstr "O USB Loader GX tem de estar desbloqueado para esta opção" + +msgid "Console must be unlocked to be able to use this." +msgstr "O USB Loader GX tem de estar desbloqueado para usar isto" + +msgid "Console should be unlocked to modify it." +msgstr "O USB Loader GX deve estar desbloqueado para alterar" + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "Continuar instalação do jogo?" + +msgid "Continue?" +msgstr "Continuar?" + +msgid "Controllevel" +msgstr "Nível de Controle" + +msgid "Copy" +msgstr "Copiar" + +msgid "Copying Canceled" +msgstr "Cópia Cancelada" + +msgid "Copying GC game..." +msgstr "Copiando Jogo..." + +msgid "Copying files..." +msgstr "Copiando arquivos:" + +msgid "Correct Password" +msgstr "Senha Correta" + +msgid "Could not connect to the server." +msgstr "Não foi possível conectar ao servidor" + +msgid "Could not create GCT file" +msgstr "Não foi possível criar o arquivo GCT" + +#, c-format +msgid "Could not create path: %s" +msgstr "Não foi possível criar caminho: %s" + +msgid "Could not extract files for:" +msgstr "Não foi possível extrair arquivos para:" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "Não foi encontrada info do jogo no wiitdb.xml" + +msgid "Could not get free device space for game." +msgstr "Não foi possível conseguir espaço livre suficiente para o jogo" + +msgid "Could not initialize DIP module!" +msgstr "Não foi possível inicializar o módulo DIP!" + +msgid "Could not initialize network!" +msgstr "Não foi possível iniciar a rede!" + +msgid "Could not initialize network, time out!" +msgstr "Não foi possível iniciar a rede. Tempo esgotado" + +msgid "Could not open Disc" +msgstr "Não foi possível abrir o Disco" + +msgid "Could not open the WiiTDB.xml file." +msgstr "Não foi possível abrir o arquivo WiiTDB.xml." + +msgid "Could not open wiitdb.xml." +msgstr "Não foi possível abrir o wiitdb.xml" + +msgid "Could not save." +msgstr "Não foi possível gravar." + +msgid "Could not write file." +msgstr "Não foi possível escrever arquivo" + +msgid "Could not write to:" +msgstr "Não foi possível escrever para:" + +msgid "Cover Download" +msgstr "Download de Capas" + +msgid "Create" +msgstr "Criar" + +msgid "Credits" +msgstr "Créditos" + +msgid "Crop Overscan" +msgstr "Cortar Overscan" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "Os arquivos do neek não são do neek2o. Auto Boot desabilitado" + +msgid "Custom Banners" +msgstr "Banners Modificados" + +msgid "Custom Paths" +msgstr "Caminhos" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "Personalizadas/Originais" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "Cam. DOL" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "Dez" + +msgid "Default" +msgstr "Padrão" + +msgid "Default Gamesettings" +msgstr "Opções Padrão" + +msgid "Default Settings" +msgstr "Configurações Padrão" + +msgid "Delete" +msgstr "Eliminar" + +msgid "Delete Cached Banner" +msgstr "Apagar Banner em Cache" + +msgid "Delete Cheat GCT" +msgstr "Eliminar Cheat GCT" + +msgid "Delete Cheat TXT" +msgstr "Eliminar Cheat TXT" + +msgid "Delete Cover Artwork" +msgstr "Eliminar Capas" + +msgid "Delete Disc Artwork" +msgstr "Eliminar Imagem Disco" + +msgid "Delete category" +msgstr "Apagar" + +msgid "Deleting directories..." +msgstr "Apagando pastas..." + +msgid "Deleting files..." +msgstr "Apagando arquivos..." + +msgid "Design:" +msgstr "Design:" + +msgid "Details" +msgstr "Detalhes" + +msgid "Developed by" +msgstr "Desenvolvido por" + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "Devolution" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "O arquivo loader.bin do Devolution não pode ser lido" + +msgid "Directory does not exist!" +msgstr "Pasta não existe!" + +msgid "Disc 1" +msgstr "Disco 1" + +msgid "Disc 2" +msgstr "Disco 2" + +msgid "Disc Artwork Download" +msgstr "Baixar Imagens Disco" + +msgid "Disc Artwork Path" +msgstr "Imagens Disco" + +msgid "Disc Default" +msgstr "Padrão do Disco" + +msgid "Disc Insert Detected" +msgstr "Um disco foi inserido" + +msgid "Disc Read Delay" +msgstr "Atrasar Leitura do Disco" + +msgid "Disc read error." +msgstr "Erro de leitura do disco." + +msgid "Disc-Select Prompt" +msgstr "Perguntar o disco a iniciar" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "O Disco 2 precisa ser descomprimido para funcionar nessa versão do DIOS MIOS. Tem certeza de que quer instalar usando compressão?" + +msgid "Discarts" +msgstr "Etiquetas de Disco" + +msgid "DiskFlip" +msgstr "Voltar Disco" + +msgid "Display" +msgstr "Mostrar" + +msgid "Display as a carousel" +msgstr "Mostrar como carrossel" + +msgid "Display as a channel grid" +msgstr "Mostrar como grade de canais" + +msgid "Display as a grid" +msgstr "Mostrar como grade" + +msgid "Display as a list" +msgstr "Mostrar como lista" + +msgid "Display favorites only" +msgstr "Apenas Favoritos" + +msgid "Do you want to apply it now?" +msgstr "Deseja aplicar agora?" + +msgid "Do you want to apply this theme?" +msgstr "Deseja aplicar este tema?" + +msgid "Do you want to change language?" +msgstr "Deseja alterar o idioma?" + +msgid "Do you want to continue with next game?" +msgstr "Você deseja continuar com o próximo jogo?" + +msgid "Do you want to copy now?" +msgstr "Você deseja copiar agora?" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "Você deseja copiar ou apagar o jogo no Cartão SD?" + +msgid "Do you want to delete a game on SD?" +msgstr "Deseja apagar um jogo no Cartão SD?" + +msgid "Do you want to discard changes?" +msgstr "Deseja desfazer as alterações?" + +msgid "Do you want to download this theme?" +msgstr "Deseja descarregar este tema?" + +msgid "Do you want to extract all the save games?" +msgstr "Deseja extrair todas as gravações?" + +msgid "Do you want to extract the save game?" +msgstr "Deseja extrair esta gravação?" + +msgid "Do you want to format:" +msgstr "Deseja FORMATAR:" + +msgid "Do you want to install selected games?" +msgstr "Deseja instalar os jogos selecionados?" + +msgid "Do you want to load the default theme?" +msgstr "Deseja carregar o tema padrão?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "Você deseja mover o(s) arquivo(s)? Os existentes serão apagados!" + +msgid "Do you want to re-init network?" +msgstr "Deseja reiniciar a rede?" + +msgid "Do you want to start the game now?" +msgstr "Deseja iniciar o jogo agora?" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "Deseja sincronizar a info de espaço livre em todas as partições FAT32?" + +msgid "Do you wish to update/download all language files?" +msgstr "Deseja atualizar os arquivos de idioma?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "" + +msgid "Download Now" +msgstr "Baixar Agora" + +msgid "Download finished" +msgstr "Download Terminado" + +msgid "Downloading 3D Covers" +msgstr "Baixando Capas 3D" + +msgid "Downloading Custom Banners" +msgstr "Baixando Banners Customizados" + +msgid "Downloading Flat Covers" +msgstr "Baixando Capas Planas" + +msgid "Downloading Full HQ Covers" +msgstr "Baixando Capas Completas HQ" + +msgid "Downloading Full LQ Covers" +msgstr "Baixando Capas Completas LQ" + +msgid "Downloading custom Discarts" +msgstr "Baixando Etiquetas de Disco Personalizadas" + +msgid "Downloading file..." +msgstr "Baixando arquivo..." + +msgid "Downloading image:" +msgstr "Baixando imagem:" + +msgid "Downloading original Discarts" +msgstr "Baixando Imagens de Disco Originais" + +msgid "Downloading pagelist:" +msgstr "Baixando a lista:" + +msgid "Dump NAND to EmuNand" +msgstr "Copiar NAND para EmuNAND" + +msgid "During zoom" +msgstr "Durante zoom" + +msgid "Dutch" +msgstr "Holandês" + +msgid "ERROR" +msgstr "ERRO" + +msgid "ERROR:" +msgstr "ERRO:" + +msgid "ERROR: Can't set up theme." +msgstr "ERRO: Impossível configurar tema." + +msgid "EmuNAND Wad Manager" +msgstr "Gerenciador da EmuNAND" + +msgid "EmuNand Channels" +msgstr "Canais EmuNAND" + +msgid "Emulated Nand" +msgstr "NAND Emulada" + +msgid "English" +msgstr "Inglês" + +msgid "Enter Path" +msgstr "Entrar Caminho" + +msgid "Error" +msgstr "Erro" + +msgid "Error !" +msgstr "Erro !" + +#, c-format +msgid "Error creating path: %s" +msgstr "Erro ao criar caminho: %s" + +msgid "Error opening downloaded file" +msgstr "Erro ao abrir arquivo baixado" + +msgid "Error reading Disc" +msgstr "Erro ao ler o Disco" + +msgid "Error reading disc" +msgstr "Erro ao ler o Disco" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "Erro ao baixar arquivo: %i" + +msgid "Error while downloding file" +msgstr "Erro ao baixar arquivo" + +msgid "Error while opening the zip." +msgstr "Erro ao abrir zip" + +msgid "Error while transfering data." +msgstr "Erro na transferência de dados" + +msgid "Error while updating USB Loader GX." +msgstr "Erro ao atualizar USB Loader GX" + +msgid "Error writing the data." +msgstr "Erro ao escrever os dados" + +msgid "Error:" +msgstr "Erro:" + +msgid "Error: Not enough space on SD." +msgstr "Não há espaço suficiente no Cartão SD" + +msgid "Errors occured." +msgstr "Ocorreram erros." + +msgid "Everything" +msgstr "Tudo" + +msgid "Exit" +msgstr "Sair" + +msgid "Exit to where?" +msgstr "Sair para onde?" + +msgid "Export All Saves to EmuNand" +msgstr "Copiar Saves para EmuNAND" + +msgid "Export Miis to EmuNand" +msgstr "Copiar Miis para EmuNAND" + +msgid "Export SYSCONF to EmuNand" +msgstr "Copiar Opções para EmuNAND" + +msgid "Extract Miis to the Emu NAND?" +msgstr "Copiar Mii para EmuNAND?" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "Copiar Configurações para EmuNAND?" + +msgid "Extract Save to EmuNand" +msgstr "Extrair Gravação para EmuNAND" + +msgid "Extracting file:" +msgstr "Extraindo arquivo:" + +msgid "Extracting files..." +msgstr "Extraindo arquivos..." + +msgid "Extracting files:" +msgstr "Extraindo arquivos:" + +msgid "Extracting nand files:" +msgstr "Extraindo arquivos da NAND:" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "Falhou" + +msgid "Failed copying file" +msgstr "Falha ao copiar" + +msgid "Failed formating" +msgstr "Falha ao formatar" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "Falha ao extrair todos os arquivos. Gravação pode não existir" + +msgid "Failed to extract." +msgstr "Falha ao extrair." + +msgid "Failed to initialize the USB storage device." +msgstr "Falha ao iniciar o dispositivo USB" + +msgid "Failed to open partition" +msgstr "Falha ao abrir partição" + +msgid "Failed to read ticket." +msgstr "Falha ao ler ticket" + +msgid "Failed to read tmd file." +msgstr "Falha ao let arquivo tmd" + +msgid "Failed to read wad header." +msgstr "Falha ao ler o arquivo WAD" + +msgid "Failed updating" +msgstr "Falha ao atualizar" + +msgid "Favorite Level" +msgstr "Estrelas" + +msgid "Features" +msgstr "Funcionalidades" + +msgid "Features Settings" +msgstr "Funcionalidades" + +msgid "Feb" +msgstr "Fev" + +msgid "File" +msgstr "Arquivo" + +msgid "File not found." +msgstr "Arquivo não encontrado" + +msgid "File read/write error." +msgstr "Erro de leitura/escrita" + +msgid "Files extracted successfully." +msgstr "Arquivos extraídos com sucesso" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "Tamanho do arquivo é %i Byte" + +msgid "Filesize is 0 Byte." +msgstr "Tamanho do arquivo é 0 Byte" + +msgid "Flat Covers" +msgstr "Capas Planas" + +msgid "Flip-X" +msgstr "Paginação Horizontal" + +msgid "Folder" +msgstr "Pasta" + +msgid "Font Scale Factor" +msgstr "Tamanho Fonte" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "Forçar NTSC" + +msgid "Force NTSC480p" +msgstr "Forçar NTSC480p" + +msgid "Force PAL480p" +msgstr "Forçar PAL480p" + +msgid "Force PAL50" +msgstr "Forçar PAL50" + +msgid "Force PAL60" +msgstr "Forçar PAL60" + +msgid "Force Titles from Disc" +msgstr "Carregar Nome de Disco" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Formatar" + +msgid "Formatting, please wait..." +msgstr "Formatando, por favor aguarde..." + +msgid "Found missing images." +msgstr "Imagens faltando encontradas" + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "Altura da Moldura" + +msgid "Frame Projection Width" +msgstr "Largura da Moldura" + +msgid "Frame Projection X-Offset" +msgstr "Deslocamento X da Moldura" + +msgid "Frame Projection Y-Offset" +msgstr "Deslocamento Y da Moldura" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "Espaço Livre" + +msgid "French" +msgstr "Francês" + +msgid "Full" +msgstr "Completo" + +msgid "Full Cover Path" +msgstr "Capas Completas" + +msgid "Full Covers" +msgstr "Capas Completas" + +msgid "Full Menu" +msgstr "Menu Completo" + +msgid "Full covers Download" +msgstr "Download de Capas" + +msgid "Full shutdown" +msgstr "Desligar" + +msgid "GAMEID_Gamename" +msgstr "IDJOGO_NomeJogo" + +msgid "GC Banner Scale" +msgstr "Tamanho Banner GC" + +msgid "GC Games" +msgstr "Jogos GameCube" + +msgid "GC Install 32K Aligned" +msgstr "Jogo GC em Setor de 32KB" + +msgid "GC Install Compressed" +msgstr "Comprimir Jogos GC" + +msgid "GCT Cheatcodes Path" +msgstr "Cód. Cheats GCT" + +msgid "GCT File created" +msgstr "Arquivo GCT criado" + +msgid "GUI Settings" +msgstr "Interface" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "Desinstalar Jogos GameCube" + +msgid "Game Cube Install Menu" +msgstr "Instalar Jogos GameCube" + +msgid "Game ID" +msgstr "ID do Jogo" + +msgid "Game IOS" +msgstr "IOS do Jogo" + +msgid "Game Language" +msgstr "Idioma" + +msgid "Game Load" +msgstr "Opções do Jogo" + +msgid "Game Lock" +msgstr "Bloquear Jogo" + +msgid "Game Only" +msgstr "Apenas Jogo" + +msgid "Game Region" +msgstr "Região" + +msgid "Game Size" +msgstr "Tamanho do Jogo" + +msgid "Game Sound Mode" +msgstr "Apresentação de Jogo" + +msgid "Game Sound Volume" +msgstr "Volume da Apresentação" + +msgid "Game Split Size" +msgstr "Dividir Jogo" + +msgid "Game Window Mode" +msgstr "Apresentação de Jogo" + +msgid "Game is already installed:" +msgstr "O jogo já está instalado:" + +msgid "Game's IOS" +msgstr "IOS do Jogo" + +msgid "Game/Install Partition" +msgstr "Partição Padrão" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "Carregar Jogos Usando" + +msgid "GameCube Source" +msgstr "Pasta de Jogos" + +msgid "Gamename [GAMEID]" +msgstr "Nome Jogo [IDJOGO]" + +msgid "Games" +msgstr "Jogos" + +msgid "Generating GXGameCategories.xml" +msgstr "Criando GXGameCategories.xml" + +msgid "Genre:" +msgstr "Tipo:" + +msgid "German" +msgstr "Alemão" + +msgid "Getting file list..." +msgstr "Gerando lista de arquivos..." + +msgid "Getting game folder size..." +msgstr "Gerando tamanho da pasta de jogos..." + +msgid "Global Settings" +msgstr "Definições Globais" + +msgid "Grid Scroll Speed" +msgstr "Veloc. Transição Grade" + +msgid "HOME Menu" +msgstr "" + +msgid "Hard Drive Settings" +msgstr "Armazenamento" + +msgid "High Quality" +msgstr "Alta Qualidade" + +msgid "High/Low" +msgstr "Alta/Baixa" + +msgid "Homebrew Apps Path" +msgstr "Apps Homebrew" + +msgid "Homebrew Channel" +msgstr "Homebrew Channel" + +msgid "Homebrew Launcher" +msgstr "Gestor de Homebrew" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "Horas" + +msgid "How do you want to update?" +msgstr "O que deseja atualizar?" + +msgid "How to Shutdown?" +msgstr "Como desligar o console?" + +msgid "Import Categories" +msgstr "Importar Categorias" + +msgid "Import operation successfully completed." +msgstr "Operação de importação completada com sucesso" + +msgid "Importing categories" +msgstr "Importando categorias" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Recebendo arquivo %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Recebendo arquivo %0.2fMB" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "Iniciando Conexão de Rede" + +msgid "Insert Disk" +msgstr "Insira o Disco" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "Insira um disco de Wii ou GameCube!" + +msgid "Install" +msgstr "Instalar" + +msgid "Install Canceled" +msgstr "Instalação Cancelada" + +msgid "Install Directories" +msgstr "Instalar Diretórios" + +msgid "Install Error!" +msgstr "Erro de Instalação!" + +msgid "Install Partitions" +msgstr "Instalar Partições" + +msgid "Install a game" +msgstr "Instalar um jogo" + +msgid "Install error - Cleaning incomplete data." +msgstr "Erro ao instalar. Apagando dados incompletos" + +msgid "Install finished" +msgstr "Instalação finalizada" + +msgid "Installing Game Cube Game..." +msgstr "Instalando jogo de GameCube..." + +msgid "Installing content" +msgstr "Instalando conteúdo" + +msgid "Installing game:" +msgstr "Instalando jogo:" + +msgid "Installing title..." +msgstr "Instalando..." + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "Número de IOS inválido. Escolha uma IOS entre 200-255" + +msgid "Invalid wad file." +msgstr "Arquivo WAD inválido" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Parece que tem informação que pode ser útil. Por favor envie esta informação à equipe de desenvolvimento" + +msgid "Italian" +msgstr "Italiano" + +msgid "Jan" +msgstr "" + +msgid "Japanese" +msgstr "Japonês" + +msgid "Japanese Patch" +msgstr "Patch Japonês" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "Jul" + +msgid "June" +msgstr "Jun" + +msgid "KPAD Read" +msgstr "Leitura KPAD" + +msgid "Keyboard" +msgstr "Teclado" + +msgid "Korean" +msgstr "Coreano" + +msgid "LED Activity" +msgstr "LED de Atividade" + +msgid "Language Files" +msgstr "Arquivos Idioma" + +msgid "Language change:" +msgstr "Alteração de idioma:" + +msgid "Languagefiles Path" +msgstr "Arquivos de Idioma" + +msgid "Languagepath changed." +msgstr "Caminho para o arquivo de Idioma alterado" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Rodar jogos do Wii com Emulação de Canais ou Saves da NAND só funciona usando a cIOS d2x!" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "Rodar Canais por Emulação da NAND só funciona usando a cIOS d2x!" + +msgid "Left" +msgstr "Esquerda" + +msgid "Like SysMenu" +msgstr "Igual ao Wii Menu" + +msgid "List on Gamelaunch" +msgstr "Lista inicial" + +msgid "Load" +msgstr "Carregar" + +msgid "Load From SD/USB" +msgstr "Carregar do SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Carregar arquivo de: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Carregar este DOL como DOL alternativo?" + +msgid "Loader Settings" +msgstr "Loader" + +msgid "Loader's IOS" +msgstr "IOS do Loader" + +msgid "Loading standard language." +msgstr "Carregando idioma padrão" + +msgid "Loading standard music." +msgstr "Carregando música padrão" + +msgid "Lock Console" +msgstr "Bloquear Console" + +msgid "Lock USB Loader GX" +msgstr "Bloquear USB Loader GX" + +msgid "Locked" +msgstr "Bloqueado" + +msgid "Log to file" +msgstr "Registrar Log" + +msgid "Loop Directory" +msgstr "Repetir Pasta" + +msgid "Loop Music" +msgstr "Repetir Música" + +msgid "Loop Sound" +msgstr "Repetir Sons" + +msgid "Low Quality" +msgstr "Baixa Qualidade" + +msgid "Low/High" +msgstr "Baixa/Alta" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "DOL Principal" + +msgid "Main GameCube Games Path" +msgstr "Caminho Jogos GameCube" + +msgid "Main GameCube Path" +msgstr "Jogos de GameCube" + +msgid "Main Path" +msgstr "Caminho Principal" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "Mar" + +msgid "Mark new games" +msgstr "Marcar jogos novos" + +msgid "May" +msgstr "Mai" + +msgid "Memory Card Blocks Size" +msgstr "Quantidade de Blocos" + +msgid "Memory Card Emulation" +msgstr "Emulação Memory Card" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "Memory Card com 2043 blocos tem problemas com o Nintendont. Use por sua conta e risco" + +msgid "Messageboard Update" +msgstr "Atualizar Messageboard" + +msgid "Motion+ Video" +msgstr "" + +msgid "Mount DVD drive" +msgstr "Rodar Jogo" + +msgid "Mount USB at launch" +msgstr "Montar USB ao iniciar" + +msgid "Move File" +msgstr "Mover Arquivo" + +msgid "Multiple Partitions" +msgstr "Partições múltiplas" + +msgid "Music Loop Mode" +msgstr "Modo de Repetição" + +msgid "Music Volume" +msgstr "Volume Música" + +msgid "NMM Mode" +msgstr "Modo NMM" + +msgid "Nand Chan. Emulation" +msgstr "EmuNAND Canais" + +msgid "Nand Channels" +msgstr "Canais da Memória do Wii" + +msgid "Nand Emu Channel Path" +msgstr "Canais EmuNAND" + +msgid "Nand Emu Path" +msgstr "Pasta EmuNAND" + +msgid "Nand Emulation" +msgstr "Emulação da NAND" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "Emulação da NAND apenas disponível em cIOS D2X!" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "Emulação da NAND apenas funciona em partições FAT/FAT32!" + +msgid "Nand Saves Emulation" +msgstr "EmuNAND Saves" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "Falha ao escolher a pasta para o Neek" + +msgid "Neek kernel file not found." +msgstr "Kernel do Neek não encontrado" + +msgid "Neek kernel loading failed." +msgstr "Não foi possível iniciar o Neek" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "Neek2o não pode ser usado para carregar uma pasta no Cartão SD! Use o Uneek2o para isso" + +msgid "Neither" +msgstr "Nenhum" + +msgid "Network is not initiated." +msgstr "Rede não inicializada" + +msgid "Next" +msgstr "Próximo" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "Nintendont" + +msgid "No" +msgstr "Não" + +msgid "No Cheatfile found" +msgstr "Arquivo de Cheat não encontrado" + +msgid "No DOL file found on disc." +msgstr "Não foi encontrado nenhum arquivo DOL no disco" + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "Não dividir" + +msgid "No URL or Path specified." +msgstr "URL ou Caminho não especificado" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "Nenhuma partição WBFS ou FAT/NTFS/EXT encontrada" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "Wiinnertag.xml não encontrado. Quer criar um arquivo de exemplo?" + +msgid "No change" +msgstr "Sem mudanças" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "Nenhum cheat foi selecionado. Apagar o arquivo GCT antigo?" + +msgid "No data could be read." +msgstr "Não foi possível ler dados" + +msgid "No disc inserted." +msgstr "Nenhum disco inserido" + +msgid "No favorites selected." +msgstr "Nenhum favorito selecionado" + +msgid "No file missing!" +msgstr "Nenhum arquivo faltando!" + +msgid "No games found on the disc" +msgstr "Não há jogos no disco" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "Não foram encontrados arquivos de idioma para atualizar. Deseja baixa-los?" + +msgid "No new updates." +msgstr "Não há novas atualizações" + +msgid "No themes found on the site." +msgstr "Nenhum tema encontrado no site" + +msgid "No themes found." +msgstr "Nenhum tema encontrado" + +msgid "No wad file found in this folder." +msgstr "Nenhum arquivo WAD encontrado" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "Nenhum" + +msgid "Normal" +msgstr "Normal" + +msgid "Not Initialized" +msgstr "Não iniciado" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "Não é um disco de Wii ou GameCube" + +msgid "Not a valid URL" +msgstr "URL inválido" + +msgid "Not a valid URL path" +msgstr "URL inválido" + +msgid "Not a valid domain" +msgstr "Domínio inválido" + +msgid "Not enough free memory." +msgstr "Não há memória livre suficiente" + +msgid "Not enough free space on device." +msgstr "Não há memória livre suficiente" + +msgid "Not enough free space!" +msgstr "Não há espaço livre suficiente!" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "Não há memória suficiente." + +msgid "Not required" +msgstr "Não requerido" + +msgid "Not supported format!" +msgstr "Formato não suportado!" + +msgid "Nothing selected to delete." +msgstr "Nada foi escolhido para apagar" + +msgid "Nothing selected to install." +msgstr "Nada foi escolhido para instalar" + +msgid "Nov" +msgstr "" + +msgid "OFF" +msgstr "NÃO" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "SIM" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "Ocarina não é suportado pelo neek2o. Iniciar mesmo assim?" + +msgid "Oct" +msgstr "" + +msgid "Official Site:" +msgstr "Site Oficial:" + +msgid "Offset" +msgstr "Offset" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "Apenas Partição Jogos" + +msgid "Only for Install" +msgstr "Apenas para instalação" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Originais/Personalizadas" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Controle dos Pais" + +msgid "Partial" +msgstr "Parcial" + +msgid "Partition" +msgstr "Partição" + +msgid "Password" +msgstr "Senha" + +msgid "Password Changed" +msgstr "Senha Alterada" + +msgid "Password has been changed" +msgstr "A senha foi alterada" + +msgid "Patch Country Strings" +msgstr "Patch Jogos Importados" + +msgid "Path Changed" +msgstr "Caminho Alterado" + +msgid "Permission denied." +msgstr "Sem autorização" + +msgid "Pick from a list" +msgstr "Escolher da lista" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Vezes jogadas" + +msgid "Play Next" +msgstr "Próxima" + +msgid "Play Once" +msgstr "Tocar uma vez" + +msgid "Play Previous" +msgstr "Anterior" + +msgid "Playing Music:" +msgstr "Reproduzindo Música:" + +msgid "Please wait" +msgstr "Aguarde" + +msgid "Please wait..." +msgstr "Por favor aguarde..." + +msgid "Power off the Wii" +msgstr "Desligar Wii" + +msgid "Prev" +msgstr "Anterior" + +msgid "Private Server" +msgstr "Servidor Online" + +msgid "Process finished." +msgstr "Processo finalizado" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Mensagens/Botões" + +msgid "Published by" +msgstr "Publicado por" + +msgid "Quick Boot" +msgstr "Boot Rápido" + +msgid "Random Directory Music" +msgstr "Pasta de Música Aleatória" + +msgid "Real Nand" +msgstr "NAND Real" + +msgid "Receiving file from:" +msgstr "Recebendo arquivo de:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "Patch Região" + +msgid "Released" +msgstr "Lançamento" + +msgid "Reload SD" +msgstr "Ler cartão SD" + +msgid "Reloading game list now, please wait..." +msgstr "Recarregando lista de jogos..." + +msgid "Remember Unlock" +msgstr "Lembrar Desbloqueio" + +msgid "Remove Read Speed Limit" +msgstr "Remover limite de leitura" + +msgid "Remove update" +msgstr "Remover atualização" + +msgid "Rename Game Title" +msgstr "Renomear jogo" + +msgid "Rename category" +msgstr "Renomear" + +msgid "Reset" +msgstr "Reiniciar" + +msgid "Reset BG Music" +msgstr "Música padrão" + +msgid "Reset Playcounter" +msgstr "Limpar Contagem" + +msgid "Reset to default BGM?" +msgstr "Voltar à música padrão?" + +msgid "Restarting..." +msgstr "Reiniciando" + +msgid "Return" +msgstr "Voltar" + +msgid "Return To" +msgstr "Voltar a" + +msgid "Return to Wii Menu" +msgstr "Voltar ao Wii Menu" + +msgid "Right" +msgstr "Direita" + +msgid "Rotating Disc" +msgstr "Disco Girando" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Vibração" + +msgid "SChinese" +msgstr "Chinês Simp." + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "Este Cartão SD não pode ser acessado" + +msgid "SD GameCube Games Path" +msgstr "Pasta de jogos de GC no Cartão" + +msgid "SD GameCube Path" +msgstr "Jogos de GC pelo Cartão" + +msgid "SD Path" +msgstr "Caminho do Cartão SD" + +msgid "SFX Volume" +msgstr "Volume Efeitos" + +msgid "Save" +msgstr "Gravar" + +msgid "Save Failed. No device inserted?" +msgstr "Gravação falhou. Nenhum dispositivo ligado?" + +msgid "Save Game List to" +msgstr "Gravar lista de Jogos para" + +msgid "Save List" +msgstr "Lista Gravação" + +msgid "Saved" +msgstr "Gravado" + +msgid "Savegame might not exist for this game." +msgstr "Gravação pode não existir para este jogo" + +msgid "Screensaver" +msgstr "Proteção de Tela" + +msgid "Screenshot" +msgstr "Captura de Tela" + +msgid "Select" +msgstr "Selecionar" + +msgid "Select DOL Offset" +msgstr "Selecionar Offset DOL" + +msgid "Select a DOL" +msgstr "Selecionar um DOL" + +msgid "Select a DOL from Game" +msgstr "Selecionar um DOL do Jogo" + +msgid "Select game categories" +msgstr "Selecionar categorias de jogos" + +msgid "Select loader mode" +msgstr "Modo de Carregamento" + +msgid "Select the NAND Emu Path to use." +msgstr "Escolha a pasta a ser usada pela EmuNAND" + +msgid "Select titles sources." +msgstr "Que conteúdo deseja carregar?" + +msgid "Sept" +msgstr "Set" + +msgid "Set Search-Filter" +msgstr "Pesquisar" + +msgid "Settings" +msgstr "Definições" + +msgid "Settings File" +msgstr "Arquivo de Opções" + +msgid "Show Categories" +msgstr "Mostrar Categorias" + +msgid "Show Favorite on banner" +msgstr "Mostrar Estrelas no Banner" + +msgid "Show Free Space" +msgstr "Mostrar Espaço Livre" + +msgid "Show Play Count" +msgstr "Mostrar Contagem Jogos" + +msgid "Show SD" +msgstr "Mostrar SD" + +msgid "Shutdown System" +msgstr "Desligar" + +msgid "Shutdown Wii" +msgstr "Desligar Wii" + +msgid "Skip Errors" +msgstr "Pular Erros" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "Patch Vídeo Sneek" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "Desculpe, mas não é possível baixar temas por aqui pois http://wii.spiffy360.com requer cadastro de usuário" + +msgid "Sort alphabetically" +msgstr "Ordenar por ordem alfabética" + +msgid "Sort by number of players" +msgstr "Ordenar por nº de jogadores" + +msgid "Sort by rank" +msgstr "Ordenar por Estrelas" + +msgid "Sort order by most played" +msgstr "Ordenar por mais jogados" + +msgid "Sound" +msgstr "Audio" + +msgid "Sound Settings" +msgstr "Áudio" + +msgid "Sound+BGM" +msgstr "Efeitos+Música" + +msgid "Sound+Quiet" +msgstr "Efeitos+Silêncio" + +msgid "Spanish" +msgstr "Espanhol" + +msgid "Special thanks to:" +msgstr "Agradecimentos especiais a:" + +msgid "Split each 2GB" +msgstr "A cada 2GB" + +msgid "Split each 4GB" +msgstr "A cada 4GB" + +msgid "Standby" +msgstr "Standby" + +msgid "Start" +msgstr "Iniciar" + +msgid "Success" +msgstr "Sucesso" + +msgid "Success." +msgstr "Sucesso" + +msgid "Success:" +msgstr "Sucesso:" + +msgid "Successfully Saved" +msgstr "Gravado com Sucesso" + +msgid "Successfully Updated" +msgstr "Atualização Concluída" + +msgid "Successfully copied" +msgstr "Copiado com sucesso" + +msgid "Successfully deleted:" +msgstr "Eliminado com Sucesso:" + +msgid "Successfully extracted theme." +msgstr "Tema extraído com sucesso" + +msgid "Successfully installed:" +msgstr "Instalado com Sucesso:" + +msgid "Successfully updated." +msgstr "Atualizado com sucesso" + +msgid "Switching to channel list mode." +msgstr "Trocando para o modo de visualização de canais" + +msgid "Sync FAT32 FS Info" +msgstr "Sincronizar Info FAT32" + +msgid "Synchronizing..." +msgstr "Sincronizando..." + +msgid "System Default" +msgstr "Padrão" + +msgid "TChinese" +msgstr "Chinês" + +msgid "TXT Cheatcodes Path" +msgstr "Cód. Cheats TXT" + +msgid "The .them file was not found in the zip." +msgstr "O arquivo .them não foi encontrado no zip" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "A opção Forçar Widescreen requer DIOS MIOS v 2.1 ou mais recente" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Os Mii serão extraidos para a EmuNAND. Atenção: Quaisquer arquivos existentes serão sobrepostos" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "A opção No Disc+ requer o DIOS MIOS 2.2 update 2 ou mais recente" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "As configurações do console serão extraídas para a EmuNAND. Atenção: Quaisquer arquivos existentes serão sobrepostos" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "O loader poderá travar se o Cartão SD estiver sendo lido ou escrito!" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "A pasta não existe, pretende criá-la?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "Os arquivos serão extraídos para a EmuNAND. Atenção: Quaisquer arquivos existentes serão sobrepostos" + +msgid "The game is on SD Card." +msgstr "O jogo está no Cartão SD" + +msgid "The game is on USB." +msgstr "O jogo está no USB" + +msgid "The save game will be extracted to your emu nand path." +msgstr "A gravação vai ser extraída para o caminho da EmuNAND" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "O progresso dos jogos serão extraidos para a EmuNAND. Atenção: Quaisquer arquivos existentes serão sobrepostos" + +msgid "The wad file was installed" +msgstr "O arquivo wad foi instalado" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "A instalação do WAD falhou com o erro %i" + +msgid "Theme Downloader" +msgstr "Download de Temas" + +msgid "Theme Menu" +msgstr "Temas" + +msgid "Theme Path" +msgstr "Temas" + +msgid "Theme Title:" +msgstr "Título do Tema:" + +msgid "Themes by www.spiffy360.com" +msgstr "Temas por www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "Este IOS é usado pelo BootMii. Se tem certeza que não é o BootMii e tem outra coisa instalada então ignore este aviso" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "Este IOS não foi encontrado. Se tem certeza que o tem instalado então ignore este aviso" + +msgid "This Nintendont version does not support games on USB." +msgstr "Essa versão do Nintendont não suporta jogos por USB." + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "Essa versão do Nintendont não é suportada. Auto boot desativado" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "Esse jogo utiliza vários discos. Escolha o disco a iniciar" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "Essa pasta precisa estar no Cartão SD!" + +msgid "Time left:" +msgstr "Restam:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Gestor de Títulos" + +msgid "Titles Path" +msgstr "Pasta Títulos" + +msgid "Titles from GameTDB" +msgstr "Títulos do GameTDB" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "Para rodar jogos de GameCube em disco, você precisa definir o modo de GameCube para MIOS nas configurações do jogo" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "Para rodar jogos de GameCube com %s, você precisa de um drive USB formatado em FAT32" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "Para rodar jogos de GameCube com %s, a pasta deverá estar na primeira partição FAT32 do armazenamento" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "Para rodar jogos de GameCube com %s, a pasta deverá estar na primeira partição primária do armazenamento" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "Para rodar jogos de GameCube com %s, a pasta de jogos deverá estar em uma partição FAT32" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "Para rodar jogos de GameCube com %s você precisa de um disco rígido formatado com 512 bytes por setor" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "Para rodar jogos de GameCube com %s, você precisa de um drive particionado com 32KB de setor ou menos." + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "Para rodar jogos de GameCube usando Devolution, o arquivo loader.bin deve estar na pasta padrão do Devolution." + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "Para rodar jogos de GameCube usando Nintendont, você precisa indicar a pasta aonde o arquivo boot.dol do Nintendont está" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "Para usar HID com o %s você precisa do arquivo %s" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "Para usar Neek você precisa configurar a pasta da EmuNAND na primeira partição primária do armazenamento" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "Para usar Neek você precisa configurar a pasta da EmuNAND para uma partição FAT32" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "Para usar Neek vocÊ precisa de um drive formatado com setores de 512 bytes" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "Para usar Ocarina com %s, você precisa do arquivo %s" + +msgid "Tooltip Delay" +msgstr "Atraso do Balão" + +msgid "Tooltips" +msgstr "Balões de dica" + +msgid "Transfer failed" +msgstr "Transferência falhou" + +msgid "Triforce Arcade Mode" +msgstr "Modo Triforce" + +msgid "Two Lines" +msgstr "Duas Linhas" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "Dispositivo USB não encontrado" + +msgid "USB Loader GX is protected" +msgstr "O USB Loader GX está bloqueado" + +msgid "USB Port" +msgstr "Porta USB" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "Mudança de Porta USB apenas suportada no cIOS Hermes" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "USB Loader GX não conseguiu verificar o arquivo boot.dol do Nintendont. Rodar mesmo assim?" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "USB Loader GX não conseguiu gravar configurações do Nintendont. Rodar mesmo assim?" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "USB Loader GX r1218 é exigido para usar o Nintendont Alpha v0.1. Atualize sua versão do Nintendont" + +msgid "Uninstall" +msgstr "Desinstalar" + +msgid "Uninstall Game" +msgstr "Desinstalar jogo" + +msgid "Uninstall Menu" +msgstr "Menu de Desinstalação" + +msgid "Uninstall all" +msgstr "Desinstalar tudo" + +msgid "Unknown" +msgstr "Desconhecido" + +msgid "Unlock USB Loader GX" +msgstr "Desbloquear USB Loader GX" + +msgid "Unlocked" +msgstr "Desbloqueado" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "Formato não suportado, tente extrair manualmente TempTheme.zip" + +msgid "Update" +msgstr "Atualizações" + +msgid "Update All" +msgstr "Atualizar Tudo" + +msgid "Update DOL" +msgstr "Atualizar DOL" + +msgid "Update Files" +msgstr "Atualizar arquivos" + +msgid "Update Path" +msgstr "Atualização" + +msgid "Update all Language Files" +msgstr "Atualizar todos os arquivos de Idioma" + +msgid "Update failed" +msgstr "Atualização falhou" + +msgid "Update successfull" +msgstr "Atualizado com Sucesso" + +msgid "Updating Language Files:" +msgstr "Atualizando arquivos de Idioma:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Arquivo ZIP instalado na pasta de Homebrew" + +msgid "Use System Font" +msgstr "Usar Fonte Sistema" + +msgid "Use global" +msgstr "Usar global" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "" + +msgid "Version:" +msgstr "Versão:" + +#, c-format +msgid "Version: %s" +msgstr "Versão: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Modo de Vídeo" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "Escala Video" + +msgid "Virtual Pointer Speed" +msgstr "Velocidade do Ponteiro" + +msgid "WDM Files Path" +msgstr "Arquivos WDM" + +msgid "WIP Patches Path" +msgstr "Patches WIP" + +msgid "Waiting..." +msgstr "Esperando..." + +msgid "Warning" +msgstr "Aviso" + +msgid "Warning:" +msgstr "Aviso:" + +msgid "What do you want to do?" +msgstr "O que deseja fazer?" + +msgid "What do you want to update?" +msgstr "Que componente deseja atualizar?" + +msgid "What should be deleted for this game title:" +msgstr "O que deve ser apagado para este jogo:" + +msgid "What to extract from NAND?" +msgstr "O que extrair da NAND?" + +msgid "Where should the game be installed to?" +msgstr "Aonde o jogo será instalado?" + +msgid "Where to dump NAND?" +msgstr "Onde extrair a NAND?" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "Qual dispositivo quer usar para os arquivos do Nintendont?" + +msgid "Which mode do you want to use?" +msgstr "Que modo deseja usar?" + +msgid "WiFi Features" +msgstr "Rede Sem Fio" + +msgid "Widescreen Factor" +msgstr "Fator Wide" + +msgid "Widescreen Fix" +msgstr "Correção 16:9" + +msgid "Wii Games" +msgstr "Jogos do Wii" + +msgid "Wii Menu" +msgstr "" + +msgid "Wii Settings" +msgstr "Definições Wii" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "WiiTDB.xml está atualizado" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "Iluminação Leitor" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "Wiinnertag" + +msgid "Wiinnertag Path" +msgstr "Wiinnertag" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Wiinnertag necessita conexão automática à Internet no início do programa. Quer habilitar agora?" + +msgid "Wiird Debugger" +msgstr "Debugger Wiird" + +#, c-format +msgid "Write error on file: %s" +msgstr "Erro de escrita no arquivo: %s" + +msgid "Writing GXGameCategories.xml" +msgstr "Escrevendo GXGameCategories.xml" + +msgid "Wrong Password" +msgstr "Senha Incorreta" + +msgid "Yes" +msgstr "Sim" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "Você escolheu uma partição FAT32/NTFS/EXT com uma cIOS 249 Rev < 18. Isto não é suportado. Continue por sua conta e risco" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "Você pode escolher, formatar ou usar o modo de visualização de canais." + +msgid "You cannot delete this category." +msgstr "Não pode apagar esta categoria" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "Você precisa do neek2o para rodar EmuNAND por subpastas" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "Você precisa instalar o DIOS MIOS Lite 1.2 ou mais recente" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "Você precisa instalar um loader adicional de GameCube ou escolher um modo diferente para carregar jogos por um drive USB ou Cartão SD" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "Sua partição para o GameCube não é compatível. Atualize o Nintendont" + +msgid "Zoom Duration (Speed)" +msgstr "Velocidade do Zoom" + +msgid "and translators for language files updates" +msgstr "e tradutores para as atualizações de idioma" + +msgid "available" +msgstr "disponível" + +msgid "does not exist!" +msgstr "não existe!" + +msgid "does not exist! Loading game without cheats." +msgstr "não existe! Carregando jogo sem cheats" + +msgid "files left" +msgstr "arquivos restantes" + +msgid "for FAT/NTFS support" +msgstr "pelo suporte FAT/NTFS" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "por GameTDB e alojar img. capas / discos" + +msgid "for Ocarina" +msgstr "pelo Ocarina" + +msgid "for diverse patches" +msgstr "por diversos patches" + +msgid "for his awesome tool LibWiiGui" +msgstr "pela sua espetacular ferramenta LibWiiGui" + +msgid "for hosting the themes" +msgstr "por alojar os temas" + +msgid "for the USB Loader source" +msgstr "pelo código do USB Loader" + +msgid "for their work on the wiki page" +msgstr "pelo seu trabalho na Wiki" + +msgid "formatted!" +msgstr "formatado!" + +msgid "free" +msgstr "livres" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "não definido" + +msgid "of" +msgstr "de" + +msgid "seconds left" +msgstr "segundos restantes" + +#~ msgid "Do you want to update this file?" +#~ msgstr "Deseja atualizar esse arquivo?" + +#~ msgid "Install WAD to EmuNand" +#~ msgstr "Instalar WAD para EmuNAND" + +#~ msgid "Update Nintendont" +#~ msgstr "Atualizar Nintendont" + +#~ msgid "WAD Installation" +#~ msgstr "Instalação de WAD" + +#~ msgid "GameTDB Path" +#~ msgstr "GameTDB" + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on a primary partition." +#~ msgstr "Para rodar jogos de GameCube com %s, escolha uma pasta que esteja numa partição primária" + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first partition of the Hard Drive." +#~ msgstr "Para rodar jogos de GameCube com %s, escolha uma pasta que esteja na primeira partição do armazenamento" diff --git a/Languages/portuguese_pt.lang b/Languages/portuguese_pt.lang new file mode 100644 index 0000000..aa94dee --- /dev/null +++ b/Languages/portuguese_pt.lang @@ -0,0 +1,2667 @@ +# USB Loader GX language source file. +# portuguese_pt.lang - r1119 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:05+0200\n" +"PO-Revision-Date: 2011-11-03 11:00+0000\n" +"Last-Translator: pplucky \n" +"Language-Team: Sky8000, pplucky\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " não foi descarregado." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " foi guardado. O texto não foi verificado. Parte do código pode não funcionar correctamente. Se detectares problemas abre o texto com um editor de texto para obteres mais informação." + +msgid " is not on the server." +msgstr " não está no servidor." + +#, c-format +msgid "%i files not found on the server!" +msgstr "%i ficheiros não encontrados no servidor!" + +#, c-format +msgid "%i missing files" +msgstr "%i ficheiros em falta" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Todos)" + +msgid "1 (Child 7+)" +msgstr "1 (Crianças 7+)" + +msgid "1 hour" +msgstr "1 hora" + +msgid "10 min" +msgstr "10 minutos" + +msgid "2 (Teen 12+)" +msgstr "2 (Adolescente 12+)" + +msgid "20 min" +msgstr "20 minutos" + +msgid "2D Cover Path" +msgstr "Cam. Capas 2D" + +msgid "3 (Mature 16+)" +msgstr "3 (Adulto 16+)" + +msgid "3 min" +msgstr "3 minutos" + +msgid "30 min" +msgstr "30 minutos" + +msgid "3D Cover Path" +msgstr "Cam. Capas 3D" + +msgid "3D Covers" +msgstr "Capas 3D" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Adultos 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 minutos" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "AUTO" + +msgid "AXNextFrame" +msgstr "AXNextFrame" + +msgid "Add category" +msgstr "Adicionar categ." + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "Todas" + +msgid "All Partitions" +msgstr "Todas as Partições" + +msgid "All files extracted." +msgstr "Todos os ficheiros extraídos." + +msgid "All images downloaded successfully." +msgstr "Todas as imagens descarregadas com sucesso." + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Todas as funcionalidades desbloqueadas." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "DOL alternativo" + +msgid "An example file was created here:" +msgstr "Ficheiro de exemplo criado aqui:" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "Idioma" + +msgid "Apply" +msgstr "Aplicar" + +msgid "Apr" +msgstr "Abr" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "Tem a certeza que quer apagar esta categoria?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "Tem a certeza que quer importar as categorias de jogos da GameTDB?" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "Tem a certeza que quer bloquear o USB Loader GX?" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "Tem a certeza que quer reinicializar?" + +msgid "Are you sure?" +msgstr "Tem a certeza?" + +msgid "Aspect Ratio" +msgstr "" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "Ago" + +msgid "Author(s):" +msgstr "Autor(es):" + +msgid "Auto" +msgstr "Auto" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "Auto-iniciar Rede" + +msgid "BCA Codes Path" +msgstr "Cam. Códigos BCA" + +msgid "Back" +msgstr "Voltar" + +msgid "Back to HBC or Wii Menu" +msgstr "Voltar ao HBC ou Menu Wii" + +msgid "Backgroundmusic" +msgstr "Música de fundo" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "Agradecimentos:" + +msgid "Block Categories Menu" +msgstr "Bloquear Menu Categorias" + +msgid "Block Categories Modify" +msgstr "Bloquear Modif. Categorias" + +msgid "Block Cover Downloads" +msgstr "Bloquear Descarregar Capas" + +msgid "Block Custom Paths" +msgstr "Bloquear Caminhos Pers." + +msgid "Block Feature Settings" +msgstr "Bloquear Def. Funcionalidades" + +msgid "Block Game Install" +msgstr "Bloquear Instalação Jogo" + +msgid "Block Game Settings" +msgstr "Bloquear Def. Jogo" + +msgid "Block GameID Change" +msgstr "Bloquear Mudança ID Jogo" + +msgid "Block Global Settings" +msgstr "Bloquear Def. Globais" + +msgid "Block Gui Settings" +msgstr "Bloquear Def. GUI" + +msgid "Block HBC Menu" +msgstr "Bloquear Menu HBC" + +msgid "Block Hard Drive Settings" +msgstr "Bloquear Def. Disco Rígido" + +msgid "Block IOS Reload" +msgstr "Bloquear Reload do IOS" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "Bloquear Def. Loader" + +msgid "Block Parental Settings" +msgstr "Bloquear Def. Parental" + +msgid "Block Priiloader Override" +msgstr "" + +msgid "Block Reset Settings" +msgstr "Bloquear Reinicialização Def." + +msgid "Block SD Reload Button" +msgstr "Bloquear Botão SD" + +msgid "Block Sound Settings" +msgstr "Bloquear Def. Som" + +msgid "Block Theme Downloader" +msgstr "Bloquear Descarregar Temas" + +msgid "Block Theme Menu" +msgstr "Bloquear Tema de Menu" + +msgid "Block Title Launcher" +msgstr "Bloquear Gestor de Títulos" + +msgid "Block Updates" +msgstr "Bloquear Actualizações" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "Carregar?" + +msgid "Both" +msgstr "Ambos" + +msgid "Both Ports" +msgstr "Ambas as Portas" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "Títulos em Cache" + +msgid "Can't be formatted" +msgstr "Não pode ser formatado" + +msgid "Can't create directory" +msgstr "Não foi possível criar a pasta" + +#, c-format +msgid "Can't create file: %s" +msgstr "" + +#, c-format +msgid "Can't create path: %s" +msgstr "Não foi possível criar caminho: %s" + +msgid "Can't delete:" +msgstr "Não foi possível apagar:" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "" + +#, c-format +msgid "Can't read file: %s" +msgstr "" + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Cannot write to destination." +msgstr "Não foi possível escrever no destino." + +msgid "Categories" +msgstr "Categorias" + +msgid "Categories:" +msgstr "Categorias:" + +msgid "Change Play Path" +msgstr "Alterar Caminho de Músicas" + +msgid "Channel Launcher" +msgstr "" + +msgid "Channels" +msgstr "" + +msgid "Cheatfile is blank" +msgstr "Ficheiro de batota vazio" + +msgid "Clear" +msgstr "Limpar" + +msgid "Click to Download Covers" +msgstr "Carregue para descarregar capas" + +msgid "Click to change game ID" +msgstr "Carregue para alterar o ID do jogo" + +msgid "Clock" +msgstr "Relógio" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "Fechar" + +msgid "Code Download" +msgstr "Download de Código" + +#, c-format +msgid "Coded by: %s" +msgstr "Programado por: %s" + +msgid "Coding:" +msgstr "Desenvolvimento:" + +msgid "Connection to server timed out." +msgstr "Time out na ligação ao servidor." + +msgid "Console" +msgstr "Consola" + +msgid "Console Default" +msgstr "Predefinição Consola" + +msgid "Console Locked" +msgstr "Consola Bloqueada" + +msgid "Console must be unlocked for this option." +msgstr "Consola tem de estar desbloqueada para esta opção." + +msgid "Console must be unlocked to be able to use this." +msgstr "Consola tem de estar desbloqueada para usar isto." + +msgid "Console should be unlocked to modify it." +msgstr "Consola deve estar desbloqueada para modificar o parâmetro." + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "Continuar instalação do jogo?" + +msgid "Continue?" +msgstr "Continuar?" + +msgid "Controllevel" +msgstr "Nível de Controle" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "Password Correcta" + +msgid "Could not connect to the server." +msgstr "Não foi possível ligação ao servidor." + +msgid "Could not create GCT file" +msgstr "Não foi possível criar o ficheiro GCT" + +#, c-format +msgid "Could not create path: %s" +msgstr "Não foi possível criar caminho: %s" + +msgid "Could not extract files for:" +msgstr "Não foi possível extrair ficheiros para:" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "Não foi encontrada info do jogo no wiitdb.xml" + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "Não foi possível inicializar o módulo DIP!" + +msgid "Could not initialize network!" +msgstr "Não foi possível incializar a Ligação de Rede!" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "Não foi possível abrir o Disco" + +msgid "Could not open the WiiTDB.xml file." +msgstr "Não foi possível abrir o ficheiro WiiTDB.xml." + +msgid "Could not open wiitdb.xml." +msgstr "Não foi possível abrir o wiitdb.xml" + +msgid "Could not save." +msgstr "Não foi possível gravar." + +msgid "Could not write file." +msgstr "Não foi possível escrever ficheiro." + +msgid "Could not write to:" +msgstr "Não foi possível escrever para:" + +msgid "Cover Download" +msgstr "Download de Capas" + +msgid "Create" +msgstr "Criar" + +msgid "Credits" +msgstr "Créditos" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "Caminhos Personalizados" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "Personalizadas/Originais" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "Cam. DOL" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "Parado Início Debugger" + +msgid "Dec" +msgstr "Dez" + +msgid "Default" +msgstr "Predefinida/o" + +msgid "Default Gamesettings" +msgstr "Definições Jogo Predefinidas" + +msgid "Default Settings" +msgstr "Definições Predefinidas" + +msgid "Delete" +msgstr "Eliminar" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "Eliminar Batota GCT" + +msgid "Delete Cheat TXT" +msgstr "Eliminar Batota TXT" + +msgid "Delete Cover Artwork" +msgstr "Eliminar Capas" + +msgid "Delete Disc Artwork" +msgstr "Eliminar Imagem Disco" + +msgid "Delete category" +msgstr "Apagar categ." + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "Design:" + +msgid "Details" +msgstr "Detalhes" + +msgid "Developed by" +msgstr "Desenvolvido por" + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "Pasta não existe!" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "Descarregar Imagens Disco" + +msgid "Disc Artwork Path" +msgstr "Cam. Imagens Disco" + +msgid "Disc Default" +msgstr "Predefinição Disco" + +msgid "Disc Insert Detected" +msgstr "" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "Voltar Disco" + +msgid "Display" +msgstr "Mostrar" + +msgid "Display as a carousel" +msgstr "Mostrar como carrossel" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "Mostrar como grelha" + +msgid "Display as a list" +msgstr "Mostrar como lista" + +msgid "Display favorites only" +msgstr "Apenas Favoritos" + +msgid "Do you want to apply it now?" +msgstr "Deseja aplicar agora?" + +msgid "Do you want to apply this theme?" +msgstr "Deseja aplicar este tema?" + +msgid "Do you want to change language?" +msgstr "Deseja alterar o idioma?" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "Deseja descarregar este tema?" + +msgid "Do you want to extract all the save games?" +msgstr "Deseja extrair todas as gravações?" + +msgid "Do you want to extract the save game?" +msgstr "Deseja extrair esta gravação?" + +msgid "Do you want to format:" +msgstr "Deseja FORMATAR:" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "Deseja carregar o tema por defeito?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "Deseja reinicializar a rede?" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "Deseja sincronizar a info de espaço livre em todas as partições FAT32?" + +msgid "Do you wish to update/download all language files?" +msgstr "Queres actualizar todos os ficheiros de idioma?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "Descarregar" + +msgid "Download Now" +msgstr "Descarregar Agora" + +msgid "Download finished" +msgstr "Descarga Terminada" + +msgid "Downloading 3D Covers" +msgstr "A Descarregar Capas 3D" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "A Descarregar Capas Planas" + +msgid "Downloading Full HQ Covers" +msgstr "A Descarregar Capas Completas HQ" + +msgid "Downloading Full LQ Covers" +msgstr "A Descarregar Capas Completas LQ" + +msgid "Downloading custom Discarts" +msgstr "A Descarregar Imagens Disco Personalizadas" + +msgid "Downloading file..." +msgstr "A Descarregar ficheiro..." + +msgid "Downloading image:" +msgstr "A Descarregar imagem:" + +msgid "Downloading original Discarts" +msgstr "A Descarregar Imagens Disco Originais" + +msgid "Downloading pagelist:" +msgstr "A Descarregar a lista:" + +msgid "Dump NAND to EmuNand" +msgstr "Sacar NAND para EmuNand" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "Holandês" + +msgid "ERROR" +msgstr "ERRO" + +msgid "ERROR:" +msgstr "ERRO:" + +msgid "ERROR: Can't set up theme." +msgstr "ERRO: Impossível configurar tema." + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "" + +msgid "Emulated Nand" +msgstr "" + +msgid "English" +msgstr "Inglês" + +msgid "Enter Path" +msgstr "Entrar Caminho" + +msgid "Error" +msgstr "Erro" + +msgid "Error !" +msgstr "Erro !" + +#, c-format +msgid "Error creating path: %s" +msgstr "Erro a criar caminho: %s" + +msgid "Error opening downloaded file" +msgstr "Erro ao abrir ficheiro descarregado" + +msgid "Error reading Disc" +msgstr "Erro ao ler o Disco" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "Erro ao descarregar ficheiro: %i" + +msgid "Error while downloding file" +msgstr "Erro ao descarregar ficheiro" + +msgid "Error while opening the zip." +msgstr "Erro ao abrir zip." + +msgid "Error while transfering data." +msgstr "Erro na transferência de dados." + +msgid "Error while updating USB Loader GX." +msgstr "Erro ao actualizar USB Loader GX." + +msgid "Error writing the data." +msgstr "Erro ao escrever os dados." + +msgid "Error:" +msgstr "Erro:" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "Ocorreram erros." + +msgid "Everything" +msgstr "Tudo" + +msgid "Exit" +msgstr "Sair" + +msgid "Exit to where?" +msgstr "Sair para onde?" + +msgid "Export All Saves to EmuNand" +msgstr "Extrair Todas as Gravações para EmuNand" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "Extrair Gravação para EmuNand" + +msgid "Extracting file:" +msgstr "A extrair ficheiro:" + +msgid "Extracting files..." +msgstr "A Extrair ficheiros..." + +msgid "Extracting files:" +msgstr "A extrair ficheiros:" + +msgid "Extracting nand files:" +msgstr "A extrair ficheiros nand:" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "Falhou" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "Falha ao formatar" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "Falha ao extrair todos os ficheiros. Gravação pode não existir." + +msgid "Failed to extract." +msgstr "Falha ao extrair." + +msgid "Failed to initialize the USB storage device." +msgstr "" + +msgid "Failed to open partition" +msgstr "Falha ao abrir partição" + +msgid "Failed to read ticket." +msgstr "" + +msgid "Failed to read tmd file." +msgstr "" + +msgid "Failed to read wad header." +msgstr "" + +msgid "Failed updating" +msgstr "Falha ao actualizar" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "Funcionalidades" + +msgid "Features Settings" +msgstr "Def. Funcionalidades" + +msgid "Feb" +msgstr "Fev" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Ficheiro não encontrado." + +msgid "File read/write error." +msgstr "" + +msgid "Files extracted successfully." +msgstr "Ficheiros extraídos com sucesso." + +#, c-format +msgid "Filesize is %i Byte." +msgstr "Tamanho ficheiro é %i Byte." + +msgid "Filesize is 0 Byte." +msgstr "Tamanho ficheiro é 0 Byte." + +msgid "Flat Covers" +msgstr "Capas Planas" + +msgid "Flip-X" +msgstr "Paginação Horizontal" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "Factor Escala Fonte" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "Forçar NTSC" + +msgid "Force NTSC480p" +msgstr "Forçar NTSC480p" + +msgid "Force PAL480p" +msgstr "Forçar PAL480p" + +msgid "Force PAL50" +msgstr "Forçar PAL50" + +msgid "Force PAL60" +msgstr "Forçar PAL60" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Formatar" + +msgid "Formatting, please wait..." +msgstr "A Formatar, por favor aguarde..." + +msgid "Found missing images." +msgstr "Imagens em falta encontradas." + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "Espaço Livre" + +msgid "French" +msgstr "Francês" + +msgid "Full" +msgstr "Completo" + +msgid "Full Cover Path" +msgstr "Cam. Capas Completas" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "Menu Completo" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "Shutdown" + +msgid "GAMEID_Gamename" +msgstr "IDJOGO_NomeJogo" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "Cam. Cód. Batota GCT" + +msgid "GCT File created" +msgstr "Ficheiro GCT criado" + +msgid "GUI Settings" +msgstr "Definições do Interface" + +msgid "GXDraw" +msgstr "GXDraw" + +msgid "GXFlush" +msgstr "GXFlush" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "ID do Jogo" + +msgid "Game IOS" +msgstr "IOS do Jogo" + +msgid "Game Language" +msgstr "Idioma" + +msgid "Game Load" +msgstr "Carregamento Jogo" + +msgid "Game Lock" +msgstr "Bloqueio Jogos" + +msgid "Game Only" +msgstr "Apenas Jogo" + +msgid "Game Region" +msgstr "Região" + +msgid "Game Size" +msgstr "Tamanho do Jogo" + +msgid "Game Sound Mode" +msgstr "Definições de Audio Jogo" + +msgid "Game Sound Volume" +msgstr "Volume de Som do Jogo" + +msgid "Game Split Size" +msgstr "Tamanho Partição Jogo" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "O jogo já está instalado:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "Jogo/Partição Instalação" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "Nome Jogo [IDJOGO]" + +msgid "Games" +msgstr "Jogos" + +msgid "Generating GXGameCategories.xml" +msgstr "A gerar GXGameCategories.xml" + +msgid "Genre:" +msgstr "Tipo:" + +msgid "German" +msgstr "Alemão" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "Definições Globais" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "Menu HOME" + +msgid "Hard Drive Settings" +msgstr "Definições de Disco Rígido" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "Cam. Apps Homebrew" + +msgid "Homebrew Channel" +msgstr "Homebrew Channel" + +msgid "Homebrew Launcher" +msgstr "Gestor de Homebrew" + +msgid "Hooktype" +msgstr "Tipo Hook" + +msgid "Hour" +msgstr "Horas" + +msgid "How do you want to update?" +msgstr "O que deseja actualizar?" + +msgid "How to Shutdown?" +msgstr "Como desligar a consola?" + +msgid "Import Categories" +msgstr "Importar Categorias" + +msgid "Import operation successfully completed." +msgstr "Operação de importação completada com sucesso." + +msgid "Importing categories" +msgstr "A importar categorias" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "A receber ficheiro %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "A receber ficheiro %0.2fMB" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "A inicializar Ligação de Rede" + +msgid "Insert Disk" +msgstr "Insira o Disco" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "Instalar" + +msgid "Install Canceled" +msgstr "" + +msgid "Install Directories" +msgstr "Instalar Directórios" + +msgid "Install Error!" +msgstr "Erro de Instalação!" + +msgid "Install Partitions" +msgstr "Instalar Partições" + +msgid "Install a game" +msgstr "Instalar um jogo" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "Instalação finalizada" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "" + +msgid "Installing game:" +msgstr "A instalar jogo:" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Parece que tem informação que pode ser útil. Por favor envie esta informação à equipa de desenvolvimento." + +msgid "Italian" +msgstr "Italiano" + +msgid "Jan" +msgstr "Jan" + +msgid "Japanese" +msgstr "Japonês" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "Joypad" + +msgid "July" +msgstr "Jul" + +msgid "June" +msgstr "Jun" + +msgid "KPAD Read" +msgstr "Leitura KPAD" + +msgid "Keyboard" +msgstr "Teclado" + +msgid "Korean" +msgstr "Coreano" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "Ficheiros Idioma" + +msgid "Language change:" +msgstr "Alteração de idioma:" + +msgid "Languagefiles Path" +msgstr "Cam. ficheiros Idioma" + +msgid "Languagepath changed." +msgstr "Caminho para o ficheiro de Idioma alterado." + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Left" +msgstr "Esquerda" + +msgid "Like SysMenu" +msgstr "Igual ao Menu Wii" + +msgid "List on Gamelaunch" +msgstr "Lista inicial" + +msgid "Load" +msgstr "Carregar" + +msgid "Load From SD/USB" +msgstr "Carregar do SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Carregar ficheiro de: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Carregar este DOL como DOL alternativo?" + +msgid "Loader Settings" +msgstr "Definições do Loader" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "A carregar idioma padrão." + +msgid "Loading standard music." +msgstr "A carregar música padrão." + +msgid "Lock Console" +msgstr "Bloquear Consola" + +msgid "Lock USB Loader GX" +msgstr "Bloquear USB Loader GX" + +msgid "Locked" +msgstr "Bloqueado" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "Repetir Pasta" + +msgid "Loop Music" +msgstr "Repetir Música" + +msgid "Loop Sound" +msgstr "Repetir Sons" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "Mar" + +msgid "Mark new games" +msgstr "Marcar jogos novos" + +msgid "May" +msgstr "Mai" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "Update Placard Mensagens" + +msgid "Motion+ Video" +msgstr "Vídeo Motion+" + +msgid "Mount DVD drive" +msgstr "Montar Unidade de DVD" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "Partições múltiplas" + +msgid "Music Loop Mode" +msgstr "Modo de Repetição" + +msgid "Music Volume" +msgstr "Volume Música" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "" + +msgid "Nand Channels" +msgstr "" + +msgid "Nand Emu Channel Path" +msgstr "" + +msgid "Nand Emu Path" +msgstr "Caminho Nand Emu" + +msgid "Nand Emulation" +msgstr "Emulação Nand" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "Emulação Nand apenas disponível em cIOS D2X!" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "Emulação Nand apenas funciona em partições FAT/FAT32!" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Nenhum" + +msgid "Network is not initiated." +msgstr "Rede não inicializada." + +msgid "Next" +msgstr "Próximo" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "Não" + +msgid "No Cheatfile found" +msgstr "Ficheiro de Batota não encontrado" + +msgid "No DOL file found on disc." +msgstr "Não foi encontrado nenhum ficheiro DOL no disco" + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "Sem Partição" + +msgid "No URL or Path specified." +msgstr "URL ou Caminho não especificado." + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "Nenhuma partição WBFS ou FAT/NTFS/EXT encontrada" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "Ficheiro Wiinnertag.xml não encontrado. Quer criar um ficheiro de exemplo?" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "Não foi possível ler dados." + +msgid "No disc inserted." +msgstr "Nenhum disco inserido." + +msgid "No favorites selected." +msgstr "Nenhum favorito seleccionado" + +msgid "No file missing!" +msgstr "Nenhum ficheiro em falta!" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "" + +msgid "No new updates." +msgstr "Não existem novas actualizações." + +msgid "No themes found on the site." +msgstr "Nenhum tema encontrado no site." + +msgid "No themes found." +msgstr "Nenhum tema encontrado." + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "Nenhum" + +msgid "Normal" +msgstr "Normal" + +msgid "Not Initialized" +msgstr "" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "URL inválido" + +msgid "Not a valid URL path" +msgstr "URL inválido" + +msgid "Not a valid domain" +msgstr "Domínio inválido" + +msgid "Not enough free memory." +msgstr "Não há memória livre suficiente." + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "Não há espaço livre suficiente!" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "Não há memória suficiente." + +msgid "Not required" +msgstr "Não requerido" + +msgid "Not supported format!" +msgstr "Formato não suportado!" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "Nov" + +msgid "OFF" +msgstr "OFF" + +msgid "OK" +msgstr "OK" + +msgid "ON" +msgstr "ON" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "OSSleepThread" + +msgid "Ocarina" +msgstr "Ocarina" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Out" + +msgid "Official Site:" +msgstr "Site Oficial:" + +msgid "Offset" +msgstr "Offset" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "Apenas Partição Jogos" + +msgid "Only for Install" +msgstr "Apenas para instalação" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Originais/Personalizadas" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Controlo Parental" + +msgid "Partial" +msgstr "Parcial" + +msgid "Partition" +msgstr "Partição" + +msgid "Password" +msgstr "Password" + +msgid "Password Changed" +msgstr "Password Alterada" + +msgid "Password has been changed" +msgstr "A Password foi alterada" + +msgid "Patch Country Strings" +msgstr "Patch Jogos Importados" + +msgid "Path Changed" +msgstr "Caminho Alterado" + +msgid "Permission denied." +msgstr "Sem autorização." + +msgid "Pick from a list" +msgstr "Escolher da lista" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Vezes jogadas" + +msgid "Play Next" +msgstr "Próxima" + +msgid "Play Once" +msgstr "Tocar uma vez" + +msgid "Play Previous" +msgstr "Anterior" + +msgid "Playing Music:" +msgstr "A reproduzir Música:" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "Por favor aguarde..." + +msgid "Power off the Wii" +msgstr "Desligar Wii" + +msgid "Prev" +msgstr "Anterior" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "Processo finalizado." + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Mensagens/Botões" + +msgid "Published by" +msgstr "Publicado por" + +msgid "Quick Boot" +msgstr "Arranque Rápido" + +msgid "Random Directory Music" +msgstr "Pasta de Música Aleatória" + +msgid "Real Nand" +msgstr "" + +msgid "Receiving file from:" +msgstr "A receber ficheiro de:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "Patch Região" + +msgid "Released" +msgstr "Lançamento" + +msgid "Reload SD" +msgstr "Ler cartão SD" + +msgid "Reloading game list now, please wait..." +msgstr "A reler lista de jogos, pf aguarde..." + +msgid "Remember Unlock" +msgstr "Lembrar Desbloqueio" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "Remover actualização" + +msgid "Rename Game Title" +msgstr "Renomear jogo" + +msgid "Rename category" +msgstr "Renomear categ." + +msgid "Reset" +msgstr "Reinicializar" + +msgid "Reset BG Music" +msgstr "Reinicializar Música de Fundo" + +msgid "Reset Playcounter" +msgstr "Limpar Contagem" + +msgid "Reset to default BGM?" +msgstr "Reinicializar Mús. Fundo predefinida?" + +msgid "Restarting..." +msgstr "A reiniciar" + +msgid "Return" +msgstr "Voltar" + +msgid "Return To" +msgstr "Voltar a" + +msgid "Return to Wii Menu" +msgstr "Voltar ao Menu Wii" + +msgid "Right" +msgstr "Direita" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Vibração" + +msgid "SChinese" +msgstr "Chinês Simplificado" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "Volume Efeitos" + +msgid "Save" +msgstr "Gravar" + +msgid "Save Failed. No device inserted?" +msgstr "Gravação falhou. Nenhum dispositivo ligado?" + +msgid "Save Game List to" +msgstr "Gravar lista de Jogos para" + +msgid "Save List" +msgstr "Lista Gravação" + +msgid "Saved" +msgstr "Gravado" + +msgid "Savegame might not exist for this game." +msgstr "Gravação pode não existir para este jogo." + +msgid "Screensaver" +msgstr "Protector de ecrã" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "Seleccionar" + +msgid "Select DOL Offset" +msgstr "Seleccionar Offset DOL" + +msgid "Select a DOL" +msgstr "Seleccionar um DOL" + +msgid "Select a DOL from Game" +msgstr "Seleccionar um DOL do Jogo" + +msgid "Select game categories" +msgstr "Seleccionar categorias de jogos" + +msgid "Select loader mode" +msgstr "" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "" + +msgid "Sept" +msgstr "Set" + +msgid "Set Search-Filter" +msgstr "Pesquisar" + +msgid "Settings" +msgstr "Definições" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "Mostrar Categorias" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "Mostrar Espaço Livre" + +msgid "Show Play Count" +msgstr "Mostrar Contagem Jogos" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "Desligar" + +msgid "Shutdown Wii" +msgstr "Desligar Wii" + +msgid "Skip Errors" +msgstr "Saltar Erros" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "Patch Vídeo Sneek" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Ordenar por ordem alfabética" + +msgid "Sort by number of players" +msgstr "Ordenar por nº de jogadores" + +msgid "Sort by rank" +msgstr "Ordenar por classificação" + +msgid "Sort order by most played" +msgstr "Ordenar por mais jogados" + +msgid "Sound" +msgstr "Audio" + +msgid "Sound Settings" +msgstr "Definições de Som" + +msgid "Sound+BGM" +msgstr "Efeitos+Música" + +msgid "Sound+Quiet" +msgstr "Efeitos+Silêncio" + +msgid "Spanish" +msgstr "Espanhol" + +msgid "Special thanks to:" +msgstr "Agradecimentos especiais a:" + +msgid "Split each 2GB" +msgstr "Partir a cada 2GB" + +msgid "Split each 4GB" +msgstr "Partir a cada 4GB" + +msgid "Standby" +msgstr "Standby" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "Sucesso" + +msgid "Success." +msgstr "Sucesso." + +msgid "Success:" +msgstr "Sucesso:" + +msgid "Successfully Saved" +msgstr "Gravado com Sucesso" + +msgid "Successfully Updated" +msgstr "Actualização Concluída" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "Eliminado com Sucesso:" + +msgid "Successfully extracted theme." +msgstr "Tema extraído com sucesso." + +msgid "Successfully installed:" +msgstr "Instalado com Sucesso:" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "" + +msgid "Sync FAT32 FS Info" +msgstr "Sincronizar Info FAT32" + +msgid "Synchronizing..." +msgstr "A sincronizar" + +msgid "System Default" +msgstr "Predefinição Sistema" + +msgid "TChinese" +msgstr "Chinês Tradicional" + +msgid "TXT Cheatcodes Path" +msgstr "Cam. Cód. Batotas TXT" + +msgid "The .them file was not found in the zip." +msgstr "O ficheiro .them não foi encontrado no zip" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "A pasta não existe, pretende criá-la?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "A gravação vai ser extraída para o caminho da emu nand." + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "O ficheiro wad foi instalado" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "A instalação do wad falhou com o erro %i" + +msgid "Theme Downloader" +msgstr "Descarregar Temas" + +msgid "Theme Menu" +msgstr "Menu Temas" + +msgid "Theme Path" +msgstr "Cam. Temas" + +msgid "Theme Title:" +msgstr "Título do Tema:" + +msgid "Themes by www.spiffy360.com" +msgstr "Temas por www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "Este IOS é o ios BootMii. Se tem a certeza que não é o BootMii e tem outra coisa instalada então ignore este aviso." + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "Este IOS não foi encontrado na lista de títulos. Se tem a certeza que o tem instalado então ignore este aviso." + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "Tempo rem:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Gestor de Títulos" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "Títulos do GameTDB" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "Dicas" + +msgid "Transfer failed" +msgstr "Transferência falhada" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "O USB Loader GX está bloqueado" + +msgid "USB Port" +msgstr "Porta USB" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "Mudança de Porta USB apenas suportada no cIOS Hermes" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "" + +msgid "Uninstall Game" +msgstr "Desinstalar jogo" + +msgid "Uninstall Menu" +msgstr "Menu de Desinstalação" + +msgid "Uninstall all" +msgstr "Desinstalar tudo" + +msgid "Unknown" +msgstr "Desconhecido" + +msgid "Unlock USB Loader GX" +msgstr "Desbloquear USB Loader GX" + +msgid "Unlocked" +msgstr "Desbloqueado" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "Formato não suportado, tente extrair manualmente TempTheme.zip." + +msgid "Update" +msgstr "Actualizações" + +msgid "Update All" +msgstr "Actualizar Tudo" + +msgid "Update DOL" +msgstr "Actualizar DOL" + +msgid "Update Files" +msgstr "Actualizar ficheiros" + +msgid "Update Path" +msgstr "Cam. Actualização" + +msgid "Update all Language Files" +msgstr "Actualizar todos os ficheiros de Idioma" + +msgid "Update failed" +msgstr "Actualização falhada" + +msgid "Update successfull" +msgstr "Actualização com sucesso" + +msgid "Updating Language Files:" +msgstr "A actualizar ficheiros de Idioma:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Ficheiro ZIP instalado na pasta de Homebrew." + +msgid "Use System Font" +msgstr "Usar Fonte Sistema" + +msgid "Use global" +msgstr "Usar global" + +msgid "VBI (Default)" +msgstr "VBI (Predefinido)" + +msgid "VIDTV Patch" +msgstr "Patch VIDTV" + +msgid "Version:" +msgstr "Versão:" + +#, c-format +msgid "Version: %s" +msgstr "Versão: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Modo de Vídeo" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "" + +msgid "WDM Files Path" +msgstr "Cam. Ficheiros WDM" + +msgid "WIP Patches Path" +msgstr "Cam. Patches WIP" + +msgid "Waiting..." +msgstr "A aguardar..." + +msgid "Warning" +msgstr "Aviso" + +msgid "Warning:" +msgstr "Aviso:" + +msgid "What do you want to do?" +msgstr "" + +msgid "What do you want to update?" +msgstr "Que componente deseja actualizar?" + +msgid "What should be deleted for this game title:" +msgstr "O que deve ser apagado para este jogo:" + +msgid "What to extract from NAND?" +msgstr "O que extrair da NAND?" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "Rede sem fios" + +msgid "Widescreen Factor" +msgstr "Factor Ecrã Panorâmico" + +msgid "Widescreen Fix" +msgstr "Correcção 16:9" + +msgid "Wii Games" +msgstr "" + +msgid "Wii Menu" +msgstr "Menu Wii" + +msgid "Wii Settings" +msgstr "Definições Wii" + +msgid "WiiTDB.xml" +msgstr "WiiTDB.xml" + +msgid "WiiTDB.xml is up to date." +msgstr "WiiTDB.xml está actualizado." + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "Iluminação Leitor" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "Wiinnertag" + +msgid "Wiinnertag Path" +msgstr "Cam. Wiinnertag" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Wiinnertag necessita ligação automática à rede no arranque da aplicação. Quer habilitar agora?" + +msgid "Wiird Debugger" +msgstr "Debugger Wiird" + +#, c-format +msgid "Write error on file: %s" +msgstr "" + +msgid "Writing GXGameCategories.xml" +msgstr "A escrever GXGameCategories.xml" + +msgid "Wrong Password" +msgstr "Password Incorrecta" + +msgid "Yes" +msgstr "Sim" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "Está a tentar seleccionar uma partição FAT32/NTFS/EXT com um cIOS 249 Rev < 18. Isto não é suportado. Continue por sua conta e risco." + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "" + +msgid "You cannot delete this category." +msgstr "Não pode apagar esta categoria." + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "e tradutores para as actualizações de idioma" + +msgid "available" +msgstr "disponível" + +msgid "does not exist!" +msgstr "não existe!" + +msgid "does not exist! Loading game without cheats." +msgstr "não existe! A carregar jogo sem batotas." + +msgid "files left" +msgstr "ficheiros restantes" + +msgid "for FAT/NTFS support" +msgstr "pelo suporte FAT/NTFS" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "por GameTDB e alojar img. capas / discos" + +msgid "for Ocarina" +msgstr "pelo Ocarina" + +msgid "for diverse patches" +msgstr "por diversos patches" + +msgid "for his awesome tool LibWiiGui" +msgstr "pela sua espectacular ferramenta LibWiiGui" + +msgid "for hosting the themes" +msgstr "por alojar os temas" + +msgid "for the USB Loader source" +msgstr "pelo código do USB Loader" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "formatado!" + +msgid "free" +msgstr "livres" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "não definido" + +msgid "of" +msgstr "de" + +msgid "seconds left" +msgstr "segundos restantes" + +#~ msgid "GameTDB Path" +#~ msgstr "Cam. GameTDB" + +#~ msgid "Anti" +#~ msgstr "Anti" + +#~ msgid "Error 002 fix" +#~ msgstr "Correcção Erro 002" + +#~ msgid "Main tester:" +#~ msgstr "Tester principal:" + +#~ msgid "Boot/Standard" +#~ msgstr "Arranque/Std" + +#~ msgid "Custom Discarts" +#~ msgstr "Imagens Disco Personalizadas" + +#~ msgid "Full HQ Covers" +#~ msgstr "Capas Completas HQ" + +#~ msgid "Full LQ Covers" +#~ msgstr "Capas Completas LQ" + +#~ msgid "Original Discarts" +#~ msgstr "Imagens Disco Originais" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "Renomear jogo (WBFS)" + +#~ msgid "Successfully Updated thanks to www.techjawa.com" +#~ msgstr "Actualizado com sucesso graças a www.techjawa.com" + +#~ msgid "for hosting the update files" +#~ msgstr "por alojar actualizações" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Insira um Disco da Wii!" + +#~ msgid "Issue manager /" +#~ msgstr "Gestor problemas /" + +#~ msgid "No cheats were selected" +#~ msgstr "Não foram seleccionados batotas" + +#~ msgid "Not a Wii Disc" +#~ msgstr "Não é um Disco da Wii" + +#~ msgid "The files will be extracted to your emu nand path. Attention: All existing files will be overwritten." +#~ msgstr "Os ficheiros serão extraídos para o caminho da emu nand. Atenção: Todos os ficheiros existentes serão sobrepostos." + +#~ msgid "The save games will be extracted to your emu nand path. Attention: All existing saves will be overwritten." +#~ msgstr "As gravações vão ser extraídas para o caminho da emu nand. Atenção: Todas as gravações existentes serão sobrepostas." + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> A eliminar tickets..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> A eliminar tickets... ERRO! " + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> A eliminar tickets... Ok! " + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> A eliminar título... ERRO! " + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> A eliminar título... Ok!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> A eliminar conteúdos do título..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> A eliminar conteúdos do título... ERRO! " + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> A eliminar conteúdos do título... Ok!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> A eliminar título..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> A finalizar instalação..." + +#~ msgid ">> Installing content #" +#~ msgstr ">> A instalar conteúdo #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> A instalar ticket..." + +#~ msgid ">> Installing title..." +#~ msgstr ">> A instalar título..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> A ler ficheiro WAD..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> A ler ficheiro WAD... ERRO!" + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> A ler ficheiro WAD... Ok!" + +#~ msgid "Done!" +#~ msgstr "Concluído!" + +#~ msgid "Error..." +#~ msgstr "Erro..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "A terminar instalação... Ok!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "A instalar conteúdo... Ok!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "A instalar ticket... Ok!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "A instalar título... Ok!" + +#~ msgid "Installing wad" +#~ msgstr "A instalar wad" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "A ler dados do WAD... Ok!" + +#~ msgid "Uninstalling wad" +#~ msgstr "A desinstalar wad" + +#~ msgid "The game installation is disabled under this IOS because of instability in usb write." +#~ msgstr "A instalação de jogo está desabilitada neste IOS devido a instabilidade na escrita usb" + +#~ msgid "You are currently using IOS" +#~ msgstr "Está a usar o IOS" + +#~ msgid "New Disc Detected" +#~ msgstr "Novo Disco Detectado" + +#~ msgid "USB Device not found" +#~ msgstr "Dispositivo USB não encontrado" + +#~ msgid "You need to select or format a partition" +#~ msgstr "Necessita seleccionar ou formatar uma partição" + +#~ msgid "Language File" +#~ msgstr "Idiomas" + +#~ msgid "Are you sure you want to import game categories from WiiTDB?" +#~ msgstr "Tem a certeza que quer importar as categorias de jogos da WiiTDB?" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Títulos do WiiTDB" + +#~ msgid "WiiTDB Files" +#~ msgstr "WiiTDB" + +#~ msgid "WiiTDB Path" +#~ msgstr "Cam. WiiTDB" + +#~ msgid "WiiTDB is up to date." +#~ msgstr "WiiTDB está actualizado." + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "por WiiTDB e alojar img. capas / discos" diff --git a/Languages/russian.lang b/Languages/russian.lang new file mode 100644 index 0000000..210854a --- /dev/null +++ b/Languages/russian.lang @@ -0,0 +1,2931 @@ +# USB Loader GX language source file. +# russian.lang - r885 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:05+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: nikolai_ca\n" +"Language-Team: Kir, alendit, nikolai_ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " не мог быть загружен" + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " был сохранен. Текст не был проверен. Некоторые части кода могут не работать успешно друг с другом. При обнаружении проблемы, загрузить текст в текстовый редактор чтобы получить дополнительную информацию." + +msgid " is not on the server." +msgstr " не найден на сервере" + +#, c-format +msgid "%i files not found on the server!" +msgstr "" + +#, c-format +msgid "%i missing files" +msgstr "" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Для всех)" + +msgid "1 (Child 7+)" +msgstr "1 (Дети 7+)" + +msgid "1 hour" +msgstr "1 час" + +msgid "10 min" +msgstr "10 мин." + +msgid "2 (Teen 12+)" +msgstr "2 (Подростки 12+)" + +msgid "20 min" +msgstr "20 мин." + +msgid "2D Cover Path" +msgstr "Путь к 2D обложкам" + +msgid "3 (Mature 16+)" +msgstr "3 (Подростки 16+)" + +msgid "3 min" +msgstr "3 мин." + +msgid "30 min" +msgstr "30 мин." + +msgid "3D Cover Path" +msgstr "Путь к 3D обложкам" + +msgid "3D Covers" +msgstr "3D Обложки" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Взрослые 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 мин." + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "АВТО" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "" + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "" + +msgid "All Partitions" +msgstr "" + +msgid "All files extracted." +msgstr "" + +msgid "All images downloaded successfully." +msgstr "" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Все функции USB Loader GX разблокированы." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Альтернативный DOL" + +msgid "An example file was created here:" +msgstr "" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "Язык приложения" + +msgid "Apply" +msgstr "" + +msgid "Apr" +msgstr "Апр" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "" + +msgid "Are you sure?" +msgstr "Вы уверены ?" + +msgid "Aspect Ratio" +msgstr "" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "Авг" + +msgid "Author(s):" +msgstr "" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "АвтоИнициализация Сети" + +msgid "BCA Codes Path" +msgstr "Путь к кодам BCA" + +msgid "Back" +msgstr "Назад" + +msgid "Back to HBC or Wii Menu" +msgstr "Вернуться в HBC или меню Wii" + +msgid "Backgroundmusic" +msgstr "Фоновая музыка" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "Большое спасибо:" + +msgid "Block Categories Menu" +msgstr "" + +msgid "Block Categories Modify" +msgstr "" + +msgid "Block Cover Downloads" +msgstr "" + +msgid "Block Custom Paths" +msgstr "" + +msgid "Block Feature Settings" +msgstr "" + +msgid "Block Game Install" +msgstr "" + +msgid "Block Game Settings" +msgstr "" + +msgid "Block GameID Change" +msgstr "" + +msgid "Block Global Settings" +msgstr "" + +msgid "Block Gui Settings" +msgstr "" + +msgid "Block HBC Menu" +msgstr "" + +msgid "Block Hard Drive Settings" +msgstr "" + +msgid "Block IOS Reload" +msgstr "Блокировать перезагрузку IOS" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "" + +msgid "Block Parental Settings" +msgstr "" + +msgid "Block Priiloader Override" +msgstr "" + +msgid "Block Reset Settings" +msgstr "" + +msgid "Block SD Reload Button" +msgstr "" + +msgid "Block Sound Settings" +msgstr "" + +msgid "Block Theme Downloader" +msgstr "" + +msgid "Block Theme Menu" +msgstr "" + +msgid "Block Title Launcher" +msgstr "" + +msgid "Block Updates" +msgstr "" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "Загрузить?" + +msgid "Both" +msgstr "Оба" + +msgid "Both Ports" +msgstr "" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "" + +msgid "Can't be formatted" +msgstr "Невозможно отформатировать" + +msgid "Can't create directory" +msgstr "Не могу создать папку" + +#, c-format +msgid "Can't create file: %s" +msgstr "" + +#, c-format +msgid "Can't create path: %s" +msgstr "" + +msgid "Can't delete:" +msgstr "Невозможно удалить:" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "" + +#, c-format +msgid "Can't read file: %s" +msgstr "" + +msgid "Cancel" +msgstr "Отмена" + +msgid "Cannot write to destination." +msgstr "" + +msgid "Categories" +msgstr "" + +msgid "Categories:" +msgstr "" + +msgid "Change Play Path" +msgstr "" + +msgid "Channel Launcher" +msgstr "" + +msgid "Channels" +msgstr "Каналы" + +msgid "Cheatfile is blank" +msgstr "Файл с читами пустой" + +msgid "Clear" +msgstr "" + +msgid "Click to Download Covers" +msgstr "Нажми, чтобы скачать обложки" + +msgid "Click to change game ID" +msgstr "Нажмите чтобы изменить ID игры" + +msgid "Clock" +msgstr "Часы" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "Закрыть" + +msgid "Code Download" +msgstr "Скачивание кода" + +#, c-format +msgid "Coded by: %s" +msgstr "Создано: %s" + +msgid "Coding:" +msgstr "Создание:" + +msgid "Connection to server timed out." +msgstr "" + +msgid "Console" +msgstr "Консоль" + +msgid "Console Default" +msgstr "По умолчанию (консоль)" + +msgid "Console Locked" +msgstr "Консоль заблокирована" + +msgid "Console must be unlocked for this option." +msgstr "" + +msgid "Console must be unlocked to be able to use this." +msgstr "" + +msgid "Console should be unlocked to modify it." +msgstr "Для изменения консоль должна быть разблокирована." + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "Продолжить установку игры ?" + +msgid "Continue?" +msgstr "" + +msgid "Controllevel" +msgstr "Уровень контроля" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "Правильный пароль" + +msgid "Could not connect to the server." +msgstr "" + +msgid "Could not create GCT file" +msgstr "Не могу создать GCT файл" + +#, c-format +msgid "Could not create path: %s" +msgstr "" + +msgid "Could not extract files for:" +msgstr "" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "" + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "Не могу запустить модуль DIP!" + +msgid "Could not initialize network!" +msgstr "Не могу инициализировать сеть!" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "Не могу прочесть диск" + +msgid "Could not open the WiiTDB.xml file." +msgstr "" + +msgid "Could not open wiitdb.xml." +msgstr "" + +msgid "Could not save." +msgstr "Не могу сохранить." + +msgid "Could not write file." +msgstr "" + +msgid "Could not write to:" +msgstr "" + +msgid "Cover Download" +msgstr "Скачать обложку" + +msgid "Create" +msgstr "Создать" + +msgid "Credits" +msgstr "Об авторах" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "Изменение путей" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "Измененный/Оригинальные" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "Путь к DOL" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "Дек" + +msgid "Default" +msgstr "По умолчанию" + +msgid "Default Gamesettings" +msgstr "Установки игры по умолчанию" + +msgid "Default Settings" +msgstr "Установки по умолчанию" + +msgid "Delete" +msgstr "Удалить" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "Удалить чит-код GCT" + +msgid "Delete Cheat TXT" +msgstr "Удалить чит-код TXT" + +msgid "Delete Cover Artwork" +msgstr "Удалить обложку" + +msgid "Delete Disc Artwork" +msgstr "Удалить картинку диска" + +msgid "Delete category" +msgstr "" + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "Дизайн:" + +msgid "Details" +msgstr "" + +msgid "Developed by" +msgstr "Создано " + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "Каталог не существует!" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "Загрузка изображений диска" + +msgid "Disc Artwork Path" +msgstr "Путь к изображениям дисков" + +msgid "Disc Default" +msgstr "По умолчанию (диск)" + +msgid "Disc Insert Detected" +msgstr "" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "ДискФлип" + +msgid "Display" +msgstr "Отображать" + +msgid "Display as a carousel" +msgstr "Покаказть в виде карусели" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "Показать в виде сетки" + +msgid "Display as a list" +msgstr "Показать в виде списка" + +msgid "Display favorites only" +msgstr "" + +msgid "Do you want to apply it now?" +msgstr "Вы действительно хотите использовать это?" + +msgid "Do you want to apply this theme?" +msgstr "" + +msgid "Do you want to change language?" +msgstr "Вы хотите сменить язык ?" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "Вы действительно хотите загрузить эту тему?" + +msgid "Do you want to extract all the save games?" +msgstr "" + +msgid "Do you want to extract the save game?" +msgstr "" + +msgid "Do you want to format:" +msgstr "Вы хотите отформатировать:" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "" + +msgid "Do you wish to update/download all language files?" +msgstr "Вы действительно хотите обновить/загрузить все языковые файлы?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "Загрузка" + +msgid "Download Now" +msgstr "Скачать сейчас" + +msgid "Download finished" +msgstr "Скачивание завершено" + +msgid "Downloading 3D Covers" +msgstr "" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "" + +msgid "Downloading Full HQ Covers" +msgstr "" + +msgid "Downloading Full LQ Covers" +msgstr "" + +msgid "Downloading custom Discarts" +msgstr "" + +msgid "Downloading file..." +msgstr "" + +msgid "Downloading image:" +msgstr "Загружается картинка:" + +msgid "Downloading original Discarts" +msgstr "" + +msgid "Downloading pagelist:" +msgstr "" + +msgid "Dump NAND to EmuNand" +msgstr "" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "Голландский" + +msgid "ERROR" +msgstr "ОШИБКА" + +msgid "ERROR:" +msgstr "ОШИБКА:" + +msgid "ERROR: Can't set up theme." +msgstr "ОШИБКА: Не удалось установить тему." + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "" + +msgid "Emulated Nand" +msgstr "" + +msgid "English" +msgstr "Английский" + +msgid "Enter Path" +msgstr "" + +msgid "Error" +msgstr "Ошибка" + +msgid "Error !" +msgstr "Ошибка !" + +#, c-format +msgid "Error creating path: %s" +msgstr "" + +msgid "Error opening downloaded file" +msgstr "" + +msgid "Error reading Disc" +msgstr "Ошибка чтения диска" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "" + +msgid "Error while downloding file" +msgstr "" + +msgid "Error while opening the zip." +msgstr "" + +msgid "Error while transfering data." +msgstr "Ошибка при передаче данных." + +msgid "Error while updating USB Loader GX." +msgstr "" + +msgid "Error writing the data." +msgstr "" + +msgid "Error:" +msgstr "Ошибка:" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "" + +msgid "Everything" +msgstr "" + +msgid "Exit" +msgstr "" + +msgid "Exit to where?" +msgstr "" + +msgid "Export All Saves to EmuNand" +msgstr "" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "" + +msgid "Extracting file:" +msgstr "" + +msgid "Extracting files..." +msgstr "Распаковка файлов..." + +msgid "Extracting files:" +msgstr "" + +msgid "Extracting nand files:" +msgstr "" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "Форматирование не удалось" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "" + +msgid "Failed to extract." +msgstr "Не удалось распаковать." + +msgid "Failed to initialize the USB storage device." +msgstr "" + +msgid "Failed to open partition" +msgstr "Не удалось открыть раздел" + +msgid "Failed to read ticket." +msgstr "" + +msgid "Failed to read tmd file." +msgstr "" + +msgid "Failed to read wad header." +msgstr "" + +msgid "Failed updating" +msgstr "" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "" + +msgid "Features Settings" +msgstr "" + +msgid "Feb" +msgstr "Фев" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Файл не найден" + +msgid "File read/write error." +msgstr "" + +msgid "Files extracted successfully." +msgstr "" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "" + +msgid "Filesize is 0 Byte." +msgstr "" + +msgid "Flat Covers" +msgstr "" + +msgid "Flip-X" +msgstr "Flip-X" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "" + +msgid "Force NTSC480p" +msgstr "" + +msgid "Force PAL480p" +msgstr "" + +msgid "Force PAL50" +msgstr "" + +msgid "Force PAL60" +msgstr "" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Форматировать" + +msgid "Formatting, please wait..." +msgstr "Форматирую, пожалуйста подождите..." + +msgid "Found missing images." +msgstr "" + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "Свободное пространство" + +msgid "French" +msgstr "Французский" + +msgid "Full" +msgstr "" + +msgid "Full Cover Path" +msgstr "" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "" + +msgid "GAMEID_Gamename" +msgstr "" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "Путь к читам" + +msgid "GCT File created" +msgstr "Файл GCT создан" + +msgid "GUI Settings" +msgstr "Настройки интерфейса" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "ID игры" + +msgid "Game IOS" +msgstr "" + +msgid "Game Language" +msgstr "Язык" + +msgid "Game Load" +msgstr "загрузка игры" + +msgid "Game Lock" +msgstr "" + +msgid "Game Only" +msgstr "" + +msgid "Game Region" +msgstr "Регион игры" + +msgid "Game Size" +msgstr "Размер игры" + +msgid "Game Sound Mode" +msgstr "Режим звука в игре" + +msgid "Game Sound Volume" +msgstr "Громкость звука в игре" + +msgid "Game Split Size" +msgstr "" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "Игра уже установлена:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "" + +msgid "Games" +msgstr "Игры" + +msgid "Generating GXGameCategories.xml" +msgstr "" + +msgid "Genre:" +msgstr "" + +msgid "German" +msgstr "Немецкий" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "Домашнее Меню" + +msgid "Hard Drive Settings" +msgstr "" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "Путь к хоумбрю-программам" + +msgid "Homebrew Channel" +msgstr "" + +msgid "Homebrew Launcher" +msgstr "Загрузчик хоумбрю" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "Час" + +msgid "How do you want to update?" +msgstr "Что вы хотите обновить ?" + +msgid "How to Shutdown?" +msgstr "Способ отключения?" + +msgid "Import Categories" +msgstr "" + +msgid "Import operation successfully completed." +msgstr "" + +msgid "Importing categories" +msgstr "" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Входящий файл размером в %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Входящий файл размером в %0.2fMB" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "Инициализирую сеть" + +msgid "Insert Disk" +msgstr "Вставьте диск" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "Установка" + +msgid "Install Canceled" +msgstr "" + +msgid "Install Directories" +msgstr "" + +msgid "Install Error!" +msgstr "Ошибка установки!" + +msgid "Install Partitions" +msgstr "" + +msgid "Install a game" +msgstr "Установить игру" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "" + +msgid "Installing game:" +msgstr "Устанавливаю игру:" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Возможно что у Вас есть информация полезная нам. Пожалуйста передайте эту информацию команде разработчиков." + +msgid "Italian" +msgstr "Итальянский" + +msgid "Jan" +msgstr "Янв" + +msgid "Japanese" +msgstr "Японский" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "Июл" + +msgid "June" +msgstr "Июн" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Клавиатура" + +msgid "Korean" +msgstr "Корейский" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "" + +msgid "Language change:" +msgstr "Смена языка:" + +msgid "Languagefiles Path" +msgstr "" + +msgid "Languagepath changed." +msgstr "Путь к языкам изменен" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Left" +msgstr "Налево" + +msgid "Like SysMenu" +msgstr "как SysMenu" + +msgid "List on Gamelaunch" +msgstr "" + +msgid "Load" +msgstr "Загрузить" + +msgid "Load From SD/USB" +msgstr "Загрузка с SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Загрузить файл из %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Загрузить этот DOL в качестве альтернативного ?" + +msgid "Loader Settings" +msgstr "" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "Загрузка языка по умолчанию" + +msgid "Loading standard music." +msgstr "Загрузка стандартной музыки" + +msgid "Lock Console" +msgstr "Заблокировать консоль" + +msgid "Lock USB Loader GX" +msgstr "" + +msgid "Locked" +msgstr "Заблокировано" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "" + +msgid "Loop Music" +msgstr "" + +msgid "Loop Sound" +msgstr "Зациклить звут" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "Мар" + +msgid "Mark new games" +msgstr "Отметить новые игры" + +msgid "May" +msgstr "Май" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "" + +msgid "Motion+ Video" +msgstr "" + +msgid "Mount DVD drive" +msgstr "Монтировать DVD" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "" + +msgid "Music Loop Mode" +msgstr "" + +msgid "Music Volume" +msgstr "Громкость" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "" + +msgid "Nand Channels" +msgstr "" + +msgid "Nand Emu Channel Path" +msgstr "" + +msgid "Nand Emu Path" +msgstr "" + +msgid "Nand Emulation" +msgstr "" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Ни то, ни другое" + +msgid "Network is not initiated." +msgstr "" + +msgid "Next" +msgstr "Следующий" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "Нет" + +msgid "No Cheatfile found" +msgstr "Не найден файл с читами" + +msgid "No DOL file found on disc." +msgstr "DOL-файл не найден на диске." + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "" + +msgid "No URL or Path specified." +msgstr "" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "Невозможно считать данные." + +msgid "No disc inserted." +msgstr "" + +msgid "No favorites selected." +msgstr "" + +msgid "No file missing!" +msgstr "Файл не найден!" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "" + +msgid "No new updates." +msgstr "Нет обновлений" + +msgid "No themes found on the site." +msgstr "На сайте не найдено ни одной темы" + +msgid "No themes found." +msgstr "" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "" + +msgid "Normal" +msgstr "Обычный" + +msgid "Not Initialized" +msgstr "" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "" + +msgid "Not a valid URL path" +msgstr "" + +msgid "Not a valid domain" +msgstr "" + +msgid "Not enough free memory." +msgstr "Недостаточно памяти" + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "Не хватает свободного места!" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "" + +msgid "Not required" +msgstr "" + +msgid "Not supported format!" +msgstr "Формат не поддерживается" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "Ноя" + +msgid "OFF" +msgstr "ВЫКЛ" + +msgid "OK" +msgstr "OK" + +msgid "ON" +msgstr "ВКЛ" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Окт" + +msgid "Official Site:" +msgstr "Оф. сайт:" + +msgid "Offset" +msgstr "" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "" + +msgid "Only for Install" +msgstr "Только при установке" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Измененные/Модифицированные" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Родительский Контроль" + +msgid "Partial" +msgstr "" + +msgid "Partition" +msgstr "Раздел" + +msgid "Password" +msgstr "Пароль" + +msgid "Password Changed" +msgstr "Пароль изменен" + +msgid "Password has been changed" +msgstr "Пароль был изменен" + +msgid "Patch Country Strings" +msgstr "Патчить строки страны" + +msgid "Path Changed" +msgstr "" + +msgid "Permission denied." +msgstr "" + +msgid "Pick from a list" +msgstr "Выберите из списка" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Запущено раз" + +msgid "Play Next" +msgstr "" + +msgid "Play Once" +msgstr "" + +msgid "Play Previous" +msgstr "" + +msgid "Playing Music:" +msgstr "" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "Пожалуйста подождите..." + +msgid "Power off the Wii" +msgstr "Выключить Wii" + +msgid "Prev" +msgstr "Предыдущий" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Кнопки приглашения" + +msgid "Published by" +msgstr "Опубликовано: " + +msgid "Quick Boot" +msgstr "Быстрая загрузка" + +msgid "Random Directory Music" +msgstr "" + +msgid "Real Nand" +msgstr "" + +msgid "Receiving file from:" +msgstr "Получение файлы из:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "" + +msgid "Released" +msgstr "Выпущено:" + +msgid "Reload SD" +msgstr "Перечитать SD карту" + +msgid "Reloading game list now, please wait..." +msgstr "" + +msgid "Remember Unlock" +msgstr "" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "" + +msgid "Rename Game Title" +msgstr "" + +msgid "Rename category" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Reset BG Music" +msgstr "" + +msgid "Reset Playcounter" +msgstr "Сбросить счетчик запусков" + +msgid "Reset to default BGM?" +msgstr "" + +msgid "Restarting..." +msgstr "Перезапускаю..." + +msgid "Return" +msgstr "Вернуться" + +msgid "Return To" +msgstr "" + +msgid "Return to Wii Menu" +msgstr "Вернуться в меню Wii" + +msgid "Right" +msgstr "Направо" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Вибрация" + +msgid "SChinese" +msgstr "Упрощенный китайский" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "Громкость эффектов" + +msgid "Save" +msgstr "Сохранить" + +msgid "Save Failed. No device inserted?" +msgstr "" + +msgid "Save Game List to" +msgstr "Сохранить список игр в" + +msgid "Save List" +msgstr "" + +msgid "Saved" +msgstr "Сохранено" + +msgid "Savegame might not exist for this game." +msgstr "" + +msgid "Screensaver" +msgstr "Скринсейвер" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "" + +msgid "Select DOL Offset" +msgstr "" + +msgid "Select a DOL" +msgstr "Выберите DOL" + +msgid "Select a DOL from Game" +msgstr "" + +msgid "Select game categories" +msgstr "" + +msgid "Select loader mode" +msgstr "" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "" + +msgid "Sept" +msgstr "Сен" + +msgid "Set Search-Filter" +msgstr "Установить фильтр для поиска" + +msgid "Settings" +msgstr "Установки" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "" + +msgid "Show Play Count" +msgstr "" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "Выключить систему" + +msgid "Shutdown Wii" +msgstr "" + +msgid "Skip Errors" +msgstr "" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Сортировать по алфавиту" + +msgid "Sort by number of players" +msgstr "" + +msgid "Sort by rank" +msgstr "Сортировать по популярности" + +msgid "Sort order by most played" +msgstr "Сортировать по частоте проигрывания" + +msgid "Sound" +msgstr "Звук" + +msgid "Sound Settings" +msgstr "" + +msgid "Sound+BGM" +msgstr "Звук и фоновая музыка" + +msgid "Sound+Quiet" +msgstr "Звук и тишина" + +msgid "Spanish" +msgstr "Испанский" + +msgid "Special thanks to:" +msgstr "Отдельные благодарности" + +msgid "Split each 2GB" +msgstr "" + +msgid "Split each 4GB" +msgstr "" + +msgid "Standby" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "Успех" + +msgid "Success." +msgstr "" + +msgid "Success:" +msgstr "Успех:" + +msgid "Successfully Saved" +msgstr "Успешно сохранено" + +msgid "Successfully Updated" +msgstr "Успешно обновлено" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "Успешно удалено:" + +msgid "Successfully extracted theme." +msgstr "Успешно извлечена тема." + +msgid "Successfully installed:" +msgstr "Успешно установлено:" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "" + +msgid "Sync FAT32 FS Info" +msgstr "" + +msgid "Synchronizing..." +msgstr "" + +msgid "System Default" +msgstr "По умолчанию" + +msgid "TChinese" +msgstr "Традиционный китайский" + +msgid "TXT Cheatcodes Path" +msgstr "Путь к TXT читкодам" + +msgid "The .them file was not found in the zip." +msgstr "" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "Заданный каталог не существует. Хотите создать его?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "" + +msgid "Theme Downloader" +msgstr "Загрузчик тем" + +msgid "Theme Menu" +msgstr "" + +msgid "Theme Path" +msgstr "Путь к темам" + +msgid "Theme Title:" +msgstr "Заголовок темы:" + +msgid "Themes by www.spiffy360.com" +msgstr "" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "" + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "Осталось времени:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Загрузчик тайтла" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "Подсказки" + +msgid "Transfer failed" +msgstr "" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX заблокирован" + +msgid "USB Port" +msgstr "" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "Деинсталлировать" + +msgid "Uninstall Game" +msgstr "Деинсталлировать игру" + +msgid "Uninstall Menu" +msgstr "Деинсталлировать меню" + +msgid "Uninstall all" +msgstr "" + +msgid "Unknown" +msgstr "" + +msgid "Unlock USB Loader GX" +msgstr "" + +msgid "Unlocked" +msgstr "Разблокировано" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "" + +msgid "Update" +msgstr "Обновление" + +msgid "Update All" +msgstr "Обновить всё" + +msgid "Update DOL" +msgstr "Обновить DOL" + +msgid "Update Files" +msgstr "Обновить файлы" + +msgid "Update Path" +msgstr "Путь к обновлениям" + +msgid "Update all Language Files" +msgstr "Обновить все языковые файлы" + +msgid "Update failed" +msgstr "Обновление не удалось" + +msgid "Update successfull" +msgstr "" + +msgid "Updating Language Files:" +msgstr "Обновление языковых файлов:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Загруженный ZIP-файл установлен в каталог homebrew" + +msgid "Use System Font" +msgstr "" + +msgid "Use global" +msgstr "" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "Патч VIDTV" + +msgid "Version:" +msgstr "" + +#, c-format +msgid "Version: %s" +msgstr "Версия: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Видео режим" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "" + +msgid "WDM Files Path" +msgstr "" + +msgid "WIP Patches Path" +msgstr "Путь к патчам QIP" + +msgid "Waiting..." +msgstr "Ожидание..." + +msgid "Warning" +msgstr "" + +msgid "Warning:" +msgstr "" + +msgid "What do you want to do?" +msgstr "" + +msgid "What do you want to update?" +msgstr "Что Вы хотите обновить?" + +msgid "What should be deleted for this game title:" +msgstr "" + +msgid "What to extract from NAND?" +msgstr "" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "свойства WiFi" + +msgid "Widescreen Factor" +msgstr "" + +msgid "Widescreen Fix" +msgstr "Широкоформатный фикс" + +msgid "Wii Games" +msgstr "" + +msgid "Wii Menu" +msgstr "Меню Wii" + +msgid "Wii Settings" +msgstr "Установки Wii" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "Подсветка Wii" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "" + +msgid "Wiird Debugger" +msgstr "" + +#, c-format +msgid "Write error on file: %s" +msgstr "" + +msgid "Writing GXGameCategories.xml" +msgstr "" + +msgid "Wrong Password" +msgstr "Неверный пароль" + +msgid "Yes" +msgstr "Да" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "" + +msgid "You cannot delete this category." +msgstr "" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "" + +msgid "available" +msgstr "доступно" + +msgid "does not exist!" +msgstr "не существует!" + +msgid "does not exist! Loading game without cheats." +msgstr "не существует! Загружаю игру без читов" + +msgid "files left" +msgstr "файлов осталось" + +msgid "for FAT/NTFS support" +msgstr "для поддержки FAT/NTFS" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "" + +msgid "for Ocarina" +msgstr "за Ocarina" + +msgid "for diverse patches" +msgstr "за различные патчи" + +msgid "for his awesome tool LibWiiGui" +msgstr "за отличную утилиту LibWiiGui" + +msgid "for hosting the themes" +msgstr "за хостинг тем" + +msgid "for the USB Loader source" +msgstr "за выпуск и публикацию исходного кода" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "форматирование завершено!" + +msgid "free" +msgstr "свободно" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "не установлено" + +msgid "of" +msgstr "из" + +msgid "seconds left" +msgstr "секунд осталось" + +#~ msgid "Anti" +#~ msgstr "Анти" + +#~ msgid "Error 002 fix" +#~ msgstr "Фикс ошибки 002" + +#~ msgid "Boot/Standard" +#~ msgstr "Загрузка/Стандарт" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "Переименовать игры в WBFS" + +#~ msgid "for hosting the update files" +#~ msgstr "за хостинг обновлений" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Вставьте диск Wii!" + +#~ msgid "No cheats were selected" +#~ msgstr "Не было выбрано ни одного чит-кода" + +#~ msgid "Not a Wii Disc" +#~ msgstr "Это не диск Wii" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> Удаление тикетов...." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> Удаление тикетов...ОШИБКА! " + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> Удаление тикетов...Успешно! " + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> Удаление тайтла ...ОШИБКА! " + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> Удаление тайтла ...Успешно!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> Удаление содержимого тайтла..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> Удаление содержимого тайтла...ОШИБКА!" + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> Удаление содержимого тайтла...Успешно!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> Удаление тайтла..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> Заканчиваю установку..." + +#~ msgid ">> Installing content #" +#~ msgstr ">>Установка контента №" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">>Установка тикета..." + +#~ msgid ">> Installing title..." +#~ msgstr ">>Установка тайтла" + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> Чтение данных WAD..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> Чтение данных WAD...ОШИБКА!" + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> Чтение данных WAD...Успешно!" + +#~ msgid "Done!" +#~ msgstr "Готово!" + +#~ msgid "Error..." +#~ msgstr "Ошибка..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "Завершение установки... ОК!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "Установка контента... ОК!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "Установка тикета... ОК!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "Установка тайтла... ОК!" + +#~ msgid "Installing wad" +#~ msgstr "Установка WAD" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "Чтение данных WAD... ОК!" + +#~ msgid "Uninstalling wad" +#~ msgstr "Деинсталлируется wad" + +#~ msgid "New Disc Detected" +#~ msgstr "Обнаружен новый диск" + +#~ msgid "USB Device not found" +#~ msgstr "USB устройство не найдено" + +#~ msgid "Language File" +#~ msgstr "Языковой файл" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Названия из WiiTDB" + +#~ msgid "WiiTDB Files" +#~ msgstr "Файлы WiiTDB" + +#~ msgid "WiiTDB Path" +#~ msgstr "Путь к WiiTDB" + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "за WIITDB и хостинг изображений обложек/дисков" + +#~ msgid "Install partitions" +#~ msgstr "Установить разделы" + +#~ msgid " Wad Saved as:" +#~ msgstr " Wad сохранен как:" + +#~ msgid "Delete ?" +#~ msgstr "Удалить ?" + +#~ msgid "Keep" +#~ msgstr "Сохранить" + +#~ msgid "Author:" +#~ msgstr "Автор:" + +#~ msgid "Download Boxart image?" +#~ msgstr "Скачать обложку диска?" + +#~ msgid "Download Discart image?" +#~ msgstr "Скачать изображение диска ?" + +#~ msgid "Downloading file" +#~ msgstr "Скачиваю файл:" + +#~ msgid "Missing files" +#~ msgstr "Отсутствующие файлы" + +#~ msgid "files not found on the server!" +#~ msgstr "файлы не найдены на сервере!" + +#~ msgid "Disc Images" +#~ msgstr "Изображения дисков" + +#~ msgid "Only Customs" +#~ msgstr "Только измененные" + +#~ msgid "Only Original" +#~ msgstr "Только оригинальные" + +#~ msgid "Do you really want to delete:" +#~ msgstr "Вы хотите удалить:" + +#~ msgid "Do you want to use the alternate DOL that is known to be correct?" +#~ msgstr "Вы хотите использовать DOL, который считается правильным?" + +#~ msgid "BETA revisions" +#~ msgstr "BETA-версии" + +#~ msgid "Unlock console to use this option." +#~ msgstr "Для изменения параметра разблокируйте консоль." + +#~ msgid "Full Shutdown" +#~ msgstr "Полное отключение" + +#~ msgid "GXtheme.cfg not found in any subfolder." +#~ msgstr "GXtheme.cfg не найден ни в одном каталоге." + +#~ msgid "If you don't have WiFi, press 1 to get an URL to get your WiiTDB.zip" +#~ msgstr "Если у вас нет сети WiFi, нажмите 1 чтобы получить URL для доступа к вашему WiiTDB.ZIP" + +#~ msgid "Paste it into your browser to get your WiiTDB.zip." +#~ msgstr "Скопируйте это в Ваш браузер чтобы получить Ваш WiiTDB.zip" + +#~ msgid "Shutdown to Idle" +#~ msgstr "Перевести в режим сна" + +#~ msgid "Your URL has been saved in %sWiiTDB_URL.txt." +#~ msgstr "Ваш URL был сохранен в %sWiiTDB_URL.txt." + +#~ msgid "Can't create file" +#~ msgstr "Не могу создать файл" + +#~ msgid "Connection lost..." +#~ msgstr "Связь потеряна..." + +#~ msgid "Download failed." +#~ msgstr "Загрузка завершилась с ошибкой." + +#~ msgid "Download request failed." +#~ msgstr "Запрос на загрузку завершился с ошибкоа." + +#~ msgid "Downloading Page List:" +#~ msgstr "Загружается список страниц:" + +#~ msgid "Theme Download Path" +#~ msgstr "Путь для загрузки темы" + +#~ msgid "Transfer failed." +#~ msgstr "Передача не удалась." + +#~ msgid "Unsupported format, try to extract manually." +#~ msgstr "Формат не поддерживается, попробуйте распаковать самостоятельно." + +#~ msgid "and translaters for language files updates" +#~ msgstr "и переводчики для обновлений языковых файлов" + +#~ msgid "Insert an SD-Card to save." +#~ msgstr "Для сохранения вставьте SD карту." + +#~ msgid "Insert an SD-Card to use this option." +#~ msgstr "Для использования этой функции нужна SD карта" + +#~ msgid "No SD-Card inserted!" +#~ msgstr "SD карта не вставлена!" + +#~ msgid "Waiting for USB Device" +#~ msgstr "Ожидание USB устройства" + +#~ msgid "Back to Loader" +#~ msgstr "Вернуться в загрузчик" + +#~ msgid "FAT: Use directories" +#~ msgstr "FAT: Использовать каталоги" + +#~ msgid "All partitions" +#~ msgstr "Все разделы" + +#~ msgid "Game partition" +#~ msgstr "Раздел игры" + +#~ msgid "Install 1:1 Copy" +#~ msgstr "Установка копии 1:1" + +#~ msgid "An Error occured" +#~ msgstr "Произошла ошибка" + +#~ msgid "Are you sure you want to enable Parent Control?" +#~ msgstr "Вы действительно хотите включить Родительский Контроль?" + +#~ msgid "AutoPatch" +#~ msgstr "Авто Патч" + +#~ msgid "Checking for Updates" +#~ msgstr "Проверяю обновления" + +#~ msgid "Downloading" +#~ msgstr "Скачиваю" + +#~ msgid "Invalid PIN code" +#~ msgstr "Неправильный PIN-код" + +#~ msgid "Parental Control disabled" +#~ msgstr "Родительский Контроль выключен" + +#~ msgid "The wad file was installed. But It could not be deleted from the SD card." +#~ msgstr "WAD файл установлен, но он не может быть удален с карты SD." + +#~ msgid "The wad installation failed with error %ld" +#~ msgstr "Установка WAD не удалась, код ошибки %ld" + +#~ msgid "Unable to open the wad that was just downloaded (%s)." +#~ msgstr "Не могу открыть скачанный WAD (%s)" + +#~ msgid "Unlock Parental Control" +#~ msgstr "Разблокировать Родительский Контроль" + +#~ msgid "Update to" +#~ msgstr "Обновить до" + +#~ msgid "Updating" +#~ msgstr "обновляю" + +#~ msgid "Updating Language Files..." +#~ msgstr "Обновление языковых файлов..." + +#~ msgid "Updating WiiTDB.zip" +#~ msgstr "Обновление WiiTDB.zip" + +#~ msgid "You don't have Parental Control enabled. If you wish to use Parental Control, enable it in the Wii Settings." +#~ msgstr "У Вас не включен Родительский Контроль. Если вы хотите использовать Родительский Контроль, включите его в установках Wii." + +#~ msgid "%s : %s May not boot correctly if your System Menu is not up to date." +#~ msgstr "%s : %s может не загрузиться правильно если ваше Системное Меню не последней версии" + +#~ msgid "BCA Codes Path changed" +#~ msgstr "Путь к кодам BCA изменен" + +#~ msgid "Back to Wii Menu" +#~ msgstr "Вернуться в меню Wii" + +#~ msgid "Checking existing artwork" +#~ msgstr "Проверка существующей графики" + +#~ msgid "Confirm" +#~ msgstr "Подтвердить" + +#~ msgid "Could not find a WBFS partition." +#~ msgstr "Не удалось найти раздел WBFS" + +#~ msgid "Could not open WBFS partition" +#~ msgstr "Не могу открыть раздел WBFS" + +#~ msgid "Could not read the disc." +#~ msgstr "Не могу прочесть диск" + +#~ msgid "Could not set USB." +#~ msgstr "Не могу настроить USB" + +#~ msgid "Cover Path Changed" +#~ msgstr "Путь к обложкам был изменен." + +#~ msgid "DOL path changed" +#~ msgstr "Путь к DOL изменен" + +#~ msgid "Disc Path Changed" +#~ msgstr "Путь к изображениям дисков изменен" + +#~ msgid "Display favorites" +#~ msgstr "Показать закладки" + +#~ msgid "Do you want to retry for 30 secs?" +#~ msgstr "Хотите попробовать еще раз на 30 секунд?" + +#~ msgid "Enable Parental Control" +#~ msgstr "Включить Родительский Контроль" + +#~ msgid "Force" +#~ msgstr "Принудительно" + +#~ msgid "GCT Cheatcodes Path changed" +#~ msgstr "Путь к читам изменен" + +#~ msgid "Hermes CIOS" +#~ msgstr "Hermes CIOS" + +#~ msgid "Homebrew Appspath changed" +#~ msgstr "Путь к хоумбрю-программам изменен" + +#~ msgid "Insert an SD-Card to download images." +#~ msgstr "Для скачивания изображений вставьте SD карту." + +#~ msgid "Install not possible" +#~ msgstr "Установка невозможна" + +#~ msgid "Most likely it has dimensions that are not evenly divisible by 4." +#~ msgstr "Размеры картинки не делятся на 4. Поздравляю, блин." + +#~ msgid "Network init error" +#~ msgstr "Ошибка инициализации сети" + +#~ msgid "No .dol or .elf files found." +#~ msgstr "Не найдены файлы .dol или .elf" + +#~ msgid "No Favorites" +#~ msgstr "Нет избранных" + +#~ msgid "No USB Device" +#~ msgstr "Нет USB устройств" + +#~ msgid "No USB Device found." +#~ msgstr "USB устройств не обнаружено" + +#~ msgid "Normal Covers" +#~ msgstr "Обычные обложки" + +#~ msgid "Not Found" +#~ msgstr "Не найден" + +#~ msgid "Not a DOL/ELF file." +#~ msgstr "Не является файлом DOL/ELF" + +#~ msgid "Save Failed" +#~ msgstr "Сохранение не удалось" + +#~ msgid "Selected DOL" +#~ msgstr "Выбранный DOL" + +#~ msgid "Standard" +#~ msgstr "Стандартный" + +#~ msgid "TXT Cheatcodes Path changed" +#~ msgstr "Путь к TXT читкодам изменен" + +#~ msgid "Theme Download Path changed" +#~ msgstr "Путь для загрузки темы изменен" + +#~ msgid "Theme Path Changed" +#~ msgstr "путь к темам изменён" + +#~ msgid "USB Loader GX will only run with Hermes CIOS rev 4! Please make sure you have revision 4 installed!" +#~ msgstr "USB Loader GX будет работать только с Hermes CIOS rev 4! Пожалуйста убедитесь что у вас установлена версия 4!" + +#~ msgid "Update Path changed." +#~ msgstr "Путь к обновлениям изменен" + +#~ msgid "WIP Patches Path changed" +#~ msgstr "Путь к патчам QIP изменен" + +#~ msgid "WiiTDB Path changed." +#~ msgstr "Путь к WiiTDB изменен" + +#~ msgid "You are about to delete " +#~ msgstr "Вы хотите удалить " + +#~ msgid "You are choosing to display favorites and you do not have any selected." +#~ msgstr "Нельзя отобразить избранные, если вы их до этого не выбрали." + +#~ msgid "You are using NTFS filesystem. Due to possible write errors to a NTFS partition, installing a game is not possible." +#~ msgstr "Вы используете файловую систему NTFS. Из-за возможных ошибок записи на раздел NTFS установка игры невозможна." + +#~ msgid "You have attempted to load a bad image" +#~ msgstr "Вы попытались загрузить плохой образ" + +#~ msgid "does not exist! You Messed something up, Idiot." +#~ msgstr "не существует! Ты облажался, идиот." + +#~ msgid "file left" +#~ msgstr "файл остался" diff --git a/Languages/schinese.lang b/Languages/schinese.lang new file mode 100644 index 0000000..206d0b3 --- /dev/null +++ b/Languages/schinese.lang @@ -0,0 +1,3075 @@ +# USB Loader GX language source file. +# schinese.lang - r1227 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:05+0200\n" +"PO-Revision-Date: 2013-08-13 07:03+0800\n" +"Last-Translator: \n" +"Language-Team: oCameLo\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr "不能下载。" + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr "已经被保存。内容尚未验证。部分代码可能无法作用。如果你遇到问题,请用文字编辑器打开文本文件以获得更多的信息。" + +msgid " is not on the server." +msgstr "不在服务器上。" + +#, c-format +msgid "%i files not found on the server!" +msgstr "在服务器上未找到 %i 个文件!" + +#, c-format +msgid "%i missing files" +msgstr "缺少 %i 个文件" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "%s只能识别Gamecube备份格式的ISO镜像文件。" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "%s需要AHB漏洞开启!请从HBC或者更新频道或者Forwarder运行USB loader GX程序。" + +msgid "--== Devolution" +msgstr "--== Devolution" + +msgid "--== Nintendont" +msgstr "--== Nintendont" + +msgid "--== DIOS MIOS (Lite) " +msgstr "--== DIOS MIOS (Lite) " + +msgid "--== DM(L) + Nintendont" +msgstr "--== DM(L) + Nintendont" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (全年龄)" + +msgid "1 (Child 7+)" +msgstr "1 (7 岁以上)" + +msgid "1 hour" +msgstr "1 小时" + +msgid "10 min" +msgstr "10 分钟" + +msgid "2 (Teen 12+)" +msgstr "2 (12 岁以上)" + +msgid "20 min" +msgstr "20 分钟" + +msgid "2D Cover Path" +msgstr "2D 封面路径" + +msgid "3 (Mature 16+)" +msgstr "3 (16 岁以上)" + +msgid "3 min" +msgstr "3 分钟" + +msgid "30 min" +msgstr "30 分钟" + +msgid "3D Cover Path" +msgstr "3D 封面路径" + +msgid "3D Covers" +msgstr "3D 封面" + +msgid "4 (Adults Only 18+)" +msgstr "4 (18 岁以上成人)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 分钟" + +msgid "=== GameCube Settings" +msgstr "=== GameCube 设置" + +msgid "AUTO" +msgstr "自动" + +msgid "AXNextFrame" +msgstr "AXNextFrame" + +msgid "Add category" +msgstr "添加分类" + +msgid "Adjust Overscan X" +msgstr "调整 X 轴扫描线" + +msgid "Adjust Overscan Y" +msgstr "调整 Y 轴扫描线" + +msgid "After zoom" +msgstr "缩放之后" + +msgid "All" +msgstr "全部" + +msgid "All Partitions" +msgstr "所有分区" + +msgid "All files extracted." +msgstr "已提取全部文件。" + +msgid "All images downloaded successfully." +msgstr "所有图片已成功下载。" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "所有 USB Loader GX 功能已解锁." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "可选择 DOL 文件" + +msgid "An example file was created here:" +msgstr "一个实例文件已创建于:" + +msgid "Animation Start" +msgstr "动画缩图启动" + +msgid "App Language" +msgstr "语言设定" + +msgid "Apply" +msgstr "应用" + +msgid "Apr" +msgstr "四月" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "确定将所有已选择游戏从 SD 卡上删除?" + +msgid "Are you sure you want to delete this category?" +msgstr "确定删除该分类?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "确定从 GameTDB 中导入游戏分类?" + +msgid "Are you sure you want to install on SD?" +msgstr "确定安装至 SD 卡?" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "确定要锁定 USB Loader GX 吗?" + +msgid "Are you sure you want to remount SD?" +msgstr "确定要重新加载 SD 卡?" + +msgid "Are you sure you want to reset?" +msgstr "确定重置吗?" + +msgid "Are you sure?" +msgstr "确定?" + +msgid "Aspect Ratio" +msgstr "长宽比例" + +msgid "Attention!" +msgstr "注意!" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "八月" + +msgid "Author(s):" +msgstr "作者:" + +msgid "Auto" +msgstr "自动" + +msgid "Auto Boot" +msgstr "自动运行" + +msgid "AutoInit Network" +msgstr "自动检测网络" + +msgid "BCA Codes Path" +msgstr "BCA 代码路径" + +msgid "Back" +msgstr "返回" + +msgid "Back to HBC or Wii Menu" +msgstr "返回 HBC 或 Wii 系统菜单" + +msgid "Backgroundmusic" +msgstr "背景音乐" + +msgid "Banner Animation" +msgstr "频道动画" + +msgid "Banner Animation Settings" +msgstr "频道动画设置" + +msgid "Banner On Channels" +msgstr "频道上的动画" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "频道动画墙只能在 AHBPROT 模式下工作!请考虑安装新版的 HBC 。" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "频道动画窗口只能在 AHBPROT 模式下工作!请考虑安装新版的 HBC 。" + +msgid "Big thanks to:" +msgstr "非常感谢:" + +msgid "Block Categories Menu" +msgstr "禁止分类菜单" + +msgid "Block Categories Modify" +msgstr "禁止分类修改" + +msgid "Block Cover Downloads" +msgstr "禁止下载封面" + +msgid "Block Custom Paths" +msgstr "禁止自定义路径" + +msgid "Block Feature Settings" +msgstr "禁止功能设置" + +msgid "Block Game Install" +msgstr "禁止游戏安装" + +msgid "Block Game Settings" +msgstr "禁止游戏设置" + +msgid "Block GameID Change" +msgstr "禁止更改 GameID" + +msgid "Block Global Settings" +msgstr "禁止全局设置" + +msgid "Block Gui Settings" +msgstr "禁止图形界面设置" + +msgid "Block HBC Menu" +msgstr "禁止 HBC 菜单" + +msgid "Block Hard Drive Settings" +msgstr "禁止硬盘设置" + +msgid "Block IOS Reload" +msgstr "禁止 IOS 重新载入" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "禁止加载器模式按钮" + +msgid "Block Loader Settings" +msgstr "禁止加载器设置" + +msgid "Block Parental Settings" +msgstr "禁止家长控制设置" + +msgid "Block Priiloader Override" +msgstr "禁止覆盖 Priiloader" + +msgid "Block Reset Settings" +msgstr "禁止重置设置" + +msgid "Block SD Reload Button" +msgstr "禁止重新加载 SD 卡按钮" + +msgid "Block Sound Settings" +msgstr "禁止声音设置" + +msgid "Block Theme Downloader" +msgstr "禁止主题下载" + +msgid "Block Theme Menu" +msgstr "禁止主题菜单" + +msgid "Block Title Launcher" +msgstr "禁止 Title 启动器" + +msgid "Block Updates" +msgstr "禁止更新" + +msgid "Boot Content" +msgstr "启动内容" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "启动?" + +msgid "Both" +msgstr "全部" + +msgid "Both Ports" +msgstr "两个接口" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "缓存 BNR 文件" + +msgid "Cache BNR Files Path" +msgstr "缓存 BNR 文件路径" + +msgid "Cache Titles" +msgstr "缓存游戏标题" + +msgid "Can't be formatted" +msgstr "无法格式化" + +msgid "Can't create directory" +msgstr "无法建立目录" + +#, c-format +msgid "Can't create file: %s" +msgstr "无法创建文件:%s" + +#, c-format +msgid "Can't create path: %s" +msgstr "无法创建路径: %s" + +msgid "Can't delete:" +msgstr "无法删除:" + +msgid "Can't mount or unknown disc format." +msgstr "无法加载或未知的碟片格式。" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "无法打开并写入文件:%s" + +#, c-format +msgid "Can't open file: %s" +msgstr "无法打开文件:%s" + +#, c-format +msgid "Can't read file: %s" +msgstr "无法读取文件:%s" + +msgid "Cancel" +msgstr "取消" + +msgid "Cannot write to destination." +msgstr "无法写入目标。" + +msgid "Categories" +msgstr "分类" + +msgid "Categories:" +msgstr "分类:" + +msgid "Change Play Path" +msgstr "更改游戏路径" + +msgid "Channel Launcher" +msgstr "频道启动器" + +msgid "Channels" +msgstr "频道" + +msgid "Cheatfile is blank" +msgstr "作弊码文件是空的" + +msgid "Clear" +msgstr "清除" + +msgid "Click to Download Covers" +msgstr "点击下载封面" + +msgid "Click to change game ID" +msgstr "点击变更 GameID" + +msgid "Clock" +msgstr "时钟" + +msgid "Clock Scale Factor" +msgstr "时钟比例因数" + +msgid "Close" +msgstr "关闭" + +msgid "Code Download" +msgstr "作弊码下载" + +#, c-format +msgid "Coded by: %s" +msgstr "编程: %s" + +msgid "Coding:" +msgstr "编程:" + +msgid "Connection to server timed out." +msgstr "连接服务器超时。" + +msgid "Console" +msgstr "主机" + +msgid "Console Default" +msgstr "主机默认" + +msgid "Console Locked" +msgstr "主机已锁定" + +msgid "Console must be unlocked for this option." +msgstr "必须解锁主机以启用该选项。" + +msgid "Console must be unlocked to be able to use this." +msgstr "主机必须解锁以使用该项。" + +msgid "Console should be unlocked to modify it." +msgstr "需解锁主机以修改该项。" + +msgid "Continue" +msgstr "继续" + +msgid "Continue to install game?" +msgstr "继续安装游戏?" + +msgid "Continue?" +msgstr "继续?" + +msgid "Controllevel" +msgstr "访问控制级别" + +msgid "Copy" +msgstr "复制" + +msgid "Copying Canceled" +msgstr "复制已取消" + +msgid "Copying GC game..." +msgstr "正在复制 GC 游戏..." + +msgid "Copying files..." +msgstr "正在复制文件..." + +msgid "Correct Password" +msgstr "密码正确" + +msgid "Could not connect to the server." +msgstr "无法连接到服务器。" + +msgid "Could not create GCT file" +msgstr "无法建立 GCT 文件" + +#, c-format +msgid "Could not create path: %s" +msgstr "无法创建路径: %s" + +msgid "Could not extract files for:" +msgstr "无法提取文件:" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "wiitdb.xml 中未找到此游戏。" + +msgid "Could not get free device space for game." +msgstr "无法为游戏获取足够的可用设备空间。" + +msgid "Could not initialize DIP module!" +msgstr "无法启动 DIP 模块!" + +msgid "Could not initialize network!" +msgstr "无法启动网络!" + +msgid "Could not initialize network, time out!" +msgstr "无法初始化网络,超时!" + +msgid "Could not open Disc" +msgstr "无法开启光盘" + +msgid "Could not open the WiiTDB.xml file." +msgstr "无法打开 WiiTDB.xml 文件。" + +msgid "Could not open wiitdb.xml." +msgstr "无法打开 wiitdb.xml 。" + +msgid "Could not save." +msgstr "无法保存。" + +msgid "Could not write file." +msgstr "无法写入文件。" + +msgid "Could not write to:" +msgstr "无法写入文件:" + +msgid "Cover Download" +msgstr "下载封面" + +msgid "Create" +msgstr "创建" + +msgid "Credits" +msgstr "作者信息" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "自定义频道动画" + +msgid "Custom Paths" +msgstr "自定义路径" + +msgid "Customs" +msgstr "自定义" + +msgid "Customs/Original" +msgstr "自制/官方" + +msgid "D Buttons" +msgstr "D键" + +msgid "DOL Path" +msgstr "DOL 路径" + +msgid "Debug" +msgstr "除错" + +msgid "Debug Wait" +msgstr "除错等待" + +msgid "Debugger Paused Start" +msgstr "出错器暂停启动" + +msgid "Dec" +msgstr "十二月" + +msgid "Default" +msgstr "缺省" + +msgid "Default Gamesettings" +msgstr "缺省游戏设定" + +msgid "Default Settings" +msgstr "缺省设置" + +msgid "Delete" +msgstr "删除" + +msgid "Delete Cached Banner" +msgstr "删除已缓存的频道动画" + +msgid "Delete Cheat GCT" +msgstr "删除 GCT 金手指文件" + +msgid "Delete Cheat TXT" +msgstr "删除 TXT 金手指文件" + +msgid "Delete Cover Artwork" +msgstr "删除封面" + +msgid "Delete Disc Artwork" +msgstr "删除光盘图片" + +msgid "Delete category" +msgstr "删除分类" + +msgid "Deleting directories..." +msgstr "正在删除目录..." + +msgid "Deleting files..." +msgstr "正在删除文件..." + +msgid "Design:" +msgstr "设计:" + +msgid "Details" +msgstr "详细" + +msgid "Developed by" +msgstr "开发" + +msgid "Developer:" +msgstr "开发者:" + +msgid "Devolution" +msgstr "Devolution" + +msgid "Devolution Loader Path" +msgstr "Devolution 加载器路径" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "无法加载 Devolution 的 loader.bin。" + +msgid "Directory does not exist!" +msgstr "目录不存在!" + +msgid "Disc 1" +msgstr "光盘 1" + +msgid "Disc 2" +msgstr "光盘 2" + +msgid "Disc Artwork Download" +msgstr "光盘图片下载" + +msgid "Disc Artwork Path" +msgstr "光盘图片路径" + +msgid "Disc Default" +msgstr "游戏默认" + +msgid "Disc Insert Detected" +msgstr "光盘已插入" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "光盘读取错误。" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "DM(L) v2.6 或以上版本需要将光盘 2 安装为非压缩格式,是否仍然以压缩格式安装?" + +msgid "Discarts" +msgstr "光盘图片" + +msgid "DiskFlip" +msgstr "光盘滑动" + +msgid "Display" +msgstr "显示" + +msgid "Display as a carousel" +msgstr "走马灯模式" + +msgid "Display as a channel grid" +msgstr "频道封面墙模式" + +msgid "Display as a grid" +msgstr "封面墙模式" + +msgid "Display as a list" +msgstr "列表模式" + +msgid "Display favorites only" +msgstr "收藏夹模式" + +msgid "Do you want to apply it now?" +msgstr "要现在应用吗?" + +msgid "Do you want to apply this theme?" +msgstr "你想应用这个主题吗?" + +msgid "Do you want to change language?" +msgstr "要变更语言吗?" + +msgid "Do you want to continue with next game?" +msgstr "要继续玩下一个游戏吗?" + +msgid "Do you want to copy now?" +msgstr "是否现在复制?" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "是否要复制游戏至 SD 卡或删除 SD 卡上的游戏?" + +msgid "Do you want to delete a game on SD?" +msgstr "是否要删除 SD 卡上的游戏?" + +msgid "Do you want to discard changes?" +msgstr "是否放弃更改?" + +msgid "Do you want to download this theme?" +msgstr "要下载这个主题吗?" + +msgid "Do you want to extract all the save games?" +msgstr "是否提取所有已保存游戏?" + +msgid "Do you want to extract the save game?" +msgstr "是否提取已保存游戏?" + +msgid "Do you want to format:" +msgstr "是否格式化:" + +msgid "Do you want to install selected games?" +msgstr "是否安装选定的游戏?" + +msgid "Do you want to load the default theme?" +msgstr "要加载默认主题吗?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "是否重新初始化网络?" + +msgid "Do you want to start the game now?" +msgstr "是否立刻开始游戏?" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "是否同步剩余空间信息扇区到所有 FAT32 分区?" + +msgid "Do you wish to update/download all language files?" +msgstr "升级/下载语言文件?" + +msgid "Dol Video Patch" +msgstr "DOL视频补丁" + +msgid "Download" +msgstr "下载" + +msgid "Download Now" +msgstr "现在下载" + +msgid "Download finished" +msgstr "下载完成" + +msgid "Downloading 3D Covers" +msgstr "正在下载 3D 封面" + +msgid "Downloading Custom Banners" +msgstr "正在下载自制光盘封面" + +msgid "Downloading Flat Covers" +msgstr "正在下载 2D 封面" + +msgid "Downloading Full HQ Covers" +msgstr "正在下载高清晰完整封面" + +msgid "Downloading Full LQ Covers" +msgstr "正在下载低清晰完整封面" + +msgid "Downloading custom Discarts" +msgstr "正在下载自制光盘封面" + +msgid "Downloading file..." +msgstr "正在下载文件 ..." + +msgid "Downloading image:" +msgstr "正在下载图片:" + +msgid "Downloading original Discarts" +msgstr "正在下载原始光盘封面" + +msgid "Downloading pagelist:" +msgstr "正在下载分页列表:" + +msgid "Dump NAND to EmuNand" +msgstr "转存 NAND 至 EmuNand" + +msgid "During zoom" +msgstr "在缩放大小时" + +msgid "Dutch" +msgstr "荷文" + +msgid "ERROR" +msgstr "错误" + +msgid "ERROR:" +msgstr "错误:" + +msgid "ERROR: Can't set up theme." +msgstr "错误:无法设置主题。" + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "EmuNand 频道" + +msgid "Emulated Nand" +msgstr "启动 EmuNand" + +msgid "English" +msgstr "英文" + +msgid "Enter Path" +msgstr "输入路径" + +msgid "Error" +msgstr "错误" + +msgid "Error !" +msgstr "错误!" + +#, c-format +msgid "Error creating path: %s" +msgstr "创建路径时出错: %s" + +msgid "Error opening downloaded file" +msgstr "打开下载文件时出错" + +msgid "Error reading Disc" +msgstr "读取光盘时出错" + +msgid "Error reading disc" +msgstr "读取光盘时出错" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "下载文件时出错: %i" + +msgid "Error while downloding file" +msgstr "下载文件时出错" + +msgid "Error while opening the zip." +msgstr "打开 zip 文件时出错。" + +msgid "Error while transfering data." +msgstr "传送数据时出错。" + +msgid "Error while updating USB Loader GX." +msgstr "升级 USB Loader GX 时出错。" + +msgid "Error writing the data." +msgstr "写入数据时出错。" + +msgid "Error:" +msgstr "错误:" + +msgid "Error: Not enough space on SD." +msgstr "错误:SD 卡上没有足够的空间。" + +msgid "Errors occured." +msgstr "发生错误。" + +msgid "Everything" +msgstr "全部" + +msgid "Exit" +msgstr "退出" + +msgid "Exit to where?" +msgstr "退出到哪里?" + +msgid "Export All Saves to EmuNand" +msgstr "提取所有游戏存档至 EmuNand" + +msgid "Export Miis to EmuNand" +msgstr "提取 Miis 至 EmuNand" + +msgid "Export SYSCONF to EmuNand" +msgstr "提取 SYSCONF 至 EmuNand" + +msgid "Extract Miis to the Emu NAND?" +msgstr "是否将 Miis 提取至 EmuNand?" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "是否将 SYSCONF 提取至 EmuNand?" + +msgid "Extract Save to EmuNand" +msgstr "提取游戏存档至 EmuNand" + +msgid "Extracting file:" +msgstr "正在提取文件:" + +msgid "Extracting files..." +msgstr "正在提取文件 ..." + +msgid "Extracting files:" +msgstr "正在提取文件:" + +msgid "Extracting nand files:" +msgstr "正在提取 Nand 文件:" + +msgid "F-Zero AX" +msgstr "F-Zero AX" + +msgid "Failed" +msgstr "已失败" + +msgid "Failed copying file" +msgstr "复制文件时失败" + +msgid "Failed formating" +msgstr "格式化失败" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "提取所有文件时失败。游戏存档可能不存在。" + +msgid "Failed to extract." +msgstr "提取失败。" + +msgid "Failed to initialize the USB storage device." +msgstr "初始化 USB 存储设备时失败。" + +msgid "Failed to open partition" +msgstr "打开分区失败" + +msgid "Failed to read ticket." +msgstr "读取 ticket 时失败。" + +msgid "Failed to read tmd file." +msgstr "读取 tmd 文件时失败。" + +msgid "Failed to read wad header." +msgstr "读取 wad 头部信息时失败。" + +msgid "Failed updating" +msgstr "升级失败" + +msgid "Favorite Level" +msgstr "收藏夹级别。" + +msgid "Features" +msgstr "功能" + +msgid "Features Settings" +msgstr "功能设置" + +msgid "Feb" +msgstr "二月" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "找不到文件。" + +msgid "File read/write error." +msgstr "文件读写出错。" + +msgid "Files extracted successfully." +msgstr "文件已成功提取。" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "文件大小是 %i 字节。" + +msgid "Filesize is 0 Byte." +msgstr "文件大小是 0 字节。" + +msgid "Flat Covers" +msgstr "普通封面" + +msgid "Flip-X" +msgstr "按键规则" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "字体比例因数" + +msgid "Force 16:9" +msgstr "强制 16:9" + +msgid "Force 4:3" +msgstr "强制 4:3" + +msgid "Force NTSC" +msgstr "强制 NTSC" + +msgid "Force NTSC480p" +msgstr "强制 NTSC480p" + +msgid "Force PAL480p" +msgstr "強制 PAL480p" + +msgid "Force PAL50" +msgstr "强制 PAL50" + +msgid "Force PAL60" +msgstr "强制 PAL60" + +msgid "Force Titles from Disc" +msgstr "强制从光盘读取标题" + +msgid "Force Widescreen" +msgstr "强制宽屏" + +msgid "Format" +msgstr "格式化" + +msgid "Formatting, please wait..." +msgstr "格式化中,请稍候 ..." + +msgid "Found missing images." +msgstr "找到缺少的图片。" + +msgid "Frame" +msgstr "帧" + +msgid "Frame Projection Height" +msgstr "帧投影高度" + +msgid "Frame Projection Width" +msgstr "帧投影宽度" + +msgid "Frame Projection X-Offset" +msgstr "帧投影 X 轴偏移" + +msgid "Frame Projection Y-Offset" +msgstr "帧投影 Y 轴偏移" + +msgid "Frames" +msgstr "帧数" + +msgid "Free Space" +msgstr "剩余空间" + +msgid "French" +msgstr "法文" + +msgid "Full" +msgstr "全部" + +msgid "Full Cover Path" +msgstr "完整封面路径" + +msgid "Full Covers" +msgstr "全部封面" + +msgid "Full Menu" +msgstr "完整菜单" + +msgid "Full covers Download" +msgstr "全部封面下载" + +msgid "Full shutdown" +msgstr "完全关机" + +msgid "GAMEID_Gamename" +msgstr "GameID_游戏名" + +msgid "GC Banner Scale" +msgstr "GC 频道大小" + +msgid "GC Games" +msgstr "GC 游戏" + +msgid "GC Install 32K Aligned" +msgstr "GC 安装 32K 对齐" + +msgid "GC Install Compressed" +msgstr "GC 压缩安装" + +msgid "GCT Cheatcodes Path" +msgstr "作弊码路径" + +msgid "GCT File created" +msgstr "GCT 文件已建立" + +msgid "GUI Settings" +msgstr "界面设置" + +msgid "GXDraw" +msgstr "GXDraw" + +msgid "GXFlush" +msgstr "GXFlush" + +msgid "Game Cube Games Delete" +msgstr "GameCube 游戏删除" + +msgid "Game Cube Install Menu" +msgstr "GameCube 安装菜单" + +msgid "Game ID" +msgstr "游戏 ID" + +msgid "Game IOS" +msgstr "游戏 IOS" + +msgid "Game Language" +msgstr "游戏语言" + +msgid "Game Load" +msgstr "游戏载入" + +msgid "Game Lock" +msgstr "锁定游戏" + +msgid "Game Only" +msgstr "仅游戏" + +msgid "Game Region" +msgstr "游戏区域" + +msgid "Game Size" +msgstr "游戏容量" + +msgid "Game Sound Mode" +msgstr "游戏声音模式" + +msgid "Game Sound Volume" +msgstr "游戏音量" + +msgid "Game Split Size" +msgstr "游戏分割大小" + +msgid "Game Window Mode" +msgstr "游戏窗口模式" + +msgid "Game is already installed:" +msgstr "游戏已安装:" + +msgid "Game's IOS" +msgstr "游戏的IOS" + +msgid "Game/Install Partition" +msgstr "游戏/安装分区" + +msgid "GameCube" +msgstr "GameCube" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "GameCube 模式" + +msgid "GameCube Source" +msgstr "GameCube 来源" + +msgid "Gamename [GAMEID]" +msgstr "游戏名 [GAMEID]" + +msgid "Games" +msgstr "游戏" + +msgid "Generating GXGameCategories.xml" +msgstr "正在生成 GXGameCategories.xml" + +msgid "Genre:" +msgstr "类型:" + +msgid "German" +msgstr "德文" + +msgid "Getting file list..." +msgstr "获取文件列表..." + +msgid "Getting game folder size..." +msgstr "获取游戏目录尺寸..." + +msgid "Global Settings" +msgstr "全局设置" + +msgid "Grid Scroll Speed" +msgstr "封面墙滚动速度" + +msgid "HOME Menu" +msgstr "主菜单" + +msgid "Hard Drive Settings" +msgstr "硬盘设置" + +msgid "High Quality" +msgstr "高品质" + +msgid "High/Low" +msgstr "高/低" + +msgid "Homebrew Apps Path" +msgstr "自制程序路径" + +msgid "Homebrew Channel" +msgstr "自制程序频道" + +msgid "Homebrew Launcher" +msgstr "自制程序管理器" + +msgid "Hooktype" +msgstr "挂载类型" + +msgid "Hour" +msgstr "小时" + +msgid "How do you want to update?" +msgstr "你要升级哪些文件?" + +msgid "How to Shutdown?" +msgstr "如何关机?" + +msgid "Import Categories" +msgstr "导入分类" + +msgid "Import operation successfully completed." +msgstr "导入操作成功完成。" + +msgid "Importing categories" +msgstr "导入分类" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "正在接收文件 %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "正在接收文件 %0.2fMB" + +msgid "Individual" +msgstr "个人" + +msgid "Initializing Network" +msgstr "正在启动网络" + +msgid "Insert Disk" +msgstr "插入光盘" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "插入一张 Wii 或 GC 光盘!" + +msgid "Install" +msgstr "安装" + +msgid "Install Canceled" +msgstr "安装已取消" + +msgid "Install Directories" +msgstr "安装目录" + +msgid "Install Error!" +msgstr "安装错误!" + +msgid "Install Partitions" +msgstr "安装分区" + +msgid "Install a game" +msgstr "安装游戏" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "安装已完成" + +msgid "Installing Game Cube Game..." +msgstr "正在安装 GameCube 游戏..." + +msgid "Installing content" +msgstr "正在安装内容" + +msgid "Installing game:" +msgstr "正在安装游戏:" + +msgid "Installing title..." +msgstr "正在安装标题..." + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "输入的 IOS 编号无效。编号必须由原值减 1 或介于 200 至 255 之间。" + +msgid "Invalid wad file." +msgstr "无效的 wad 文件。" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "看来你有一些能帮到我们的信息。请将这些信息发送给开发团队。" + +msgid "Italian" +msgstr "意大利文" + +msgid "Jan" +msgstr "一月" + +msgid "Japanese" +msgstr "日文" + +msgid "Japanese Patch" +msgstr "日语补丁" + +msgid "Joypad" +msgstr "摇杆" + +msgid "July" +msgstr "七月" + +msgid "June" +msgstr "六月" + +msgid "KPAD Read" +msgstr "KPAD Read" + +msgid "Keyboard" +msgstr "键盘" + +msgid "Korean" +msgstr "韩文" + +msgid "LED Activity" +msgstr "LED灯显示开启" + +msgid "Language Files" +msgstr "语言文件" + +msgid "Language change:" +msgstr "变更语言:" + +msgid "Languagefiles Path" +msgstr "语言文件路径" + +msgid "Languagepath changed." +msgstr "语言文件路径已变更" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "需要 d2x cIOS 才能从 EmuNand 加载 Wii 游戏!请先将游戏 IOS 设置为 d2x cIOS。" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "需要 d2x cIOS 才能加载 EmuNand 频道!请先将游戏 IOS 设置为 d2x cIOS。" + +msgid "Left" +msgstr "左" + +msgid "Like SysMenu" +msgstr "同系统菜单" + +msgid "List on Gamelaunch" +msgstr "游戏启动时选择" + +msgid "Load" +msgstr "载入" + +msgid "Load From SD/USB" +msgstr "从 SD/USB 载入" + +#, c-format +msgid "Load file from: %s ?" +msgstr "从 %s 加载文件?" + +msgid "Load this DOL as alternate DOL?" +msgstr "加载这个 DOL 作为 ALT DOL ?" + +msgid "Loader Settings" +msgstr "加载器设置" + +msgid "Loader's IOS" +msgstr "加载器的IOS" + +msgid "Loading standard language." +msgstr "加载标准语言。" + +msgid "Loading standard music." +msgstr "加载标准音乐。" + +msgid "Lock Console" +msgstr "锁定主机" + +msgid "Lock USB Loader GX" +msgstr "锁定 USB Loader GX" + +msgid "Locked" +msgstr "已锁定" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "循环目录" + +msgid "Loop Music" +msgstr "循环音乐" + +msgid "Loop Sound" +msgstr "循环声音" + +msgid "Low Quality" +msgstr "低品质" + +msgid "Low/High" +msgstr "低/高" + +msgid "MIOS (Default & Customs)" +msgstr "MIOS (默认&自定义)" + +msgid "Main DOL" +msgstr "首选 DOL" + +msgid "Main GameCube Games Path" +msgstr "首选 GameCube 游戏路径" + +msgid "Main GameCube Path" +msgstr "首选 GameCube 路径" + +msgid "Main Path" +msgstr "首选路径" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "三月" + +msgid "Mark new games" +msgstr "标记新游戏" + +msgid "May" +msgstr "五月" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "记忆卡模拟" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "留言板更新" + +msgid "Motion+ Video" +msgstr "移动+视频" + +msgid "Mount DVD drive" +msgstr "挂载 DVD 光驱" + +msgid "Mount USB at launch" +msgstr "开启时加载USB设备" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "多分区" + +msgid "Music Loop Mode" +msgstr "音乐循环模式" + +msgid "Music Volume" +msgstr "音量" + +msgid "NMM Mode" +msgstr "免记忆卡模式" + +msgid "Nand Chan. Emulation" +msgstr "Nand 频道模拟" + +msgid "Nand Channels" +msgstr "Nand 频道" + +msgid "Nand Emu Channel Path" +msgstr "Nand 模拟频道路径" + +msgid "Nand Emu Path" +msgstr "Nand 模拟路径" + +msgid "Nand Emulation" +msgstr "Nand 模拟器" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "Nand 模拟器必须工作于 D2X cIOS!" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "Nand 模拟器只能工作于 FAT/FAT32 分区!" + +msgid "Nand Saves Emulation" +msgstr "Nand 存档模拟器" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "全不" + +msgid "Network is not initiated." +msgstr "网络尚未初始化。" + +msgid "Next" +msgstr "往后" + +msgid "Nintendont" +msgstr "Nintendont" + +msgid "Nintendont Loader Path" +msgstr "Nintendont加载器补丁" + +msgid "No" +msgstr "否" + +msgid "No Cheatfile found" +msgstr "作弊码文件没找到" + +msgid "No DOL file found on disc." +msgstr "光盘中未找到 DOL 文件。" + +msgid "No Disc+" +msgstr "无光盘" + +msgid "No Splitting" +msgstr "不分割" + +msgid "No URL or Path specified." +msgstr "未指定 URL 或路径。" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "找不到 WBFS 或 FAT/NTFS/EXT 分区" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "在配置路径中未找到 Wiinnertag.xml 。是否创建一个示例文件?" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "未选择金手指! GCT 文件是否已被删除?" + +msgid "No data could be read." +msgstr "无法读取数据。" + +msgid "No disc inserted." +msgstr "未插入光盘。" + +msgid "No favorites selected." +msgstr "未选择收藏。" + +msgid "No file missing!" +msgstr "没有缺少文件!" + +msgid "No games found on the disc" +msgstr "光盘中未找到游戏" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "存储设备中没有可更新的语言文件!是否下载新的语言文件?" + +msgid "No new updates." +msgstr "没有可用更新。" + +msgid "No themes found on the site." +msgstr "网站上没找到主题。" + +msgid "No themes found." +msgstr "没有找到主题。" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "无" + +msgid "Normal" +msgstr "一般" + +msgid "Not Initialized" +msgstr "未初始化" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "不是 Wii 或 GameCube 光盘" + +msgid "Not a valid URL" +msgstr "不是有效的 URL" + +msgid "Not a valid URL path" +msgstr "不是有效的 URL 路径" + +msgid "Not a valid domain" +msgstr "不是有效的域名" + +msgid "Not enough free memory." +msgstr "剩余内存不足。" + +msgid "Not enough free space on device." +msgstr "设备中没有足够的剩余空间。" + +msgid "Not enough free space!" +msgstr "剩余空间不足!" + +msgid "Not enough memory for FST." +msgstr "FST 剩余内存不足。" + +msgid "Not enough memory." +msgstr "内存不足。" + +msgid "Not required" +msgstr "不需要" + +msgid "Not supported format!" +msgstr "不支持的格式!" + +msgid "Nothing selected to delete." +msgstr "未选择要删除的内容。" + +msgid "Nothing selected to install." +msgstr "未选择要安装的内容。" + +msgid "Nov" +msgstr "十一月" + +msgid "OFF" +msgstr "关闭" + +msgid "OK" +msgstr "确定" + +msgid "ON" +msgstr "开启" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "OSSleepThread" + +msgid "Ocarina" +msgstr "Ocarina 金手指" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "十月" + +msgid "Official Site:" +msgstr "官方网址:" + +msgid "Offset" +msgstr "偏移位" + +msgid "Ok" +msgstr "确定" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "仅游戏分区" + +msgid "Only for Install" +msgstr "仅安装" + +msgid "Original" +msgstr "官方" + +msgid "Original/Customs" +msgstr "官方/自制" + +msgid "PAD Hook" +msgstr "PAD Hook" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "家长控制" + +msgid "Partial" +msgstr "部分的" + +msgid "Partition" +msgstr "分区" + +msgid "Password" +msgstr "密码" + +msgid "Password Changed" +msgstr "密码已变更" + +msgid "Password has been changed" +msgstr "密码已被变更" + +msgid "Patch Country Strings" +msgstr "设定区码" + +msgid "Path Changed" +msgstr "路径已变更" + +msgid "Permission denied." +msgstr "没有权限。" + +msgid "Pick from a list" +msgstr "从列表中选取" + +msgid "Pixels" +msgstr "像素" + +msgid "Play Count" +msgstr "游戏计数" + +msgid "Play Next" +msgstr "播放下一曲" + +msgid "Play Once" +msgstr "播放一次" + +msgid "Play Previous" +msgstr "播放上一曲" + +msgid "Playing Music:" +msgstr "正在播放音乐:" + +msgid "Please wait" +msgstr "请稍候" + +msgid "Please wait..." +msgstr "请等待 ..." + +msgid "Power off the Wii" +msgstr "关闭 Wii 主机" + +msgid "Prev" +msgstr "往前" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "操作已完成。" + +msgid "Progressive Patch" +msgstr "步进补丁" + +msgid "Prompts Buttons" +msgstr "显示校正" + +msgid "Published by" +msgstr "发行" + +msgid "Quick Boot" +msgstr "快速启动" + +msgid "Random Directory Music" +msgstr "随机目录音乐" + +msgid "Real Nand" +msgstr "真实 Nand" + +msgid "Receiving file from:" +msgstr "接收文件:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "区域补丁" + +msgid "Released" +msgstr "放出" + +msgid "Reload SD" +msgstr "重新载入 SD 卡" + +msgid "Reloading game list now, please wait..." +msgstr "正在重新加载游戏列表,请稍候..." + +msgid "Remember Unlock" +msgstr "存储解锁" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "删除更新" + +msgid "Rename Game Title" +msgstr "修改游戏标题" + +msgid "Rename category" +msgstr "修改分类名" + +msgid "Reset" +msgstr "重启" + +msgid "Reset BG Music" +msgstr "重置背景音乐" + +msgid "Reset Playcounter" +msgstr "重置游戏计数" + +msgid "Reset to default BGM?" +msgstr "重置为默认背景音乐?" + +msgid "Restarting..." +msgstr "重启中 ..." + +msgid "Return" +msgstr "返回" + +msgid "Return To" +msgstr "返回至" + +msgid "Return to Wii Menu" +msgstr "返回 Wii 主菜单" + +msgid "Right" +msgstr "右" + +msgid "Rotating Disc" +msgstr "选择光盘" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "震动" + +msgid "SChinese" +msgstr "简体中文" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "SD 卡不能访问。" + +msgid "SD GameCube Games Path" +msgstr "SD GameCube 游戏路径" + +msgid "SD GameCube Path" +msgstr "SD GameCube 路径" + +msgid "SD Path" +msgstr "SD 卡路径" + +msgid "SFX Volume" +msgstr "SFX 音量" + +msgid "Save" +msgstr "保存" + +msgid "Save Failed. No device inserted?" +msgstr "保存失败。 可能是没有设备插入?" + +msgid "Save Game List to" +msgstr "保存游戏列表到" + +msgid "Save List" +msgstr "保存列表" + +msgid "Saved" +msgstr "已保存" + +msgid "Savegame might not exist for this game." +msgstr "该游戏的存档可能不存在。" + +msgid "Screensaver" +msgstr "屏幕保护" + +msgid "Screenshot" +msgstr "截图" + +msgid "Select" +msgstr "选择" + +msgid "Select DOL Offset" +msgstr "选择 DOL 偏移位" + +msgid "Select a DOL" +msgstr "选择一个 DOL" + +msgid "Select a DOL from Game" +msgstr "从游戏选择 DOL" + +msgid "Select game categories" +msgstr "选择游戏分类" + +msgid "Select loader mode" +msgstr "选择加载器模式" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "选择标题来源。" + +msgid "Sept" +msgstr "九月" + +msgid "Set Search-Filter" +msgstr "设置搜索过滤器" + +msgid "Settings" +msgstr "設置" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "显示分类" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "显示剩余空间" + +msgid "Show Play Count" +msgstr "显示执行次数" + +msgid "Show SD" +msgstr "显示 SD 卡" + +msgid "Shutdown System" +msgstr "关闭系统" + +msgid "Shutdown Wii" +msgstr "关闭 Wii" + +msgid "Skip Errors" +msgstr "跳过错误" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "Sneek 视频补丁" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "按字母排序" + +msgid "Sort by number of players" +msgstr "以玩家数量排序" + +msgid "Sort by rank" +msgstr "以排名排序" + +msgid "Sort order by most played" +msgstr "按玩过次数排序" + +msgid "Sound" +msgstr "声音" + +msgid "Sound Settings" +msgstr "声音设置" + +msgid "Sound+BGM" +msgstr "声音+背景音乐" + +msgid "Sound+Quiet" +msgstr "声音+静音" + +msgid "Spanish" +msgstr "西班牙文" + +msgid "Special thanks to:" +msgstr "特别感谢:" + +msgid "Split each 2GB" +msgstr "每个分割为 2GB" + +msgid "Split each 4GB" +msgstr "每个分割为 4GB" + +msgid "Standby" +msgstr "待机" + +msgid "Start" +msgstr "開始" + +msgid "Success" +msgstr "成功" + +msgid "Success." +msgstr "成功。" + +msgid "Success:" +msgstr "成功:" + +msgid "Successfully Saved" +msgstr "保存成功" + +msgid "Successfully Updated" +msgstr "升级成功!" + +msgid "Successfully copied" +msgstr "已成功复制" + +msgid "Successfully deleted:" +msgstr "成功删除:" + +msgid "Successfully extracted theme." +msgstr "解压主题成功" + +msgid "Successfully installed:" +msgstr "成功安装:" + +msgid "Successfully updated." +msgstr "已成功更新。" + +msgid "Switching to channel list mode." +msgstr "正在切换至频道列表模式。" + +msgid "Sync FAT32 FS Info" +msgstr "同步 FAT32 文件系统信息" + +msgid "Synchronizing..." +msgstr "正在同步 ..." + +msgid "System Default" +msgstr "系统默认" + +msgid "TChinese" +msgstr "繁体中文" + +msgid "TXT Cheatcodes Path" +msgstr "TXT 作弊码路径" + +msgid "The .them file was not found in the zip." +msgstr "zip 文件中没有找到 .them 文件。" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "强制宽屏需要 DIOS-MIOS v2.1 或以上版本。该设置将被忽略。" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Miis 将被提取至模拟 NAND 路径和模拟 NAND 频道路径。注意:所有已存在的文件都将被覆盖。" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "免光盘模式需要 DIOS-MIOS v2.2 update2。该设置将被忽略。" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "SYSCONF 文件将被提取至模拟 NAND 路径和模拟 NAND 频道路径。注意:所有已存在的文件都将被覆盖。" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "如正在读写 SD 卡,程序有可能会崩溃!" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "已进入的目录不存在。你想要创建一个目录吗?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "文件将被提取至模拟 NAND 路径和模拟 NAND 频道路径。注意:所有已存在的文件都将被覆盖。" + +msgid "The game is on SD Card." +msgstr "该游戏位于 SD 卡。" + +msgid "The game is on USB." +msgstr "该游戏位于 USB 设备。" + +msgid "The save game will be extracted to your emu nand path." +msgstr "游戏存档将被提取至模拟 NAND 路径和模拟 NAND 频道路径。注意:所有已存在的文件都将被覆盖。" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "游戏存档将被提取至模拟 NAND 路径和模拟 NAND 频道路径。注意:所有已存在的文件都将被覆盖。" + +msgid "The wad file was installed" +msgstr "WAD 文件已安装" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "WAD 安装失败,错误号 %i" + +msgid "Theme Downloader" +msgstr "主题下载器" + +msgid "Theme Menu" +msgstr "主题菜单" + +msgid "Theme Path" +msgstr "主题路径" + +msgid "Theme Title:" +msgstr "主题名称:" + +msgid "Themes by www.spiffy360.com" +msgstr "www.spiffy360.com 的主题" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "该 IOS 是BootMii IOS 。如果你确定它不是 BootMii 并且安装了其他 IOS 则可忽略该警告。" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "在 titles 列表中未找到该 IOS 。如果你确定已安装则可忽略该警告。" + +msgid "This Nintendont version does not support games on USB." +msgstr "Nintendont版本不支持在USB上运行游戏。" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "该游戏有多张光盘。请选择想要加载的光盘。" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "该路径必须位于 SD 卡!" + +msgid "Time left:" +msgstr "剩余时间:" + +msgid "Timer Fix" +msgstr "定时器修复" + +msgid "Title Launcher" +msgstr "系统频道" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "从 GameTDB 读取标题" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "想要加载光盘上的 GameCube 游戏,请将游戏设置中的 GameCube 模式设置为 MIOS。" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "为了运行Gamecube游戏需要用%s替换在fat32分区usb上面的内容。" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "为了运行Gamecube游戏需要用%s设置你的'主Gamecube路径'在FAT32放到usb分区上." + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "为了运行Gamecube游戏需要用%s使用512字节/扇区的硬盘。" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "为了运行Gamecube游戏需要用%s使用32k字节/簇或者小于的硬盘。" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "为了使用Devolution运行Gamecube游戏,你需要放置loader.bin文件在Devolution加载器的目录中。" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "为了使用Nintendont运行Gamecube游戏,你需要放置boot.dol文件在Nintendont加载器的目录中。" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "为了使用HID %s 你需要%s文件。" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "为了是哦那个金手指%s你需要 %s 文件。 " + +msgid "Tooltip Delay" +msgstr "提示信息延迟时间" + +msgid "Tooltips" +msgstr "提示信息" + +msgid "Transfer failed" +msgstr "传输失败" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "USB设备无法初始化。" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX 被锁定" + +msgid "USB Port" +msgstr "USB 接口" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "仅 Hermes cIOS 支持改变 USB 接口。" + +msgid "USB-HID Controller" +msgstr "USB—HID手柄" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "USBloaderGX不能验证Nintendont boot.dol文件。无论如何都运行此boot。dol程序?" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "USBloaderGX不能写Nintendont设置文件,是否运行Nintendont?" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "USBloaderGX r1218之针对nintendont Alpha v0.1,请更新你的Nintendont boot。dol版本。" + +msgid "Uninstall" +msgstr "删除" + +msgid "Uninstall Game" +msgstr "删除游戏" + +msgid "Uninstall Menu" +msgstr "删除菜单" + +msgid "Uninstall all" +msgstr "卸载所有" + +msgid "Unknown" +msgstr "未知" + +msgid "Unlock USB Loader GX" +msgstr "解锁 USB Loader GX" + +msgid "Unlocked" +msgstr "已解锁" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "不支持的格式,请手动解压缩 TempTheme.zip 。" + +msgid "Update" +msgstr "升级" + +msgid "Update All" +msgstr "全部升级" + +msgid "Update DOL" +msgstr "仅升级主程序" + +msgid "Update Files" +msgstr "升级文件" + +msgid "Update Path" +msgstr "升级文件存放路径" + +msgid "Update all Language Files" +msgstr "升级全部语言文件" + +msgid "Update failed" +msgstr "升级失败" + +msgid "Update successfull" +msgstr "升级成功" + +msgid "Updating Language Files:" +msgstr "正在升级语言文件:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "上传已安装 Zip 文件到自制程序目录" + +msgid "Use System Font" +msgstr "使用系统字体" + +msgid "Use global" +msgstr "使用全局设置" + +msgid "VBI (Default)" +msgstr "VBI (预设)" + +msgid "VIDTV Patch" +msgstr "VIDTV 补丁" + +msgid "Version:" +msgstr "版本:" + +#, c-format +msgid "Version: %s" +msgstr "版本: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "视频制式" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "虚拟指针速度" + +msgid "WDM Files Path" +msgstr "WDM 文件路径" + +msgid "WIP Patches Path" +msgstr "WIP 补丁路径" + +msgid "Waiting..." +msgstr "等待中 ..." + +msgid "Warning" +msgstr "警告" + +msgid "Warning:" +msgstr "警告:" + +msgid "What do you want to do?" +msgstr "你想要做什么?" + +msgid "What do you want to update?" +msgstr "要升级什么?" + +msgid "What should be deleted for this game title:" +msgstr "要删除这个游戏的什么:" + +msgid "What to extract from NAND?" +msgstr "从 NAND 中提取什么?" + +msgid "Where should the game be installed to?" +msgstr "游戏安装到什么地方?" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "WiFi 功能" + +msgid "Widescreen Factor" +msgstr "宽屏因数" + +msgid "Widescreen Fix" +msgstr "宽屏校正" + +msgid "Wii Games" +msgstr "Wii 游戏" + +msgid "Wii Menu" +msgstr "Wii 系统菜单" + +msgid "Wii Settings" +msgstr "Wii 设置" + +msgid "WiiTDB.xml" +msgstr "WiiTDB.xml" + +msgid "WiiTDB.xml is up to date." +msgstr "WiiTDB.xml 已是最新版。" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "光驱灯" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "Wiinnertag" + +msgid "Wiinnertag Path" +msgstr "Wiinnertag 路径" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Wiinnertag 需要启用程序启动时自动连接网络的功能。是否现在启用?" + +msgid "Wiird Debugger" +msgstr "Wiird 除错器" + +#, c-format +msgid "Write error on file: %s" +msgstr "写入该文件出错: %s" + +msgid "Writing GXGameCategories.xml" +msgstr "正在写入 GXGameCategories.xml" + +msgid "Wrong Password" +msgstr "密码错误" + +msgid "Yes" +msgstr "是" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "低于 r18 版本的 cIOS 249 不支持 FAT32/NTFS/EXT 分区。如要继续风险自负。" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "你可以选择或格式化一个分区,或使用频道加载器模式。" + +msgid "You cannot delete this category." +msgstr "无法删除该分类。" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "你需要安装 DIOS-MIOS Lite v1.2 或更新版本。" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "你需要安装另外的Gamecube加载器或者选择不同的Gamecub模式来从usb或者sd卡运行Gamecube游戏。" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "缩放间隔 (速度)" + +msgid "and translators for language files updates" +msgstr "以及翻译人员的语言文件更新" + +msgid "available" +msgstr "允许" + +msgid "does not exist!" +msgstr "不存在!" + +msgid "does not exist! Loading game without cheats." +msgstr "不存在!游戏以无作弊码方式载入。" + +msgid "files left" +msgstr "剩余文件" + +msgid "for FAT/NTFS support" +msgstr "的 FAT/NTFS 支持" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "设置 GameTDB 与封面 / 光盘图片文件存放空间" + +msgid "for Ocarina" +msgstr "的 Ocarina" + +msgid "for diverse patches" +msgstr "的多个补丁" + +msgid "for his awesome tool LibWiiGui" +msgstr "的优秀工具 LibWiiGui" + +msgid "for hosting the themes" +msgstr "的主题服务器" + +msgid "for the USB Loader source" +msgstr "放出 USB Loader 源代码" + +msgid "for their work on the wiki page" +msgstr "与他们在 wiki 网页的付出" + +msgid "formatted!" +msgstr "完成格式化!" + +msgid "free" +msgstr "剩余" + +msgid "ms" +msgstr "毫秒" + +msgid "not set" +msgstr "未设定" + +msgid "of" +msgstr "的" + +msgid "seconds left" +msgstr "剩余秒数" + +#~ msgid "Install WAD to EmuNand" +#~ msgstr "安装 WAD 至 EmuNand" + +#~ msgid "WAD Installation" +#~ msgstr "WAD 安装" + +#~ msgid "GameTDB Path" +#~ msgstr "GameTDB 路径" + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on a primary partition." +#~ msgstr "为了运行Gamecube游戏需要用%s设置你的'主Gamecube路径'在主分区上." + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first partition of the Hard Drive." +#~ msgstr "为了运行Gamecube游戏需要用%s设置你的'主Gamecube路径'在第一个主分区上." + +#~ msgid "Error 002 fix" +#~ msgstr "002 错误修正" + +#~ msgid "Use Game Settings" +#~ msgstr "使用游戏设置" + +#~ msgid "Anti" +#~ msgstr "防止" + +#~ msgid "Main tester:" +#~ msgstr "主要测试员:" + +#~ msgid "USB Device not found." +#~ msgstr "未找到 USB 设备。" + +#~ msgid "Boot/Standard" +#~ msgstr "启动/标准" + +#~ msgid "DEVO Force Widescreen" +#~ msgstr "DEVO 强制宽屏" + +#~ msgid "DEVO LED Activity" +#~ msgstr "DEVO 开启 LED" + +#~ msgid "DEVO MemCard Emulation" +#~ msgstr "DEVO 模拟记忆卡" + +#~ msgid "DML Auto" +#~ msgstr "DML 自动" + +#~ msgid "DML Debug" +#~ msgstr "DML 除错" + +#~ msgid "DML Force Widescreen" +#~ msgstr "DML 强制宽屏" + +#~ msgid "DML Japanese Patch" +#~ msgstr "DML 日语补丁" + +#~ msgid "DML LED Activity" +#~ msgstr "DML 开启 LED" + +#~ msgid "DML NMM Mode" +#~ msgstr "DML 免记忆卡模式" + +#~ msgid "DML No Disc+" +#~ msgstr "DML 免光盘模式" + +#~ msgid "DML None" +#~ msgstr "DML 无" + +#~ msgid "DML PAD Hook" +#~ msgstr "DML PAD 挂载" + +#~ msgid "DML Progressive Patch" +#~ msgstr "DML 级进补丁" + +#~ msgid "DML Screenshot" +#~ msgstr "DML 屏幕截图" + +#~ msgid "DML Video Mode" +#~ msgstr "DML 视频模式" + +#~ msgid "Devolution requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +#~ msgstr "Devolution 需要 AHBPROT 模式!请从 HBC,或一个已升级的频道或 forwarder 加载 USBLoaderGX。" + +#~ msgid "To run GameCube games with DIOS MIOS you need to place them on an USB FAT32 partition." +#~ msgstr "想要使用 DIOS-MIOS 加载 GameCube 游戏,请将其放置在一个 USB 设备的 FAT32 分区中。" + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' on a primary partition." +#~ msgstr "想要使用 DIOS-MIOS 加载 GameCube 游戏, ‘首选 GameCube 路径’必须设置在一个主要分区上。" + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' on the first partition of the Hard Drive." +#~ msgstr "想要使用 DIOS-MIOS 加载 GameCube 游戏, ‘首选 GameCube 路径’必须设置在硬盘的第一个分区上。" + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' to an USB FAT32 partition." +#~ msgstr "想要使用 DIOS-MIOS 加载 GameCube 游戏, ‘首选 GameCube 路径’必须设置在一个位于 USB 设备的 FAT32 分区上。" + +#~ msgid "To run GameCube games with DIOS MIOS you need to use a 512 bytes/sector Hard Drive." +#~ msgstr "想要使用 DIOS-MIOS 加载 GameCube 游戏,你需要使用一个每扇区 512 字节的硬盘。" + +#~ msgid "To run GameCube games with DIOS MIOS you need to use a partition with 32k bytes/cluster or less." +#~ msgstr "想要使用 DIOS-MIOS 加载 GameCube 游戏,你需要使用一个每簇 32K 字节的硬盘。" + +#~ msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Path." +#~ msgstr "想要使用 Devolution 加载 GameCube 游戏,你在 Devolution 路径中放置 loader.bin。" + +#~ msgid "You need to install Devolution or DIOS MIOS (Lite) to launch GameCube games from USB or SD card" +#~ msgstr "你需要安装 Devolution 或 DIOS-MIOS (Lite) 以加载位于 USB 设备或 SD 卡上的 GameCube 游戏。" + +#~ msgid "You need to set GameCube Mode to Devolution to launch GameCube games from USB or SD card" +#~ msgstr "你需要将 GameCube 模式设置为 Devolution 以加载 USB 设备或 SD 卡上的 GameCube 游戏。" + +#~ msgid "Custom Discarts" +#~ msgstr "自定义光盘图片" + +#~ msgid "Full HQ Covers" +#~ msgstr "完整高清晰封面" + +#~ msgid "Full LQ Covers" +#~ msgstr "完整低清晰封面" + +#~ msgid "Original Discarts" +#~ msgstr "官方光盘图片" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "改变 WBFS (硬盘)上的游戏名称" + +#~ msgid "Successfully Updated thanks to www.techjawa.com" +#~ msgstr "更新成功。感谢 www.techjawa.com" + +#~ msgid "for hosting the update files" +#~ msgstr "的升级服务器" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "插入 Wii 光盘!" + +#~ msgid "Issue manager /" +#~ msgstr "问题管理 /" + +#~ msgid "No cheats were selected" +#~ msgstr "没有选择作弊码" + +#~ msgid "Not a Wii Disc" +#~ msgstr "不是 Wii 的光盘" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> 删除 tickets..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> 删除 tickets... 错误!" + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> 删除 tickets... 成功!" + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> 删除 title... 错误!" + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> 删除 title... 成功!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> 删除 title 内容 ..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> 删除 title 内容 ... 错误!" + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> 删除 title 内容 ... 成功!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> 删除 title..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> 完成安装 ..." + +#~ msgid ">> Installing content #" +#~ msgstr ">> 安装程序主体 #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> 安装 ticket..." + +#~ msgid ">> Installing title..." +#~ msgstr ">> 安装 title..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> 读取 WAD 数据 ..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> 读取 WAD 数据 ... 错误!" + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> 读取 WAD 数据 ... 成功!" + +#~ msgid "Done!" +#~ msgstr "完成!" + +#~ msgid "Error..." +#~ msgstr "错误 ..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "正在完成安装... 完成!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "正在安装程序主体... 完成!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "安装 ticket... 完成!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "安装 title... 完成!" + +#~ msgid "Installing wad" +#~ msgstr "安裝 WAD" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "读取 WAD 数据... 完成!" + +#~ msgid "Uninstalling wad" +#~ msgstr "卸载 WAD" + +#~ msgid "The game installation is disabled under this IOS because of instability in usb write." +#~ msgstr "由于 USB 写入不稳定,在这个 IOS 下游戏安装被禁用。" + +#~ msgid "You are currently using IOS" +#~ msgstr "正在使用 IOS" + +#~ msgid "New Disc Detected" +#~ msgstr "新光盘已检测" + +#~ msgid "USB Device not found" +#~ msgstr "找不到 USB 设备" + +#~ msgid "You need to select or format a partition" +#~ msgstr "你需要选择或者格式化一个分区" + +#~ msgid "Language File" +#~ msgstr "语言文件" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "使用 WiiTDB 游戏名" + +#~ msgid "WiiTDB Files" +#~ msgstr "WiiTDB 文件" + +#~ msgid "WiiTDB Path" +#~ msgstr "WiiTDB 路径" + +#~ msgid "WiiTDB is up to date." +#~ msgstr "WiiTDB 已更新。" + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "的 WiiTDB 和封面下载服务" + +#~ msgid "Automatic port switching is done on the fly. You need to change all custom paths to SD-Card first for this option or else it could damage a filesystem." +#~ msgstr "接口自动切换已生效。你需要立即更改所有自定义路径为 SD 卡,否则可能会损坏 USB 分区上的文件系统。" + +#~ msgid "Install directories" +#~ msgstr "安装目录" + +#~ msgid "Install partitions" +#~ msgstr "安装分区" + +#~ msgid " Wad Saved as:" +#~ msgstr "WAD 保存为:" + +#~ msgid "Delete ?" +#~ msgstr "删除?" + +#~ msgid "Keep" +#~ msgstr "保持" + +#~ msgid "Not a WAD file." +#~ msgstr "不是 WAD 文件。" + +#~ msgid "Author:" +#~ msgstr "作者:" + +#~ msgid "Do you want to load this theme?" +#~ msgstr "是否载入这个主题?" + +#~ msgid "Loading default theme." +#~ msgstr "正在加载默认主题。" + +#~ msgid "Theme path is changed." +#~ msgstr "主题路径已变更。" + +#~ msgid "Use IOS58" +#~ msgstr "使用 IOS58" + +#~ msgid "Custom Disc Images" +#~ msgstr "自定义光盘图片" + +#~ msgid "Download Boxart image?" +#~ msgstr "下载封盒图片?" + +#~ msgid "Download Discart image?" +#~ msgstr "下载光盘图片?" + +#~ msgid "Downloading file" +#~ msgstr "下载文件:" + +#~ msgid "Missing files" +#~ msgstr "缺少的文件" + +#~ msgid "Original Disc Images" +#~ msgstr "官方光盘图片" + +#~ msgid "files not found on the server!" +#~ msgstr "服务器中无此文件!" + +#~ msgid "Disc Images" +#~ msgstr "光盘图片" + +#~ msgid "Downloading covers" +#~ msgstr "正在下载封面" + +#~ msgid "Only Customs" +#~ msgstr "仅自制" + +#~ msgid "Only Original" +#~ msgstr "仅官方" + +#~ msgid "Trying custom Discarts" +#~ msgstr "尝试下载自制光盘封面" + +#~ msgid "Trying original Discarts" +#~ msgstr "尝试下载官方光盘封面" + +#~ msgid "Do you really want to delete:" +#~ msgstr "确定删除:" + +#~ msgid "Do you want to use the alternate DOL that is known to be correct?" +#~ msgstr "使用这个已知是正确的 Alt DOL 文件?" + +#~ msgid "0 (Locked and Unlocked Games)" +#~ msgstr "0 (锁定和未锁定游戏)" + +#~ msgid "1 (Unlocked Games Only)" +#~ msgstr "1 (仅未锁定游戏)" + +#~ msgid "BETA revisions" +#~ msgstr "测试版本" + +#~ msgid "GamesLevel" +#~ msgstr "游戏等级" + +#~ msgid "Unlock console to use this option." +#~ msgstr "请解锁主机以使用该功能。" + +#~ msgid "Enabling this option on a FAT partition might slow the startup of the loader." +#~ msgstr "在 FAT 分区启用这个选项可能减缓 Loader 启动速度。" + +#~ msgid "Unsupported format, try to extract manually." +#~ msgstr "不支持的格式,请手动解压缩。" + +#~ msgid "and translaters for language files updates" +#~ msgstr "和所有语言包更新的翻译者" + +#~ msgid "All partitions" +#~ msgstr "所有分区" + +#~ msgid "An Error occured" +#~ msgstr "发生一个错误" + +#~ msgid "AutoPatch" +#~ msgstr "自动修改" + +#~ msgid "Back to Loader" +#~ msgstr "返回加载器" + +#~ msgid "Checking for Updates" +#~ msgstr "检测软件最新版本" + +#~ msgid "Downloading" +#~ msgstr "下载" + +#~ msgid "Downloading files" +#~ msgstr "正在下载文件" + +#~ msgid "FAT: Use directories" +#~ msgstr "FAT:使用目录" + +#~ msgid "Game partition" +#~ msgstr "游戏分区" + +#~ msgid "Install 1:1 Copy" +#~ msgstr "安装 1:1 副本" + +#~ msgid "No SD-Card inserted!" +#~ msgstr "未插入 SD 卡!" + +#~ msgid "Parental Control disabled" +#~ msgstr "已禁用家长控制" + +#~ msgid "The wad file was installed. But It could not be deleted from the SD card." +#~ msgstr "WAD 已安装,但文件无法从 SD 卡中删除。" + +#~ msgid "The wad installation failed with error %ld" +#~ msgstr "WAD 安装失败,错误号 %ld" + +#~ msgid "Unable to open the wad that was just downloaded (%s)." +#~ msgstr "不能打开刚下载的 WAD 文件 (%s)。" + +#~ msgid "Update to" +#~ msgstr "升级到" + +#~ msgid "Updating" +#~ msgstr "升级中" + +#~ msgid "Updating Language Files..." +#~ msgstr "升级语言文件..." + +#~ msgid "Updating WiiTDB.zip" +#~ msgstr "正在升级 WiiTDB.zip" + +#~ msgid "Back to Wii Menu" +#~ msgstr "返回 Wii 系统菜单" + +#~ msgid "Checking existing artwork" +#~ msgstr "检测已存在的插图" + +#~ msgid "Confirm" +#~ msgstr "确定" + +#~ msgid "Connection lost..." +#~ msgstr "连接已丢失..." + +#~ msgid "Could not find a WBFS partition." +#~ msgstr "找不到 WBFS 分区。" + +#~ msgid "Could not open WBFS partition" +#~ msgstr "无法打开 WBFS 分区" + +#~ msgid "Could not read the disc." +#~ msgstr "无法读取光盘。" + +#~ msgid "Could not set USB." +#~ msgstr "无法设置 USB。" + +#~ msgid "Cover Path Changed" +#~ msgstr "封面路径已变更" + +#~ msgid "Download failed." +#~ msgstr "下载失败。" + +#~ msgid "Downloading Page List:" +#~ msgstr "正在下载分页列表:" + +#~ msgid "Download request failed." +#~ msgstr "下载请求失败。" + +#~ msgid "DOL path changed" +#~ msgstr "DOL 路径已变更" + +#~ msgid "Disc Path Changed" +#~ msgstr "光盘图片路径已变更" + +#~ msgid "Display favorites" +#~ msgstr "收藏夹模式" + +#~ msgid "Do you want to retry for 30 secs?" +#~ msgstr "是否等待 30 秒后重试?" + +#~ msgid "Force" +#~ msgstr "强制" + +#~ msgid "Full Shutdown" +#~ msgstr "完全关机" + +#~ msgid "GCT Cheatcodes Path changed" +#~ msgstr "作弊码路径已变更" + +#~ msgid "GXtheme.cfg not found in any subfolder." +#~ msgstr "没有在任一子目录中找到 GXtheme.cfg。" + +#~ msgid "Homebrew Appspath changed" +#~ msgstr "自制程序路径已变更" + +#~ msgid "If you don't have WiFi, press 1 to get an URL to get your WiiTDB.zip" +#~ msgstr "如果你没有联网,请按 1 键以获取一个 WiiTDB.zip 的下载链接。" + +#~ msgid "Insert an SD-Card to save." +#~ msgstr "插入 SD 卡以保存。" + +#~ msgid "Insert an SD-Card to use this option." +#~ msgstr "插入 SD 卡使用此功能。" + +#~ msgid "Invalid PIN code" +#~ msgstr "错误的 PIN 码" + +#~ msgid "Insert an SD-Card to download images." +#~ msgstr "插入 SD 卡以下载封面。" + +#~ msgid "Most likely it has dimensions that are not evenly divisible by 4." +#~ msgstr "图片格式错误,可能它的尺寸不是 4 的倍数。" + +#~ msgid "Network init error" +#~ msgstr "网络启动错误" + +#~ msgid "No .dol or .elf files found." +#~ msgstr "找不到 .dol 或 .elf 文件。" + +#~ msgid "No Favorites" +#~ msgstr "没有收藏记录" + +#~ msgid "No USB Device" +#~ msgstr "没有 USB 设备" + +#~ msgid "No USB Device found." +#~ msgstr "找不到 USB 设备。" + +#~ msgid "Normal Covers" +#~ msgstr "普通封面" + +#~ msgid "Not Found" +#~ msgstr "没找到" + +#~ msgid "Not a DOL/ELF file." +#~ msgstr "不是 DOL/ELF 文件。" + +#~ msgid "Paste it into your browser to get your WiiTDB.zip." +#~ msgstr "粘贴这个链接到浏览器来下载 WiiTDB.zip 文件。" + +#~ msgid "Save Failed" +#~ msgstr "保存失败" + +#~ msgid "Selected DOL" +#~ msgstr "已选择 DOL" + +#~ msgid "Shutdown to Idle" +#~ msgstr "进入待机状态" + +#~ msgid "Shutdown?" +#~ msgstr "要关机吗?" + +#~ msgid "Standard" +#~ msgstr "标准" + +#~ msgid "TXT Cheatcodes Path changed" +#~ msgstr "TXT 作弊码文件路径已变更" + +#~ msgid "Theme Download Path" +#~ msgstr "主题下载路径" + +#~ msgid "Theme Path Changed" +#~ msgstr "主题路径已变更" + +#~ msgid "Transfer failed." +#~ msgstr "传输失败。" + +#~ msgid "Update Path changed." +#~ msgstr "升级文件存放路径已变更。" + +#~ msgid "Waiting for USB Device" +#~ msgstr "等待 USB 设备。" + +#~ msgid "WiiTDB Path changed." +#~ msgstr "WiiTDB 路径已变更。" + +#~ msgid "You are about to delete " +#~ msgstr "即将删除" + +#~ msgid "You are choosing to display favorites and you do not have any selected." +#~ msgstr "你选择显示收藏夹但里面还没有任何收藏。" + +#~ msgid "You have attempted to load a bad image" +#~ msgstr "你在加载损坏的图像" + +#~ msgid "Your URL has been saved in %sWiiTDB_URL.txt." +#~ msgstr "链接已写入 %sWiiTDB_URL.txt 文件。" + +#~ msgid "does not exist! You Messed something up, Idiot." +#~ msgstr "不存在!你搞错什么东西了,小白。" + +#~ msgid "file left" +#~ msgstr "剩余文件" diff --git a/Languages/spanish.lang b/Languages/spanish.lang new file mode 100644 index 0000000..ec6f203 --- /dev/null +++ b/Languages/spanish.lang @@ -0,0 +1,2721 @@ +# USB Loader GX language source file. +# spanish.lang - r1235 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:05+0200\n" +"PO-Revision-Date: 2011-07-25 16:40+0200\n" +"Last-Translator: Galen/xFede\n" +"Language-Team: Penn, SirPalax, hvy109\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: Español\n" + +msgid " could not be downloaded." +msgstr " no se han podido descargar." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " ha sido Guardado. Algún código puede no funcionar correctamente. Si experimentas problemas, revisa el texto en un editor de texto para obtener más información." + +msgid " is not on the server." +msgstr " no existe en el servidor." + +#, c-format +msgid "%i files not found on the server!" +msgstr "¡%i archivos no encontrados en servidor!" + +#, c-format +msgid "%i missing files" +msgstr "Faltan %i archivos" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "%s sólo acepta juegos de GameCube en formato ISO." + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "¡%s requiere acceso AHB! Actualiza tu canal/forwarder o inicia el programa desde el Canal Homebrew." + +msgid "--== Devolution" +msgstr "-- Devolution" + +msgid "--== Nintendont" +msgstr "-- Nintendont" + +msgid "--== DIOS MIOS (Lite) " +msgstr "-- DIOS MIOS (Lite) " + +msgid "--== DM(L) + Nintendont" +msgstr "-- DM(L)/Nintendont " + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Todos)" + +msgid "1 (Child 7+)" +msgstr "1 (Niños 7+)" + +msgid "1 hour" +msgstr "1 hora" + +msgid "10 min" +msgstr "10 min." + +msgid "2 (Teen 12+)" +msgstr "2 (Adolescentes 12+)" + +msgid "20 min" +msgstr "20 min." + +msgid "2D Cover Path" +msgstr "Ruta Carátulas 2D" + +msgid "3 (Mature 16+)" +msgstr "3 (Jóvenes 16+)" + +msgid "3 min" +msgstr "3 min." + +msgid "30 min" +msgstr "30 min." + +msgid "3D Cover Path" +msgstr "Ruta Carátulas 3D" + +msgid "3D Covers" +msgstr "Carátulas 3D" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Sólo Adultos 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 min." + +msgid "=== GameCube Settings" +msgstr "== GameCube" + +msgid "AUTO" +msgstr "Automático" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "Añadir categoría" + +msgid "Adjust Overscan X" +msgstr "Ajuste Overscan X" + +msgid "Adjust Overscan Y" +msgstr "Ajuste Overscan Y" + +msgid "After zoom" +msgstr "Zoom Posterior" + +msgid "All" +msgstr "Todos" + +msgid "All Partitions" +msgstr "Todas las particiones" + +msgid "All files extracted." +msgstr "Todos los archivos extraidos." + +msgid "All images downloaded successfully." +msgstr "Todas las imagenes descargadas con éxito." + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Todas las características del USB Loader GX desbloqueadas." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "DOL Alternativo" + +msgid "An example file was created here:" +msgstr "Un archivo de ejemplo fue creado aquí:" + +msgid "Animation Start" +msgstr "Inicio de Animación" + +msgid "App Language" +msgstr "Idioma Aplicación" + +msgid "Apply" +msgstr "Aplicar" + +msgid "Apr" +msgstr "Abr" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "¿Seguro que quieres eliminar todos los juegos seleccionados de la tarjeta SD?" + +msgid "Are you sure you want to delete this category?" +msgstr "¿Quieres eliminar esta categoría?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "¿Quieres importar las categorías de juegos de GameTDB?" + +msgid "Are you sure you want to install on SD?" +msgstr "¿Quieres instalar en la SD?" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "¿Quieres bloquear USB Loader GX?" + +msgid "Are you sure you want to remount SD?" +msgstr "¿Quieres volver a montar la SD?" + +msgid "Are you sure you want to reset?" +msgstr "¿Quieres resetear?" + +msgid "Are you sure?" +msgstr "¿Estás seguro?" + +msgid "Aspect Ratio" +msgstr "Relación de Aspecto" + +msgid "Attention!" +msgstr "¡Atención!" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "Ago" + +msgid "Author(s):" +msgstr "Autor(es):" + +msgid "Auto" +msgstr "Automático" + +msgid "Auto Boot" +msgstr "Autoarranque" + +msgid "AutoInit Network" +msgstr "Auto Iniciar la Red" + +msgid "BCA Codes Path" +msgstr "Ruta Códigos BCA" + +msgid "Back" +msgstr "Atrás" + +msgid "Back to HBC or Wii Menu" +msgstr "Volver a HBC o Menú Wii" + +msgid "Backgroundmusic" +msgstr "Música de fondo" + +msgid "Banner Animation" +msgstr "Animación Banner" + +msgid "Banner Animation Settings" +msgstr "Opciones de Animación Banner" + +msgid "Banner On Channels" +msgstr "Banner en canales" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "El modo de vista Banner solo esta disponible con AHBPROT! instala una versión actual de HBC." + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "Las ventanas Banner solo estan disponible con AHBPROT! Por favor instala una nueva versión de HBC." + +msgid "Big thanks to:" +msgstr "Gracias a:" + +msgid "Block Categories Menu" +msgstr "Bloq. Menú Categorías" + +msgid "Block Categories Modify" +msgstr "Bloq. Modif. Categorías" + +msgid "Block Cover Downloads" +msgstr "Bloq. Descarga Carátulas" + +msgid "Block Custom Paths" +msgstr "Bloquear Rutas Personal." + +msgid "Block Feature Settings" +msgstr "Bloq. Conf. Característ." + +msgid "Block Game Install" +msgstr "Bloquear Instal. Juegos" + +msgid "Block Game Settings" +msgstr "Bloquear Config. Juegos" + +msgid "Block GameID Change" +msgstr "Bloquear Cambio IDjuego" + +msgid "Block Global Settings" +msgstr "Bloquear Config. Global" + +msgid "Block Gui Settings" +msgstr "Bloquear Config. Gui" + +msgid "Block HBC Menu" +msgstr "Bloquear Menú HBC" + +msgid "Block Hard Drive Settings" +msgstr "Bloq. Config. Disco Duro" + +msgid "Block IOS Reload" +msgstr "Impedir recarga IOS" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "Bloq. Carga por Boton" + +msgid "Block Loader Settings" +msgstr "Bloq. Config. Cargador" + +msgid "Block Parental Settings" +msgstr "Bloq. Config. Parental" + +msgid "Block Priiloader Override" +msgstr "Bloq. Parche Priiloader" + +msgid "Block Reset Settings" +msgstr "Bloq. Resetear Config." + +msgid "Block SD Reload Button" +msgstr "Bloq. Botón Recarga SD" + +msgid "Block Sound Settings" +msgstr "Bloquear Config. Sonido" + +msgid "Block Theme Downloader" +msgstr "Bloq. Descarga Temas" + +msgid "Block Theme Menu" +msgstr "Bloquear Menú Temas" + +msgid "Block Title Launcher" +msgstr "Bloq. Lanzador Canales" + +msgid "Block Updates" +msgstr "Bloq. Actualizaciones" + +msgid "Boot Content" +msgstr "Iniciar contenido" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "¿Ejecutar?" + +msgid "Both" +msgstr "Ambos" + +msgid "Both Ports" +msgstr "Ambos Puertos" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "Cache de archivos BNR" + +msgid "Cache BNR Files Path" +msgstr "Ruta Cache archivos BNR " + +msgid "Cache Titles" +msgstr "Caché de Títulos" + +msgid "Can't be formatted" +msgstr "No se puede formatear" + +msgid "Can't create directory" +msgstr "No se creó la carpeta" + +#, c-format +msgid "Can't create file: %s" +msgstr "No se creó el archivo" + +#, c-format +msgid "Can't create path: %s" +msgstr "No se creó la ruta: %s" + +msgid "Can't delete:" +msgstr "No se eliminó:" + +msgid "Can't mount or unknown disc format." +msgstr "No se puede montar o disco en formato desconocido." + +#, c-format +msgid "Can't open file for write: %s" +msgstr "No se ha podido abrir el archivo para escribir: %S" + +#, c-format +msgid "Can't open file: %s" +msgstr "No se abrió el archivo: %s" + +#, c-format +msgid "Can't read file: %s" +msgstr "No se pudo leer el archivo: %s" + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Cannot write to destination." +msgstr "No se escribió en el destino." + +msgid "Categories" +msgstr "Categorías" + +msgid "Categories:" +msgstr "Categorías:" + +msgid "Change Play Path" +msgstr "Cambiar Ruta" + +msgid "Channel Launcher" +msgstr "Cargar Canales" + +msgid "Channels" +msgstr "Canales" + +msgid "Cheatfile is blank" +msgstr "El archivo de Trucos está vacio" + +msgid "Clear" +msgstr "Borrar" + +msgid "Click to Download Covers" +msgstr "Clic para descargar Carátulas" + +msgid "Click to change game ID" +msgstr "Clic para cambiar la ID del juego" + +msgid "Clock" +msgstr "Reloj" + +msgid "Clock Scale Factor" +msgstr "Escala reloj" + +msgid "Close" +msgstr "Salir" + +msgid "Code Download" +msgstr "Descargar Códigos" + +#, c-format +msgid "Coded by: %s" +msgstr "Programado por: %s" + +msgid "Coding:" +msgstr "Programación:" + +msgid "Connection to server timed out." +msgstr "Tiempo de conexión con el servidor agotado." + +msgid "Console" +msgstr "Consola" + +msgid "Console Default" +msgstr "Consola" + +msgid "Console Locked" +msgstr "Consola Bloqueada" + +msgid "Console must be unlocked for this option." +msgstr "Debes desbloquear la consola para esta opción." + +msgid "Console must be unlocked to be able to use this." +msgstr "Debes desbloquear la consola para poder usar esto." + +msgid "Console should be unlocked to modify it." +msgstr "Debes desbloquear la consola para modificarlo." + +msgid "Continue" +msgstr "Continuar" + +msgid "Continue to install game?" +msgstr "¿Continuar instalando juego?" + +msgid "Continue?" +msgstr "Continuar?" + +msgid "Controllevel" +msgstr "Control de Nivel" + +msgid "Copy" +msgstr "Copiar" + +msgid "Copying Canceled" +msgstr "Copia cancelada" + +msgid "Copying GC game..." +msgstr "Copiando juego GC..." + +msgid "Copying files..." +msgstr "Copiando archivos..." + +msgid "Correct Password" +msgstr "Contraseña Correcta" + +msgid "Could not connect to the server." +msgstr "No se pudo conectar al servidor." + +msgid "Could not create GCT file" +msgstr "¡No se pudo crear el archivo GCT!" + +#, c-format +msgid "Could not create path: %s" +msgstr "No se pudo crear la ruta: %s" + +msgid "Could not extract files for:" +msgstr "No se pudo extraer archivos para:" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "No se pudo encontrar información del juego en wiitdb.xml." + +msgid "Could not get free device space for game." +msgstr "No hay espacio disponible para el juego." + +msgid "Could not initialize DIP module!" +msgstr "¡No se pudo iniciar módulo DIP!" + +msgid "Could not initialize network!" +msgstr "¡No se pudo iniciar la Red!" + +msgid "Could not initialize network, time out!" +msgstr "No se pudo iniciar la Red, ¡tiempo de espera agotado!" + +msgid "Could not open Disc" +msgstr "¡No se pudo abrir el Disco!" + +msgid "Could not open the WiiTDB.xml file." +msgstr "No se pudo abrir el archivo WiiTDB.xml." + +msgid "Could not open wiitdb.xml." +msgstr "No se pudo abrir wiitdb.xml." + +msgid "Could not save." +msgstr "¡No se pudo guardar!" + +msgid "Could not write file." +msgstr "No se ha podido escribir el archivo" + +msgid "Could not write to:" +msgstr "No se pudo escribir en:" + +msgid "Cover Download" +msgstr "Descarga de Carátulas" + +msgid "Create" +msgstr "Crear/reemplazar" + +msgid "Credits" +msgstr "Créditos" + +msgid "Crop Overscan" +msgstr "Recortar overscan" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "Banners personalizados" + +msgid "Custom Paths" +msgstr "Rutas personalizadas" + +msgid "Customs" +msgstr "Personalizadas" + +msgid "Customs/Original" +msgstr "Personalizadas/originales" + +msgid "D Buttons" +msgstr "Botones del pad" + +msgid "DOL Path" +msgstr "Ruta del DOL" + +msgid "Debug" +msgstr "Depurador" + +msgid "Debug Wait" +msgstr "Depurador en espera" + +msgid "Debugger Paused Start" +msgstr "Iniciar Wiird pausado" + +msgid "Dec" +msgstr "Dic" + +msgid "Default" +msgstr "Predeterminado" + +msgid "Default Gamesettings" +msgstr "Restaurar configuración" + +msgid "Default Settings" +msgstr "Restaurar configuración" + +msgid "Delete" +msgstr "Borrar" + +msgid "Delete Cached Banner" +msgstr "Borrar banner en caché" + +msgid "Delete Cheat GCT" +msgstr "Borrar Trucos GCT" + +msgid "Delete Cheat TXT" +msgstr "Borrar Trucos TXT" + +msgid "Delete Cover Artwork" +msgstr "Borrar Carátulas" + +msgid "Delete Disc Artwork" +msgstr "Borrar Imagen de Disco" + +msgid "Delete category" +msgstr "Borrar categoría" + +msgid "Deleting directories..." +msgstr "Borrando directorios..." + +msgid "Deleting files..." +msgstr "Borrando archivos" + +msgid "Design:" +msgstr "Diseño:" + +msgid "Details" +msgstr "Detalles" + +msgid "Developed by" +msgstr "Desarrollado por" + +msgid "Developer:" +msgstr "Desarrollado:" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "Ubicación de Devolution" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "No se puede cargar el loader.bin de Devolution." + +msgid "Directory does not exist!" +msgstr "¡La carpeta no existe!" + +msgid "Disc 1" +msgstr "Disco 1" + +msgid "Disc 2" +msgstr "Disco 2" + +msgid "Disc Artwork Download" +msgstr "Imagenes de Discos" + +msgid "Disc Artwork Path" +msgstr "Ruta Imagenes Discos" + +msgid "Disc Default" +msgstr "Disco" + +msgid "Disc Insert Detected" +msgstr "Detectado Disco Insertado" + +msgid "Disc Read Delay" +msgstr "Delay lectura disco" + +msgid "Disc read error." +msgstr "Error de lectura del disco." + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "DM(L) v2.6+ necesita el disco 2 en formato original (sin compresión), ¿estás seguro que deseas instalarlo en formato comprimido?" + +msgid "Discarts" +msgstr "Discos" + +msgid "DiskFlip" +msgstr "GiraDiscos" + +msgid "Display" +msgstr "Mostrar" + +msgid "Display as a carousel" +msgstr "Mostrar en carrusel" + +msgid "Display as a channel grid" +msgstr "Mostrar en canales" + +msgid "Display as a grid" +msgstr "Mostrar en rejilla" + +msgid "Display as a list" +msgstr "Mostrar en lista" + +msgid "Display favorites only" +msgstr "Mostrar solo favoritos" + +msgid "Do you want to apply it now?" +msgstr "¿Quieres aplicarlo ahora?" + +msgid "Do you want to apply this theme?" +msgstr "¿Quieres aplicar este tema?" + +msgid "Do you want to change language?" +msgstr "¿Quieres cambiar el idioma?" + +msgid "Do you want to continue with next game?" +msgstr "¿Quieres continuar con el juego siguiente?" + +msgid "Do you want to copy now?" +msgstr "¿Quieres copiar ahora?" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "¿Quieres copiar el juego a la tarjeta SD o borrar un juego en la tarjeta SD?" + +msgid "Do you want to delete a game on SD?" +msgstr "¿Quieres borrar un juego en la tarjeta SD?" + +msgid "Do you want to discard changes?" +msgstr "¿quieres descartar los cambios?" + +msgid "Do you want to download this theme?" +msgstr "¿Quieres descargar este Tema?" + +msgid "Do you want to extract all the save games?" +msgstr "¿Quieres extraer las partidas?" + +msgid "Do you want to extract the save game?" +msgstr "¿Quieres extraer la partida?" + +msgid "Do you want to format:" +msgstr "Quieres formatear:" + +msgid "Do you want to install selected games?" +msgstr "¿Quieres instalar los juegos seleccionados?" + +msgid "Do you want to load the default theme?" +msgstr "¿Quieres cargar el tema por defecto?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "¿Quieres reiniciar la red?" + +msgid "Do you want to start the game now?" +msgstr "¿Quieres comenzar el juego ahora?" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "¿Quieres sincronizar el sector de información de espacio libre en todas las particiones FAT32?" + +msgid "Do you wish to update/download all language files?" +msgstr "¿Quieres actualizar/descargar todos los archivos de idiomas?" + +msgid "Dol Video Patch" +msgstr "Parche vídeo DOL" + +msgid "Download" +msgstr "Descargar" + +msgid "Download Now" +msgstr "Descargar ahora" + +msgid "Download finished" +msgstr "Descarga completada" + +msgid "Downloading 3D Covers" +msgstr "Descargando Carátulas 3D" + +msgid "Downloading Custom Banners" +msgstr "Descargando banners personalizados" + +msgid "Downloading Flat Covers" +msgstr "Descargando Carátulas 2D" + +msgid "Downloading Full HQ Covers" +msgstr "Descargando Carátulas HQ Completas" + +msgid "Downloading Full LQ Covers" +msgstr "Descargando Carátulas LQ Completas" + +msgid "Downloading custom Discarts" +msgstr "Descargando Img. Discos Artísticas" + +msgid "Downloading file..." +msgstr "Descargando archivo..." + +msgid "Downloading image:" +msgstr "Descargando imagen:" + +msgid "Downloading original Discarts" +msgstr "Descargando Img. Discos Originales" + +msgid "Downloading pagelist:" +msgstr "Descargando lista de páginas:" + +msgid "Dump NAND to EmuNand" +msgstr "Volcar Nand a Nand emu." + +msgid "During zoom" +msgstr "Durante el Zoom" + +msgid "Dutch" +msgstr "Holandés" + +msgid "ERROR" +msgstr "" + +msgid "ERROR:" +msgstr "" + +msgid "ERROR: Can't set up theme." +msgstr "ERROR: No se puede configurar el tema." + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "Canales en Nand Emulada" + +msgid "Emulated Nand" +msgstr "Nand Emulada" + +msgid "English" +msgstr "Inglés" + +msgid "Enter Path" +msgstr "Introduce ruta" + +msgid "Error" +msgstr "" + +msgid "Error !" +msgstr "¡Error!" + +#, c-format +msgid "Error creating path: %s" +msgstr "Error creando ruta: %s" + +msgid "Error opening downloaded file" +msgstr "Error abriendo archivo descargado" + +msgid "Error reading Disc" +msgstr "Error leyendo Disco" + +msgid "Error reading disc" +msgstr "Error leyendo disco" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "Error descargando archivo: %i" + +msgid "Error while downloding file" +msgstr "Error descargando archivo" + +msgid "Error while opening the zip." +msgstr "Error abriendo archivo zip." + +msgid "Error while transfering data." +msgstr "Error transfiriendo los datos." + +msgid "Error while updating USB Loader GX." +msgstr "Error actualizando USB Loader GX." + +msgid "Error writing the data." +msgstr "Error escribiendo los datos." + +msgid "Error:" +msgstr "" + +msgid "Error: Not enough space on SD." +msgstr "Error: No hay espacio suficiente en la tarjeta SD" + +msgid "Errors occured." +msgstr "A ocurrido un error." + +msgid "Everything" +msgstr "Todo" + +msgid "Exit" +msgstr "Salir" + +msgid "Exit to where?" +msgstr "¿Salir a dónde?" + +msgid "Export All Saves to EmuNand" +msgstr "Extraer partidas a Nand emu." + +msgid "Export Miis to EmuNand" +msgstr "Copiar Miis a Nand emu." + +msgid "Export SYSCONF to EmuNand" +msgstr "Copiar SysConf a Nand emu." + +msgid "Extract Miis to the Emu NAND?" +msgstr "¿Extraer los Miis a la EmuNand?" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "¿Extraer SYSCONF a la EmuNand?" + +msgid "Extract Save to EmuNand" +msgstr "Extraer partida a Nand emulada" + +msgid "Extracting file:" +msgstr "Extrayendo archivo:" + +msgid "Extracting files..." +msgstr "Extrayendo archivos..." + +msgid "Extracting files:" +msgstr "Extrayendo archivos:" + +msgid "Extracting nand files:" +msgstr "Extrayendo archivos Nand" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "Fallo" + +msgid "Failed copying file" +msgstr "Fallo copiando archivo" + +msgid "Failed formating" +msgstr "No se ha podido formatear" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "Fallo al extraer los archivos, Pueden no existir partidas guardadas" + +msgid "Failed to extract." +msgstr "No se ha podido extraer." + +msgid "Failed to initialize the USB storage device." +msgstr "Fallo al iniciar el dispositivo USB" + +msgid "Failed to open partition" +msgstr "No se ha podido abrir la partición" + +msgid "Failed to read ticket." +msgstr "Fallo al leer ticket" + +msgid "Failed to read tmd file." +msgstr "Fallo al leer archivo tmd" + +msgid "Failed to read wad header." +msgstr "Fallo al leer cabecera wad " + +msgid "Failed updating" +msgstr "No se ha podido actualizar" + +msgid "Favorite Level" +msgstr "Nivel Favorito" + +msgid "Features" +msgstr "Características" + +msgid "Features Settings" +msgstr "Configuración de las características" + +msgid "Feb" +msgstr "" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Archivo no encontrado." + +msgid "File read/write error." +msgstr "Error de lectura/escritura en archivo" + +msgid "Files extracted successfully." +msgstr "Archivos extraidos correctamente" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "El tamaño de archivo es %i Byte." + +msgid "Filesize is 0 Byte." +msgstr "El tamaño de archivo es 0 Byte." + +msgid "Flat Covers" +msgstr "Carátulas 2D" + +msgid "Flip-X" +msgstr "Animación Menú Disco" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "Escala textos" + +msgid "Force 16:9" +msgstr "Forzar 16:9" + +msgid "Force 4:3" +msgstr "Forzar 4:3" + +msgid "Force NTSC" +msgstr "Forzar NTSC" + +msgid "Force NTSC480p" +msgstr "Forzar NTSC480p" + +msgid "Force PAL480p" +msgstr "Forzar PAL480p" + +msgid "Force PAL50" +msgstr "Forzar PAL50" + +msgid "Force PAL60" +msgstr "Forzar PAL60" + +msgid "Force Titles from Disc" +msgstr "Forzar titulos del disco" + +msgid "Force Widescreen" +msgstr "Forzar 16:9" + +msgid "Format" +msgstr "Formateo" + +msgid "Formatting, please wait..." +msgstr "Formateando, por favor espera..." + +msgid "Found missing images." +msgstr "Se encontraron imágenes que faltan." + +msgid "Frame" +msgstr "Marco" + +msgid "Frame Projection Height" +msgstr "Proyección del marco Ancho" + +msgid "Frame Projection Width" +msgstr "Proyección del marco Alto" + +msgid "Frame Projection X-Offset" +msgstr "Proyección del marco X-Offset" + +msgid "Frame Projection Y-Offset" +msgstr "Proyección del marco Y-Offset" + +msgid "Frames" +msgstr "Marcos" + +msgid "Free Space" +msgstr "Espacio Libre" + +msgid "French" +msgstr "Francés" + +msgid "Full" +msgstr "Completa" + +msgid "Full Cover Path" +msgstr "Ruta Carátulas Comp." + +msgid "Full Covers" +msgstr "Carátulas comp." + +msgid "Full Menu" +msgstr "Completo" + +msgid "Full covers Download" +msgstr "Descargar carátulas comp." + +msgid "Full shutdown" +msgstr "Apagado completo" + +msgid "GAMEID_Gamename" +msgstr "IDdelJuego_NombreDelJuego" + +msgid "GC Banner Scale" +msgstr "Escala del Banner GC" + +msgid "GC Games" +msgstr "Juegos GC" + +msgid "GC Install 32K Aligned" +msgstr "Instalar GC alineado 32k" + +msgid "GC Install Compressed" +msgstr "Instalar GC comprimido" + +msgid "GCT Cheatcodes Path" +msgstr "Ruta de Trucos GCT" + +msgid "GCT File created" +msgstr "Archivo GCT creado" + +msgid "GUI Settings" +msgstr "Configuración de GUI" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "Borrar Juego de GameCube" + +msgid "Game Cube Install Menu" +msgstr "Menu de instalación GameCube" + +msgid "Game ID" +msgstr "ID del Juego" + +msgid "Game IOS" +msgstr "IOS del Juego" + +msgid "Game Language" +msgstr "Idioma" + +msgid "Game Load" +msgstr "Configuración del Juego" + +msgid "Game Lock" +msgstr "Bloqueo del Juego" + +msgid "Game Only" +msgstr "Solo el Juego" + +msgid "Game Region" +msgstr "Región" + +msgid "Game Size" +msgstr "Tamaño del Juego" + +msgid "Game Sound Mode" +msgstr "Modo sonido del Juego" + +msgid "Game Sound Volume" +msgstr "Volumen del Juego" + +msgid "Game Split Size" +msgstr "Separación WBFS" + +msgid "Game Window Mode" +msgstr "Juego en modo ventana" + +msgid "Game is already installed:" +msgstr "El juego ya estaba instalado:" + +msgid "Game's IOS" +msgstr "IOS del juego" + +msgid "Game/Install Partition" +msgstr "Partición de Juegos" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "Cantidad de mandos" + +msgid "GameCube Mode" +msgstr "Modo GameCube" + +msgid "GameCube Source" +msgstr "Origen GameCube" + +msgid "Gamename [GAMEID]" +msgstr "Nombrejuego [IDJUEGO]" + +msgid "Games" +msgstr "Juegos" + +msgid "Generating GXGameCategories.xml" +msgstr "Generando GXGameCategories.xml" + +msgid "Genre:" +msgstr "Género:" + +msgid "German" +msgstr "Alemán" + +msgid "Getting file list..." +msgstr "Obteniendo lista de archivos..." + +msgid "Getting game folder size..." +msgstr "Obteniendo tamaño de la carpeta" + +msgid "Global Settings" +msgstr "Configuración Global" + +msgid "Grid Scroll Speed" +msgstr "Velocidad Scroll" + +msgid "HOME Menu" +msgstr "Menú HOME" + +msgid "Hard Drive Settings" +msgstr "Configuración del Disco Duro" + +msgid "High Quality" +msgstr "Alta calidad" + +msgid "High/Low" +msgstr "Alta/baja" + +msgid "Homebrew Apps Path" +msgstr "Ruta Apps Homebrew" + +msgid "Homebrew Channel" +msgstr "Canal Homebrew" + +msgid "Homebrew Launcher" +msgstr "Ejecutar Homebrew" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "Horas" + +msgid "How do you want to update?" +msgstr "¿Cómo quieres actualizar?" + +msgid "How to Shutdown?" +msgstr "¿Cómo quieres apagar?" + +msgid "Import Categories" +msgstr "Importar Categorías" + +msgid "Import operation successfully completed." +msgstr "Importación completada con éxito." + +msgid "Importing categories" +msgstr "Importando categorías" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Archivo recibido %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Archivo recibido %0.2fMB" + +msgid "Individual" +msgstr "1 por juego" + +msgid "Initializing Network" +msgstr "Iniciando la Red" + +msgid "Insert Disk" +msgstr "Inserta el Disco" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "Inserta un disco de Wii o Game Cube" + +msgid "Install" +msgstr "Instalar" + +msgid "Install Canceled" +msgstr "Instalación cancelada" + +msgid "Install Directories" +msgstr "Instalar en carpeta" + +msgid "Install Error!" +msgstr "¡Error de Instalación!" + +msgid "Install Partitions" +msgstr "Instalar Particiones" + +msgid "Install a game" +msgstr "Instalar un juego" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "Instalación terminada" + +msgid "Installing Game Cube Game..." +msgstr "Instalando un juego de GameCube" + +msgid "Installing content" +msgstr "Instalando Contenido" + +msgid "Installing game:" +msgstr "Instalando juego:" + +msgid "Installing title..." +msgstr "Instalando Título" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "Número de IOS no valido. Debe ser -1 por defecto o 200 a 255" + +msgid "Invalid wad file." +msgstr "Archivo WAD no valido" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Parece que tienes alguna información que puede ser útil para nosotros. Por favor envía esta información al equipo desarrollador." + +msgid "Italian" +msgstr "Italiano" + +msgid "Jan" +msgstr "Ene" + +msgid "Japanese" +msgstr "Japonés" + +msgid "Japanese Patch" +msgstr "Parche japonés" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "Jul" + +msgid "June" +msgstr "Jun" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Teclado" + +msgid "Korean" +msgstr "Coreano" + +msgid "LED Activity" +msgstr "Iluminar lector" + +msgid "Language Files" +msgstr "Archivos de idioma" + +msgid "Language change:" +msgstr "Cambio de Idioma:" + +msgid "Languagefiles Path" +msgstr "Ruta Archivos Idioma" + +msgid "Languagepath changed." +msgstr "Ruta de idioma cambiada." + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "¡Cargar juegos de Wii de una nand emulada sólo funciona con un cIOS d2x!" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "La carga de canales de Nand emuada solo funciona con cIOS d2x, cambia el IOS del juego a d2x primero" + +msgid "Left" +msgstr "Izquierda" + +msgid "Like SysMenu" +msgstr "Como Menú Sist." + +msgid "List on Gamelaunch" +msgstr "Lista en la carga del juego" + +msgid "Load" +msgstr "Cargar" + +msgid "Load From SD/USB" +msgstr "Cargar desde SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "¿Cargar el archivo desde: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "¿Cargar este DOL como DOL Alternativo?" + +msgid "Loader Settings" +msgstr "Configuración del Cargador" + +msgid "Loader's IOS" +msgstr "IOS del cargador" + +msgid "Loading standard language." +msgstr "Cargando idioma estándar." + +msgid "Loading standard music." +msgstr "Cargando música estándar." + +msgid "Lock Console" +msgstr "Bloquear consola" + +msgid "Lock USB Loader GX" +msgstr "Bloquear USB Loader GX" + +msgid "Locked" +msgstr "Bloqueada" + +msgid "Log to file" +msgstr "Guardar registro" + +msgid "Loop Directory" +msgstr "Carpeta de bucle" + +msgid "Loop Music" +msgstr "Bucle musical" + +msgid "Loop Sound" +msgstr "Bucle de sonido" + +msgid "Low Quality" +msgstr "Baja calidad" + +msgid "Low/High" +msgstr "Baja/alta" + +msgid "MIOS (Default & Customs)" +msgstr "MIOS (Original y modificados)" + +msgid "Main DOL" +msgstr "DOL Principal" + +msgid "Main GameCube Games Path" +msgstr "Ruta Principal de juegos GameCube" + +msgid "Main GameCube Path" +msgstr "Ruta principal GameCube" + +msgid "Main Path" +msgstr "Ruta principal" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "" + +msgid "Mark new games" +msgstr "Marcar juegos nuevos" + +msgid "May" +msgstr "" + +msgid "Memory Card Blocks Size" +msgstr "Bloques Memory Card" + +msgid "Memory Card Emulation" +msgstr "Emular Memory Card" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "Las Memory Card de 2043 bloques traen problemas al usarlas con Nintendont." + +msgid "Messageboard Update" +msgstr "Actualizar Tablón Wii" + +msgid "Motion+ Video" +msgstr "Vídeo Motion+" + +msgid "Mount DVD drive" +msgstr "Montar unidad DVD" + +msgid "Mount USB at launch" +msgstr "Montar USB al inicio" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "Múltiples Particiones" + +msgid "Music Loop Mode" +msgstr "Modo Bucle Musical" + +msgid "Music Volume" +msgstr "Volumen de la Música" + +msgid "NMM Mode" +msgstr "Modo NMM" + +msgid "Nand Chan. Emulation" +msgstr "Emular canales Nand" + +msgid "Nand Channels" +msgstr "Canales en Nand" + +msgid "Nand Emu Channel Path" +msgstr "Ruta canales Nand emulada" + +msgid "Nand Emu Path" +msgstr "Ruta Nand emulada" + +msgid "Nand Emulation" +msgstr "Emulación Nand" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "¡La emulación Nand solo está disponible en cIOS D2X!" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "¡La emulación Nand solo funciona en particiones FAT/FAT32!" + +msgid "Nand Saves Emulation" +msgstr "Emular partidas Nand" + +msgid "Native Controller" +msgstr "Sólo mandos nativos" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Ninguno" + +msgid "Network is not initiated." +msgstr "No se inició la red." + +msgid "Next" +msgstr "Siguiente" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "Ruta de Nintendont" + +msgid "No" +msgstr "" + +msgid "No Cheatfile found" +msgstr "No se encontró el archivo de Trucos" + +msgid "No DOL file found on disc." +msgstr "No se encontró el archivo DOL en el Disco" + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "Sin Separación" + +msgid "No URL or Path specified." +msgstr "URL o ruta no especificada." + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "Partición WBFS o FAT/NTFS/EXT no encontrada" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "No se encontró el archivo Wiinnertag.xml. ¿Quieres crear un archivo de ejemplo?" + +msgid "No change" +msgstr "Sin cambios" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "No hay trucos seleccionados, ¿debe ser borrado el archivo GCT?" + +msgid "No data could be read." +msgstr "No se dispone de datos para leer." + +msgid "No disc inserted." +msgstr "No hay disco insertado." + +msgid "No favorites selected." +msgstr "Ningún favorito seleccionado." + +msgid "No file missing!" +msgstr "¡No faltan archivos!" + +msgid "No games found on the disc" +msgstr "No se han encontrado juegos en el disco" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "No hay archivos de idioma en tus dispositivos, ¿quieres descargar nuevos archivos de idioma?" + +msgid "No new updates." +msgstr "No hay nuevas actualizaciones." + +msgid "No themes found on the site." +msgstr "No hay Temas en este sitio." + +msgid "No themes found." +msgstr "Ningún tema encontrado." + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "Sólo NoSSL" + +msgid "None" +msgstr "Ninguno" + +msgid "Normal" +msgstr "" + +msgid "Not Initialized" +msgstr "No Iniciado" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "No es un disco Wii o GameCube" + +msgid "Not a valid URL" +msgstr "URL no válida" + +msgid "Not a valid URL path" +msgstr "Ruta URL no válida" + +msgid "Not a valid domain" +msgstr "Dominio no válido" + +msgid "Not enough free memory." +msgstr "¡No hay suficiente memoria libre!" + +msgid "Not enough free space on device." +msgstr "No hay suficiente espacio en el dispositivo" + +msgid "Not enough free space!" +msgstr "¡No hay suficiente espacio libre!" + +msgid "Not enough memory for FST." +msgstr "No hay memoria suficiente la FST" + +msgid "Not enough memory." +msgstr "No hay suficiente memoria." + +msgid "Not required" +msgstr "No requerido" + +msgid "Not supported format!" +msgstr "Formato no soportado." + +msgid "Nothing selected to delete." +msgstr "Nada seleccionado para borrar" + +msgid "Nothing selected to install." +msgstr "Nada seleccionado para instalar" + +msgid "Nov" +msgstr "" + +msgid "OFF" +msgstr "Desactivado" + +msgid "OK" +msgstr "Aceptar" + +msgid "ON" +msgstr "Activado" + +msgid "ON (Multi)" +msgstr "1 global" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "" + +msgid "Official Site:" +msgstr "Página Oficial:" + +msgid "Offset" +msgstr "Desfasaje" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "Solo Partición de Juegos" + +msgid "Only for Install" +msgstr "Sólo al instalar" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Originales/Artísticas" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Control Parental" + +msgid "Partial" +msgstr "Parcial" + +msgid "Partition" +msgstr "Partición" + +msgid "Password" +msgstr "Contraseña" + +msgid "Password Changed" +msgstr "Contraseña cambiada" + +msgid "Password has been changed" +msgstr "La contraseña ha sido cambiada" + +msgid "Patch Country Strings" +msgstr "Parchear País" + +msgid "Path Changed" +msgstr "Ruta cambiada" + +msgid "Permission denied." +msgstr "Permiso denegado." + +msgid "Pick from a list" +msgstr "Elegir de una lista" + +msgid "Pixels" +msgstr "Píxeles" + +msgid "Play Count" +msgstr "Partidas" + +msgid "Play Next" +msgstr "Oír Siguiente" + +msgid "Play Once" +msgstr "Oir una vez" + +msgid "Play Previous" +msgstr "Oír Anterior" + +msgid "Playing Music:" +msgstr "Reproducción Musical:" + +msgid "Please wait" +msgstr "Por favor, espera" + +msgid "Please wait..." +msgstr "Por favor, espera..." + +msgid "Power off the Wii" +msgstr "Apagar la Wii" + +msgid "Prev" +msgstr "Ant." + +msgid "Private Server" +msgstr "Servidor privado" + +msgid "Process finished." +msgstr "Proceso terminado" + +msgid "Progressive Patch" +msgstr "Forzar progresivo" + +msgid "Prompts Buttons" +msgstr "Botones" + +msgid "Published by" +msgstr "Publicado por" + +msgid "Quick Boot" +msgstr "Inicio Rápido" + +msgid "Random Directory Music" +msgstr "Aleatorio de la carpeta musical" + +msgid "Real Nand" +msgstr "Nand Real" + +msgid "Receiving file from:" +msgstr "Recibir archivo desde:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "Parche región" + +msgid "Released" +msgstr "Comercializado el" + +msgid "Reload SD" +msgstr "Recargar SD" + +msgid "Reloading game list now, please wait..." +msgstr "Recargando lista de juegos, espere por favor..." + +msgid "Remember Unlock" +msgstr "Recordar bloqueo" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "Quitar actualización" + +msgid "Rename Game Title" +msgstr "Renombrar juego" + +msgid "Rename category" +msgstr "Renombrar categoría" + +msgid "Reset" +msgstr "Reiniciar" + +msgid "Reset BG Music" +msgstr "Reiniciar Música de Fondo" + +msgid "Reset Playcounter" +msgstr "Reiniciar Partidas" + +msgid "Reset to default BGM?" +msgstr "¿Resetear a música de fondo por defecto?" + +msgid "Restarting..." +msgstr "Reiniciando..." + +msgid "Return" +msgstr "Volver" + +msgid "Return To" +msgstr "Volver a" + +msgid "Return to Wii Menu" +msgstr "Volver a Menú Wii" + +msgid "Right" +msgstr "Derecha" + +msgid "Rotating Disc" +msgstr "Disco girando" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Vibración" + +msgid "SChinese" +msgstr "Chino S." + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "No se puede acceder a la tarjeta SD" + +msgid "SD GameCube Games Path" +msgstr "Ruta de juegos GameCUbe en SD" + +msgid "SD GameCube Path" +msgstr "Ruta de GameCube en SD" + +msgid "SD Path" +msgstr "Ruta en SD" + +msgid "SFX Volume" +msgstr "Volumen de los Efectos" + +msgid "Save" +msgstr "Guardar" + +msgid "Save Failed. No device inserted?" +msgstr "Fallo en el guardado. ¿No hay introducido ningún dispositivo?" + +msgid "Save Game List to" +msgstr "Guardar Lista de Juegos en" + +msgid "Save List" +msgstr "Guardar Lista" + +msgid "Saved" +msgstr "Guardado" + +msgid "Savegame might not exist for this game." +msgstr "Puede no existir partida guardada para este juego" + +msgid "Screensaver" +msgstr "Salvapantallas" + +msgid "Screenshot" +msgstr "Captura de pantalla" + +msgid "Select" +msgstr "Seleccionar" + +msgid "Select DOL Offset" +msgstr "Seleccionar DOL" + +msgid "Select a DOL" +msgstr "Seleccionar DOL" + +msgid "Select a DOL from Game" +msgstr "Seleccionar DOL del Juego" + +msgid "Select game categories" +msgstr "Seleccionar categorías de juegos" + +msgid "Select loader mode" +msgstr "Seleccionar cargador" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "Selecciona fuente de títulos" + +msgid "Sept" +msgstr "" + +msgid "Set Search-Filter" +msgstr "Usar filtro de búsqueda" + +msgid "Settings" +msgstr "Configuración" + +msgid "Settings File" +msgstr "Configuración" + +msgid "Show Categories" +msgstr "Mostrar Categorías" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "Mostrar Espacio Libre" + +msgid "Show Play Count" +msgstr "Mostrar núm. jugados" + +msgid "Show SD" +msgstr "Mostrar SD" + +msgid "Shutdown System" +msgstr "Apagar consola" + +msgid "Shutdown Wii" +msgstr "Apagar la Wii" + +msgid "Skip Errors" +msgstr "Saltar errores" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "Parche vídeo Sneek" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Ordenar alfabéticamente" + +msgid "Sort by number of players" +msgstr "Ordenar por número de jugadores" + +msgid "Sort by rank" +msgstr "Ordenar por clasificación" + +msgid "Sort order by most played" +msgstr "Ordenar por más jugados" + +msgid "Sound" +msgstr "Sonido" + +msgid "Sound Settings" +msgstr "Configuración de Sonido" + +msgid "Sound+BGM" +msgstr "Sonido+Música Fondo" + +msgid "Sound+Quiet" +msgstr "Sonido+Silencio" + +msgid "Spanish" +msgstr "Español" + +msgid "Special thanks to:" +msgstr "Agradecimientos especiales a:" + +msgid "Split each 2GB" +msgstr "Separar cada 2GB" + +msgid "Split each 4GB" +msgstr "Separar cada 4GB" + +msgid "Standby" +msgstr "En espera" + +msgid "Start" +msgstr "Comenzar" + +msgid "Success" +msgstr "Conseguido" + +msgid "Success." +msgstr "Conseguido" + +msgid "Success:" +msgstr "Conseguido:" + +msgid "Successfully Saved" +msgstr "Guardado correctamente" + +msgid "Successfully Updated" +msgstr "Actualización correcta" + +msgid "Successfully copied" +msgstr "Copia correcta" + +msgid "Successfully deleted:" +msgstr "Borrado correctamente:" + +msgid "Successfully extracted theme." +msgstr "Tema extraido correctamente." + +msgid "Successfully installed:" +msgstr "Instalado correctamente:" + +msgid "Successfully updated." +msgstr "actualización correcta" + +msgid "Switching to channel list mode." +msgstr "Cambiando a modo de lista de canales" + +msgid "Sync FAT32 FS Info" +msgstr "Sinc. Esp. Libre FAT32" + +msgid "Synchronizing..." +msgstr "Sincronizando..." + +msgid "System Default" +msgstr "Consola" + +msgid "TChinese" +msgstr "Chino Tradicional" + +msgid "TXT Cheatcodes Path" +msgstr "Ruta de Trucos TXT" + +msgid "The .them file was not found in the zip." +msgstr "El archivo .them no se encontró en el zip." + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "El forzado 16:9 requiere DIOS MIOS 2.1 o superior." + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Los miis serán extraidos a la ruta de tu EmuNand y Canales de EmuNand. Atención: todos los archivos existentes serán sobreescritos." + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "El ajuste No Disc+ requiere DIOS MIOS 2.2 update2." + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "El archivo SYSCONF será extraido a la ruta de tu EmuNand y Canales de EmuNand. Atención: todos los archivos existentes serán sobreescritos" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "¡La aplicación puede fallar si hay algún acceso de lectura/escritura en la tarjeta SD!" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "La carpeta especificada no existe. ¿Quieres crearla?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "Los archivos sera extraidos a tu ruta de EmuNand y partidas de EmuNand. Atención: todos los archivos existentes serán seleccionados." + +msgid "The game is on SD Card." +msgstr "El juego está en la SD." + +msgid "The game is on USB." +msgstr "El juego esta en el USB." + +msgid "The save game will be extracted to your emu nand path." +msgstr "La partida guardada se extraerá en la ruta de tu Nand emuada." + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "Las partidas guardadas serán extraidas en la ruta de tus partidas de EmuNand y Canales de EmuNand. Atención: todos los archivos sera sobreescritos." + +msgid "The wad file was installed" +msgstr "Se instaló el archivo wad" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "La instalación del wad falló con error %i" + +msgid "Theme Downloader" +msgstr "Descarga de Temas" + +msgid "Theme Menu" +msgstr "Menú de Temas" + +msgid "Theme Path" +msgstr "Ruta de Temas" + +msgid "Theme Title:" +msgstr "Título del Tema:" + +msgid "Themes by www.spiffy360.com" +msgstr "Temas por www.spiffy360.com" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "Este IOS es el ios de BootMii. Si estás seguro de que no está BootMii y que tienes otra cosa instalada ahí, ignora esta advertencia." + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "No se encontró este IOS en la lista de títulos. Si estás seguro de que lo tienes instalado, ignora esta advertencia." + +msgid "This Nintendont version does not support games on USB." +msgstr "Esta versión de Nintendont no soporta juegos en USB." + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "Esta versión de Nintendont no es soportada. El autoarranque será desactivado." + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "Este juego posee varios discos. Por favor, elige el que deseas cargar." + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "¡Esta ruta debe ser en la SD!" + +msgid "Time left:" +msgstr "Quedan:" + +msgid "Timer Fix" +msgstr "Corrección del timer" + +msgid "Title Launcher" +msgstr "Lanzador de Canales" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "Titulos de GameTDB" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "Para cargar juegos de GameCube desde la lectora debes configurar el modo GameCube a MIOS." + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "Para cargar juegos de GameCube con %s debes ponerlos en un USB con formato FAT32." + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "Para cargar juegos de GameCube con %s debes configurar tu Ruta GameCube principal en un USB con formato FAT32." + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "Para cargar juegos de GameCube con %s debes usar una partición con 512 bytes por sector." + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "Para cargar juegos de GameCube con %s debes usar una partición con 32KB o menos por sector." + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "Para cargar juegos de GameCube con Devolution debes tener el loader.bin en la Ruta de Devolution." + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "Para cargar juegos de GameCube con Nintendont debes tener el boot.dol en la Ruta de Nintendont." + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "Para usar HID con %s necesitas el archivo %s." + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "Para usar ocarina con %s necesitas el archivo %s." + +msgid "Tooltip Delay" +msgstr "Retraso de ayuda rápida" + +msgid "Tooltips" +msgstr "Descripción" + +msgid "Transfer failed" +msgstr "Transferencia fallida" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "Dispositivo USB no iniciado." + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX está protegido" + +msgid "USB Port" +msgstr "Puerto USB" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "El cambio de Puerto USB sólo funciona con el cIOS de Hermes." + +msgid "USB-HID Controller" +msgstr "Mando USB-HID" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "No se puede verificar el archivo boot.dol de Nintendont, ¿desea continuar igual?" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "No se puede escribir la configuración de Nintendont, ¿desea continuar igual?" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "Se necesita la versión r1218 para Nintendont Alpha 0.1. Por favor, actualiza el boot.dol de Nintendont." + +msgid "Uninstall" +msgstr "Desinstalar" + +msgid "Uninstall Game" +msgstr "Desinstalar Juego" + +msgid "Uninstall Menu" +msgstr "Menú de Desinstalación" + +msgid "Uninstall all" +msgstr "Desinstalar todo" + +msgid "Unknown" +msgstr "Desconocido" + +msgid "Unlock USB Loader GX" +msgstr "Desbloquear USB Loader GX" + +msgid "Unlocked" +msgstr "Desbloqueada" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "Formato no soportado, intenta extraer manualmente TempTheme.zip." + +msgid "Update" +msgstr "Actualizar" + +msgid "Update All" +msgstr "Actualizar Todo" + +msgid "Update DOL" +msgstr "Actualizar DOL" + +msgid "Update Files" +msgstr "Actual. archivos" + +msgid "Update Path" +msgstr "Ruta Actualización" + +msgid "Update all Language Files" +msgstr "Actualizar todos los archivos de Idiomas" + +msgid "Update failed" +msgstr "Error en la Actualización" + +msgid "Update successfull" +msgstr "Actualización con éxito" + +msgid "Updating Language Files:" +msgstr "Actualizando archivos de Idiomas:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Enviado archivo ZIP instalado en la carpeta homebrew." + +msgid "Use System Font" +msgstr "Tipografía Wii" + +msgid "Use global" +msgstr "Usar global" + +msgid "VBI (Default)" +msgstr "VBI (Predeterminado)" + +msgid "VIDTV Patch" +msgstr "Parche VIDTV" + +msgid "Version:" +msgstr "Versión:" + +#, c-format +msgid "Version: %s" +msgstr "Versión: %s" + +msgid "Video Deflicker" +msgstr "Deflicker" + +msgid "Video Mode" +msgstr "Modo vídeo " + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "Vel. Puntero Virtual" + +msgid "WDM Files Path" +msgstr "Rutas Archivos WDM" + +msgid "WIP Patches Path" +msgstr "Ruta Parches WIP" + +msgid "Waiting..." +msgstr "Esperando..." + +msgid "Warning" +msgstr "Advertencia" + +msgid "Warning:" +msgstr "Advertencia:" + +msgid "What do you want to do?" +msgstr "¿Que quieres hacer?" + +msgid "What do you want to update?" +msgstr "¿Qué quieres actualizar?" + +msgid "What should be deleted for this game title:" +msgstr "Qué se debería borrar para este juego:" + +msgid "What to extract from NAND?" +msgstr "¿Que Extraer de la Nand?" + +msgid "Where should the game be installed to?" +msgstr "¿Donde debe ser instalado el juego?" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "Características WiFi" + +msgid "Widescreen Factor" +msgstr "Escala 16:9" + +msgid "Widescreen Fix" +msgstr "Ajuste 16:9" + +msgid "Wii Games" +msgstr "Juegos Wii" + +msgid "Wii Menu" +msgstr "Menú de Wii" + +msgid "Wii Settings" +msgstr "Opciones de Wii" + +msgid "WiiTDB.xml" +msgstr "WiiTDB" + +msgid "WiiTDB.xml is up to date." +msgstr "WiiTDB está actualizado." + +msgid "WiiU Widescreen" +msgstr "16:9 en Wii U" + +msgid "Wiilight" +msgstr "Iluminar lector" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "Ruta Wiinnertag" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "Wiinnertag requiere habilitar la conexión automática a la red al iniciar la aplicación. ¿Quieres habilitarla ahora?" + +msgid "Wiird Debugger" +msgstr "Depurador Wiird" + +#, c-format +msgid "Write error on file: %s" +msgstr "Error de escritura en archivo" + +msgid "Writing GXGameCategories.xml" +msgstr "Escribiendo GXGameCategories.xml" + +msgid "Wrong Password" +msgstr "Contraseña incorrecta" + +msgid "Yes" +msgstr "Sí" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "Estás intentando seleccionar una partición FAT32/NTFS/EXT con cIOS 249 Rev < 18. Esto no es soportado. Continúa bajo tu propio riesgo." + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "Puedes seleccionar o formatear una particón o usar el modo de carga de canales" + +msgid "You cannot delete this category." +msgstr "No puedes borrar esta categoría." + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "Necesitas instalar DIOS MIOS Lite 1.2 o superior." + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "Debes instalar otro cargador GameCube o seleccionar uno distinto en la configuración Modo GameCube para cargar juegos desde USB o SD." + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "Duración de Zoom" + +msgid "and translators for language files updates" +msgstr "y traductores por los archivos de idiomas" + +msgid "available" +msgstr "disponible" + +msgid "does not exist!" +msgstr "no existe" + +msgid "does not exist! Loading game without cheats." +msgstr "no existe. Ejecutando el juego sin trucos." + +msgid "files left" +msgstr "archivos pendientes" + +msgid "for FAT/NTFS support" +msgstr "por el soporte FAT/NTFS" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "Para GameTBD y almacenar caratulas / imagenes de disco" + +msgid "for Ocarina" +msgstr "por Ocarina" + +msgid "for diverse patches" +msgstr "por diversos parches" + +msgid "for his awesome tool LibWiiGui" +msgstr "por su increible herramienta LibWiiGui" + +msgid "for hosting the themes" +msgstr "por alojar los Temas" + +msgid "for the USB Loader source" +msgstr "por el código de USB Loader" + +msgid "for their work on the wiki page" +msgstr "por su trabajo en la web wiki" + +msgid "formatted!" +msgstr "¡formateado!" + +msgid "free" +msgstr "libres" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "sin contraseña" + +msgid "of" +msgstr "de" + +msgid "seconds left" +msgstr "segundos restantes" + +#~ msgid "Do you want to update this file?" +#~ msgstr "¿Quieres actualizar este archivo?" + +#~ msgid "Install WAD to EmuNand" +#~ msgstr "Instalar WAD en Nand Emu." + +#~ msgid "Update Nintendont" +#~ msgstr "Actualizar Nintendont" + +#~ msgid "WAD Installation" +#~ msgstr "Instalacion WAD" + +#~ msgid "GameTDB Path" +#~ msgstr "Ruta GameDTB" + +#~ msgid "Where do you want MCEmu to be located?" +#~ msgstr "¿Dónde deseas guardar la MCEmu?" + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on a primary partition." +#~ msgstr "Para cargar juegos de GameCube con %s debes configurar tu Ruta GameCube principal en una partición primaria." + +#~ msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first partition of the Hard Drive." +#~ msgstr "Para cargar juegos de GameCube con %s debes configurar tu Ruta GameCube principal en la primer partición del USB." + +#~ msgid "Anti" +#~ msgstr "Anti" + +#~ msgid "Error 002 fix" +#~ msgstr "Parchear Error 002" + +#~ msgid "Main tester:" +#~ msgstr "Probador principal:" + +#~ msgid "USB Device not found." +#~ msgstr "Dispositivo USB no encontrado" + +#~ msgid "Boot/Standard" +#~ msgstr "Inicio/Estándar" + +#~ msgid "DML Debug" +#~ msgstr "Depurador DML" + +#~ msgid "DML LED Activity" +#~ msgstr "LED actividad DML" + +#~ msgid "DML NMM Mode" +#~ msgstr "Modo NMM DML" + +#~ msgid "DML PAD Hook" +#~ msgstr "PAD Hook DML" + +#~ msgid "DML No Disc" +#~ msgstr "Sin disco DML" + +#~ msgid "Custom Discarts" +#~ msgstr "Img. Discos Artísticas" + +#~ msgid "Full HQ Covers" +#~ msgstr "Carátulas HQ Comp." + +#~ msgid "Full LQ Covers" +#~ msgstr "Carátulas LQ Comp." + +#~ msgid "Original Discarts" +#~ msgstr "Img. Discos Originales" + +#~ msgid "GC Force Interlace" +#~ msgstr "Forzar entrelazado GC" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "Renombrar juego en WBFS" + +#~ msgid "Do you want to discart changes?" +#~ msgstr "¿quieres descartar los cambios?" + +#~ msgid "Successfully Updated thanks to www.techjawa.com" +#~ msgstr "Actualización correcta gracias a www.techjawa.com" + +#~ msgid "Beginning" +#~ msgstr "Basico" + +#~ msgid "Content" +#~ msgstr "Contenido" + +#~ msgid "Loader Mode" +#~ msgstr "Modo de Carga" + +#~ msgid "Search Mode" +#~ msgstr "Modo de Busqueda" + +#~ msgid "for hosting the update files" +#~ msgstr "por alojar las actualizaciones" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "¡Inserta un Disco Wii!" + +#~ msgid "No cheats were selected" +#~ msgstr "No se seleccionaron trucos" + +#~ msgid "Not a Wii Disc" +#~ msgstr "No es un Disco Wii" + +#~ msgid "The files will be extracted to your emu nand path. Attention: All existing files will be overwritten." +#~ msgstr "Los archivos se extraeran en la ruta de tu Nand emuada. ATENCION: los archivos existentes seran sobreescritos" + +#~ msgid "The save games will be extracted to your emu nand path. Attention: All existing saves will be overwritten." +#~ msgstr "Las partidas guardadas se extraeran en la ruta de tu Nand emuada. ATENCION: las partidas existentes seran sobreescritas" + +#~ msgid "Extracting Nand files:" +#~ msgstr "Extrayendo archivos de Nand" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> Borrando tickets..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> Borrando tickets... ¡ERROR! " + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> Borrando tickets... ¡Correcto! " + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> Borrando título... ¡ERROR! " + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> Borrando título... ¡Correcto!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> Borrando contenidos del título..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> Borrando contenidos del título... ¡ERROR! " + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> Borrando contenidos del título... ¡Correcto!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> Borrando título..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> Finalizando instalación..." + +#~ msgid ">> Installing content #" +#~ msgstr ">> Instalando contenido #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> Instalando ticket..." + +#~ msgid ">> Installing title..." +#~ msgstr ">> Instalando título..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> Leyendo datos del WAD..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> Leyendo datos del WAD... ¡ERROR!" + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> Leyendo datos del WAD... ¡Correcto!" + +#~ msgid "Done!" +#~ msgstr "¡Listo!" + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "Finalizando instalación... ¡Correcto!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "Instalando contenido... ¡Correcto!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "Instalando ticket... ¡Correcto!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "Instalando título... ¡Correcto!" + +#~ msgid "Installing wad" +#~ msgstr "Instalando WAD" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "Leyendo datos del WAD... ¡Correcto!" + +#~ msgid "Uninstalling wad" +#~ msgstr "Desinstalando WAD" + +#~ msgid "The game installation is disabled under this IOS because of instability in usb write." +#~ msgstr "La instalación de juegos está desabilitada bajo este IOS porque la escritura USB es inestable." + +#~ msgid "You are currently using IOS" +#~ msgstr "Estás usando el IOS" + +#~ msgid "New Disc Detected" +#~ msgstr "Nuevo Disco Detectado" + +#~ msgid "USB Device not found" +#~ msgstr "USB no encontrado" + +#~ msgid "You need to select or format a partition" +#~ msgstr "Necesitas seleccionar o formatear una partición" + +#~ msgid "Language File" +#~ msgstr "Idiomas" + +#~ msgid "Are you sure you want to import game categories from WiiTDB?" +#~ msgstr "¿Estás seguro de importar las categorías desde WiiTDB?" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Títulos WiiTDB" + +#~ msgid "WiiTDB Files" +#~ msgstr "Archivos WiiTDB" + +#~ msgid "WiiTDB Path" +#~ msgstr "Ruta WiiTDB" + +#~ msgid "WiiTDB is up to date." +#~ msgstr "WiiTDB está actualizado." + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "por WiiTDB y alojar carátulas e imágenes" diff --git a/Languages/swedish.lang b/Languages/swedish.lang new file mode 100644 index 0000000..f91ada9 --- /dev/null +++ b/Languages/swedish.lang @@ -0,0 +1,2934 @@ +# USB Loader GX language source file. +# swedish.lang - r898 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:05+0200\n" +"PO-Revision-Date: 2010-01-19 17:39+0200\n" +"Last-Translator: Katsurou\n" +"Language-Team: Katsurou, pirateX\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr "Kunde inte laddas ner." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr "har sparats. Texten har inte blivit varifierad. Några av koderna kanske inte fungerar riktigt med varandra. Om du upplever problem, öppna texten i en textredigerare för mer information." + +msgid " is not on the server." +msgstr "finns inte på servern." + +#, c-format +msgid "%i files not found on the server!" +msgstr "" + +#, c-format +msgid "%i missing files" +msgstr "" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Alla)" + +msgid "1 (Child 7+)" +msgstr "1 (Barn 7+)" + +msgid "1 hour" +msgstr "1 timme" + +msgid "10 min" +msgstr "" + +msgid "2 (Teen 12+)" +msgstr "2 (Tonåringar 12+)" + +msgid "20 min" +msgstr "" + +msgid "2D Cover Path" +msgstr "2D Omslagsmapp" + +msgid "3 (Mature 16+)" +msgstr "3 (Ungdomar 16+)" + +msgid "3 min" +msgstr "" + +msgid "30 min" +msgstr "" + +msgid "3D Cover Path" +msgstr "3D Omslagsmapp" + +msgid "3D Covers" +msgstr "3D-Omslag" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Endast Vuxna 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "" + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "" + +msgid "All Partitions" +msgstr "" + +msgid "All files extracted." +msgstr "" + +msgid "All images downloaded successfully." +msgstr "" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "Alla funktioner i USB Loader GX är upplåsta." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Alternativ DOL" + +msgid "An example file was created here:" +msgstr "" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "Programspråk" + +msgid "Apply" +msgstr "" + +msgid "Apr" +msgstr "Apr" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "" + +msgid "Are you sure?" +msgstr "Är du säker?" + +msgid "Aspect Ratio" +msgstr "" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "" + +msgid "Author(s):" +msgstr "" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "Autoinitiera Nätverk" + +msgid "BCA Codes Path" +msgstr "BCA kodssökväg" + +msgid "Back" +msgstr "Tillbaka" + +msgid "Back to HBC or Wii Menu" +msgstr "Tillbaka till HBC eller Wii-Menyn" + +msgid "Backgroundmusic" +msgstr "Bakgrundsmusik" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "Stort tack till:" + +msgid "Block Categories Menu" +msgstr "" + +msgid "Block Categories Modify" +msgstr "" + +msgid "Block Cover Downloads" +msgstr "" + +msgid "Block Custom Paths" +msgstr "" + +msgid "Block Feature Settings" +msgstr "" + +msgid "Block Game Install" +msgstr "" + +msgid "Block Game Settings" +msgstr "" + +msgid "Block GameID Change" +msgstr "" + +msgid "Block Global Settings" +msgstr "" + +msgid "Block Gui Settings" +msgstr "" + +msgid "Block HBC Menu" +msgstr "" + +msgid "Block Hard Drive Settings" +msgstr "" + +msgid "Block IOS Reload" +msgstr "Blockera IOS omladdning" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "" + +msgid "Block Parental Settings" +msgstr "" + +msgid "Block Priiloader Override" +msgstr "" + +msgid "Block Reset Settings" +msgstr "" + +msgid "Block SD Reload Button" +msgstr "" + +msgid "Block Sound Settings" +msgstr "" + +msgid "Block Theme Downloader" +msgstr "" + +msgid "Block Theme Menu" +msgstr "" + +msgid "Block Title Launcher" +msgstr "" + +msgid "Block Updates" +msgstr "" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "Starta?" + +msgid "Both" +msgstr "Båda" + +msgid "Both Ports" +msgstr "" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "" + +msgid "Can't be formatted" +msgstr "Kan inte formateras" + +msgid "Can't create directory" +msgstr "Kan inte skapa mapp" + +#, c-format +msgid "Can't create file: %s" +msgstr "" + +#, c-format +msgid "Can't create path: %s" +msgstr "" + +msgid "Can't delete:" +msgstr "Kunde inte radera:" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "" + +#, c-format +msgid "Can't read file: %s" +msgstr "" + +msgid "Cancel" +msgstr "Avbryt" + +msgid "Cannot write to destination." +msgstr "" + +msgid "Categories" +msgstr "" + +msgid "Categories:" +msgstr "" + +msgid "Change Play Path" +msgstr "Ändra spel sökväg" + +msgid "Channel Launcher" +msgstr "" + +msgid "Channels" +msgstr "Kannaler" + +msgid "Cheatfile is blank" +msgstr "Fuskfilen är blank" + +msgid "Clear" +msgstr "" + +msgid "Click to Download Covers" +msgstr "Klicka för att ladda ner omslag" + +msgid "Click to change game ID" +msgstr "Klicka för att byta spel ID" + +msgid "Clock" +msgstr "Klocka" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "Stäng" + +msgid "Code Download" +msgstr "Fusknedladdning" + +#, c-format +msgid "Coded by: %s" +msgstr "Kodad av: %s" + +msgid "Coding:" +msgstr "Kodning:" + +msgid "Connection to server timed out." +msgstr "" + +msgid "Console" +msgstr "Konsol" + +msgid "Console Default" +msgstr "Konsolestandard" + +msgid "Console Locked" +msgstr "Konsol låst" + +msgid "Console must be unlocked for this option." +msgstr "" + +msgid "Console must be unlocked to be able to use this." +msgstr "" + +msgid "Console should be unlocked to modify it." +msgstr "Konsolen måste vara upplåst för att kunna ändra det." + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "Fortsätt installera spel?" + +msgid "Continue?" +msgstr "" + +msgid "Controllevel" +msgstr "Kontrollnivå" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "Rätt lösenord" + +msgid "Could not connect to the server." +msgstr "" + +msgid "Could not create GCT file" +msgstr "Kunde inte skapa GCT fil" + +#, c-format +msgid "Could not create path: %s" +msgstr "" + +msgid "Could not extract files for:" +msgstr "" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "" + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "Kunde inte starta DIP-modul!" + +msgid "Could not initialize network!" +msgstr "Kunde inte starta nätverket!" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "Kunde inte öppna skivan" + +msgid "Could not open the WiiTDB.xml file." +msgstr "" + +msgid "Could not open wiitdb.xml." +msgstr "" + +msgid "Could not save." +msgstr "Kunde inte spara." + +msgid "Could not write file." +msgstr "" + +msgid "Could not write to:" +msgstr "" + +msgid "Cover Download" +msgstr "Omslagsnedladdning" + +msgid "Create" +msgstr "Skapa" + +msgid "Credits" +msgstr "Medverkande" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "Anpassade sökvägar" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "Anpassade/Original" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "DOL-sökväg" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "" + +msgid "Default" +msgstr "Standard" + +msgid "Default Gamesettings" +msgstr "Ställ till spelstandard" + +msgid "Default Settings" +msgstr "Standardinställningar" + +msgid "Delete" +msgstr "Radera" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "Radera fusk GCT" + +msgid "Delete Cheat TXT" +msgstr "Radera fusk TXT" + +msgid "Delete Cover Artwork" +msgstr "Radera omslag" + +msgid "Delete Disc Artwork" +msgstr "Radera skivbilder" + +msgid "Delete category" +msgstr "" + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "" + +msgid "Details" +msgstr "" + +msgid "Developed by" +msgstr "Utvecklat av" + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "Katalog existerar inte!" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "Skivbildsnedladdning" + +msgid "Disc Artwork Path" +msgstr "Skivbildsmapp" + +msgid "Disc Default" +msgstr "Skivans standard" + +msgid "Disc Insert Detected" +msgstr "" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "Vänd Skiva" + +msgid "Display" +msgstr "Visning" + +msgid "Display as a carousel" +msgstr "Visa som en karusell" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "Visa som ett rutnät" + +msgid "Display as a list" +msgstr "Visa som en lista" + +msgid "Display favorites only" +msgstr "" + +msgid "Do you want to apply it now?" +msgstr "Vill du tillämpa det nu?" + +msgid "Do you want to apply this theme?" +msgstr "" + +msgid "Do you want to change language?" +msgstr "Vill du byta språk?" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "Vill du ladda ner detta tema?" + +msgid "Do you want to extract all the save games?" +msgstr "" + +msgid "Do you want to extract the save game?" +msgstr "" + +msgid "Do you want to format:" +msgstr "Vill du formatera:" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "" + +msgid "Do you wish to update/download all language files?" +msgstr "Vill du uppdatera/ladda ner alla språkfiler?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "Ladda ner" + +msgid "Download Now" +msgstr "Ladda ner nu" + +msgid "Download finished" +msgstr "Nedladdning klar" + +msgid "Downloading 3D Covers" +msgstr "" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "" + +msgid "Downloading Full HQ Covers" +msgstr "" + +msgid "Downloading Full LQ Covers" +msgstr "" + +msgid "Downloading custom Discarts" +msgstr "" + +msgid "Downloading file..." +msgstr "" + +msgid "Downloading image:" +msgstr "Laddar ner bild:" + +msgid "Downloading original Discarts" +msgstr "" + +msgid "Downloading pagelist:" +msgstr "" + +msgid "Dump NAND to EmuNand" +msgstr "" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "Nederländska" + +msgid "ERROR" +msgstr "FEL" + +msgid "ERROR:" +msgstr "FEL:" + +msgid "ERROR: Can't set up theme." +msgstr "FEL: Kan inte ställa in tema" + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "" + +msgid "Emulated Nand" +msgstr "" + +msgid "English" +msgstr "Engelska" + +msgid "Enter Path" +msgstr "" + +msgid "Error" +msgstr "Fel" + +msgid "Error !" +msgstr "Fel!" + +#, c-format +msgid "Error creating path: %s" +msgstr "" + +msgid "Error opening downloaded file" +msgstr "" + +msgid "Error reading Disc" +msgstr "Fel vid läsning av skiva" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "" + +msgid "Error while downloding file" +msgstr "" + +msgid "Error while opening the zip." +msgstr "" + +msgid "Error while transfering data." +msgstr "Fel vid överförning av data." + +msgid "Error while updating USB Loader GX." +msgstr "" + +msgid "Error writing the data." +msgstr "" + +msgid "Error:" +msgstr "Fel:" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "" + +msgid "Everything" +msgstr "" + +msgid "Exit" +msgstr "" + +msgid "Exit to where?" +msgstr "" + +msgid "Export All Saves to EmuNand" +msgstr "" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "" + +msgid "Extracting file:" +msgstr "" + +msgid "Extracting files..." +msgstr "Packar upp filer..." + +msgid "Extracting files:" +msgstr "" + +msgid "Extracting nand files:" +msgstr "" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "Formatering misslyckad" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "" + +msgid "Failed to extract." +msgstr "Uppackning misslyckades." + +msgid "Failed to initialize the USB storage device." +msgstr "" + +msgid "Failed to open partition" +msgstr "Misslyckades att öppna partition" + +msgid "Failed to read ticket." +msgstr "" + +msgid "Failed to read tmd file." +msgstr "" + +msgid "Failed to read wad header." +msgstr "" + +msgid "Failed updating" +msgstr "" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "" + +msgid "Features Settings" +msgstr "" + +msgid "Feb" +msgstr "" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Kunde inte hitta fil" + +msgid "File read/write error." +msgstr "" + +msgid "Files extracted successfully." +msgstr "" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "" + +msgid "Filesize is 0 Byte." +msgstr "" + +msgid "Flat Covers" +msgstr "" + +msgid "Flip-X" +msgstr "Vänd-X" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "" + +msgid "Force NTSC480p" +msgstr "" + +msgid "Force PAL480p" +msgstr "" + +msgid "Force PAL50" +msgstr "" + +msgid "Force PAL60" +msgstr "" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Formatera" + +msgid "Formatting, please wait..." +msgstr "Formaterar, Vänta..." + +msgid "Found missing images." +msgstr "" + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "Ledigt utrymme" + +msgid "French" +msgstr "Franska" + +msgid "Full" +msgstr "" + +msgid "Full Cover Path" +msgstr "" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "" + +msgid "GAMEID_Gamename" +msgstr "" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "Fusksökväg" + +msgid "GCT File created" +msgstr "GCT fil skapad" + +msgid "GUI Settings" +msgstr "GUI inställningar" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "Spel-ID" + +msgid "Game IOS" +msgstr "" + +msgid "Game Language" +msgstr "Språk" + +msgid "Game Load" +msgstr "Spelinställningar" + +msgid "Game Lock" +msgstr "" + +msgid "Game Only" +msgstr "" + +msgid "Game Region" +msgstr "Spelregion" + +msgid "Game Size" +msgstr "Spelstorlek" + +msgid "Game Sound Mode" +msgstr "Spel ljuds läge" + +msgid "Game Sound Volume" +msgstr "Spel ljuds volym" + +msgid "Game Split Size" +msgstr "" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "Spelet är redan installerat:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "" + +msgid "Games" +msgstr "Spel" + +msgid "Generating GXGameCategories.xml" +msgstr "" + +msgid "Genre:" +msgstr "" + +msgid "German" +msgstr "Tyska" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "Hemmeny" + +msgid "Hard Drive Settings" +msgstr "" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "Homebrew Apps" + +msgid "Homebrew Channel" +msgstr "" + +msgid "Homebrew Launcher" +msgstr "Homebrew Startare" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "Timmars" + +msgid "How do you want to update?" +msgstr "Hur vill du uppdatera?" + +msgid "How to Shutdown?" +msgstr "Hur vill du stänga av?" + +msgid "Import Categories" +msgstr "" + +msgid "Import operation successfully completed." +msgstr "" + +msgid "Importing categories" +msgstr "" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Inkommande fil %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Inkommande fil %0.2fMB" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "Startar nätverk" + +msgid "Insert Disk" +msgstr "Sätt i en skiva" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "Installera" + +msgid "Install Canceled" +msgstr "" + +msgid "Install Directories" +msgstr "" + +msgid "Install Error!" +msgstr "Fel vid installering!" + +msgid "Install Partitions" +msgstr "" + +msgid "Install a game" +msgstr "Installera ett spel" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "" + +msgid "Installing game:" +msgstr "Installerar spel:" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "Det verkar som om du har information som kan vara till nytta för oss. Vänligen skicka informationen vidare till DEV team." + +msgid "Italian" +msgstr "Italienska" + +msgid "Jan" +msgstr "" + +msgid "Japanese" +msgstr "Japanska" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "Juli" + +msgid "June" +msgstr "Juni" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Tangentbord" + +msgid "Korean" +msgstr "Koreanska" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "" + +msgid "Language change:" +msgstr "Språkbyte:" + +msgid "Languagefiles Path" +msgstr "" + +msgid "Languagepath changed." +msgstr "Sökväg till språk ändrad" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Left" +msgstr "Vänster" + +msgid "Like SysMenu" +msgstr "Som System-menyn" + +msgid "List on Gamelaunch" +msgstr "" + +msgid "Load" +msgstr "Ladda" + +msgid "Load From SD/USB" +msgstr "Ladda från SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Ladda fil från: %s?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Ladda denna DOL som alternativ DOL?" + +msgid "Loader Settings" +msgstr "" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "Laddar standard språk." + +msgid "Loading standard music." +msgstr "Laddar standard musik." + +msgid "Lock Console" +msgstr "Lås konsol" + +msgid "Lock USB Loader GX" +msgstr "" + +msgid "Locked" +msgstr "Låst" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "" + +msgid "Loop Music" +msgstr "" + +msgid "Loop Sound" +msgstr "Loopa ljudet" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "" + +msgid "Mark new games" +msgstr "Markera nya spel" + +msgid "May" +msgstr "Maj" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "" + +msgid "Motion+ Video" +msgstr "" + +msgid "Mount DVD drive" +msgstr "Montera DVD läsare" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "" + +msgid "Music Loop Mode" +msgstr "Musik Återuppspelningsläge" + +msgid "Music Volume" +msgstr "Volym" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "" + +msgid "Nand Channels" +msgstr "" + +msgid "Nand Emu Channel Path" +msgstr "" + +msgid "Nand Emu Path" +msgstr "" + +msgid "Nand Emulation" +msgstr "" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Inget" + +msgid "Network is not initiated." +msgstr "" + +msgid "Next" +msgstr "Nästa" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "Nej" + +msgid "No Cheatfile found" +msgstr "Ingen fuskfil hittades" + +msgid "No DOL file found on disc." +msgstr "Ingen DOL-fil hittades på skivan." + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "" + +msgid "No URL or Path specified." +msgstr "" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "Ingen data kunde läsas." + +msgid "No disc inserted." +msgstr "" + +msgid "No favorites selected." +msgstr "" + +msgid "No file missing!" +msgstr "Inga filer saknas!" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "" + +msgid "No new updates." +msgstr "Inga nya uppdateringar" + +msgid "No themes found on the site." +msgstr "Inga teman hittades på sidan." + +msgid "No themes found." +msgstr "" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "" + +msgid "Normal" +msgstr "Vanlig" + +msgid "Not Initialized" +msgstr "" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "" + +msgid "Not a valid URL path" +msgstr "" + +msgid "Not a valid domain" +msgstr "" + +msgid "Not enough free memory." +msgstr "Inte tillräckligt med ledigt minne." + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "Inte tillräckligt med ledigt utrymme!" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "" + +msgid "Not required" +msgstr "" + +msgid "Not supported format!" +msgstr "Formatet stöds inte!" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "" + +msgid "OFF" +msgstr "AV" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "PÅ" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Okt" + +msgid "Official Site:" +msgstr "Officiell sida:" + +msgid "Offset" +msgstr "" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "" + +msgid "Only for Install" +msgstr "Endast för installering" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Original/Anpassade" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Föräldrakontroll" + +msgid "Partial" +msgstr "" + +msgid "Partition" +msgstr "" + +msgid "Password" +msgstr "Lösenord" + +msgid "Password Changed" +msgstr "Lösenordet ändrat" + +msgid "Password has been changed" +msgstr "Lösenordet har ändrats" + +msgid "Patch Country Strings" +msgstr "Ställ in landssträngar" + +msgid "Path Changed" +msgstr "" + +msgid "Permission denied." +msgstr "" + +msgid "Pick from a list" +msgstr "Välj från en lista" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Spelat" + +msgid "Play Next" +msgstr "Spela nästa" + +msgid "Play Once" +msgstr "" + +msgid "Play Previous" +msgstr "Spela förgående" + +msgid "Playing Music:" +msgstr "Spela musik:" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "Vänligen vänta..." + +msgid "Power off the Wii" +msgstr "Stäng av Wii" + +msgid "Prev" +msgstr "Förra" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Dialogknappar" + +msgid "Published by" +msgstr "Publicerat av" + +msgid "Quick Boot" +msgstr "Snabbstart" + +msgid "Random Directory Music" +msgstr "" + +msgid "Real Nand" +msgstr "" + +msgid "Receiving file from:" +msgstr "Tar emot filer från:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "" + +msgid "Released" +msgstr "Släppt" + +msgid "Reload SD" +msgstr "Ladda om SD" + +msgid "Reloading game list now, please wait..." +msgstr "" + +msgid "Remember Unlock" +msgstr "" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "" + +msgid "Rename Game Title" +msgstr "" + +msgid "Rename category" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Reset BG Music" +msgstr "återställ BG musik" + +msgid "Reset Playcounter" +msgstr "Återställ spelat-räknaren" + +msgid "Reset to default BGM?" +msgstr "" + +msgid "Restarting..." +msgstr "Startar om..." + +msgid "Return" +msgstr "Återvänd" + +msgid "Return To" +msgstr "" + +msgid "Return to Wii Menu" +msgstr "Återvänd till Wii-menyn" + +msgid "Right" +msgstr "Höger" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Vibration" + +msgid "SChinese" +msgstr "SKinesiska" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "SFX Volym" + +msgid "Save" +msgstr "Spara" + +msgid "Save Failed. No device inserted?" +msgstr "" + +msgid "Save Game List to" +msgstr "Spara spel lista till" + +msgid "Save List" +msgstr "" + +msgid "Saved" +msgstr "Sparat" + +msgid "Savegame might not exist for this game." +msgstr "" + +msgid "Screensaver" +msgstr "Skärmsläckare" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "Välj" + +msgid "Select DOL Offset" +msgstr "" + +msgid "Select a DOL" +msgstr "Välj en DOL" + +msgid "Select a DOL from Game" +msgstr "" + +msgid "Select game categories" +msgstr "" + +msgid "Select loader mode" +msgstr "" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "" + +msgid "Sept" +msgstr "" + +msgid "Set Search-Filter" +msgstr "Ställ in sök-filter" + +msgid "Settings" +msgstr "Inställningar" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "" + +msgid "Show Play Count" +msgstr "" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "Stäng av helt" + +msgid "Shutdown Wii" +msgstr "" + +msgid "Skip Errors" +msgstr "" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Sortera alfabetiskt" + +msgid "Sort by number of players" +msgstr "" + +msgid "Sort by rank" +msgstr "Sortera efter rank" + +msgid "Sort order by most played" +msgstr "Sortera efter mest spelade" + +msgid "Sound" +msgstr "Ljud" + +msgid "Sound Settings" +msgstr "" + +msgid "Sound+BGM" +msgstr "Ljud+BGM" + +msgid "Sound+Quiet" +msgstr "Ljud+Tyst" + +msgid "Spanish" +msgstr "Spanska" + +msgid "Special thanks to:" +msgstr "Speciellt tack till:" + +msgid "Split each 2GB" +msgstr "" + +msgid "Split each 4GB" +msgstr "" + +msgid "Standby" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "Lyckat" + +msgid "Success." +msgstr "" + +msgid "Success:" +msgstr "Lyckat:" + +msgid "Successfully Saved" +msgstr "Lyckad sparning" + +msgid "Successfully Updated" +msgstr "Uppdateringen lyckades" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "Lyckad radering av:" + +msgid "Successfully extracted theme." +msgstr "Extrahering av tema lyckades." + +msgid "Successfully installed:" +msgstr "Lyckad installation av:" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "" + +msgid "Sync FAT32 FS Info" +msgstr "" + +msgid "Synchronizing..." +msgstr "" + +msgid "System Default" +msgstr "Systemets standard" + +msgid "TChinese" +msgstr "TKinesiska" + +msgid "TXT Cheatcodes Path" +msgstr "Sökväg till txt koder" + +msgid "The .them file was not found in the zip." +msgstr "" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "Den angivna katalogen existerar inte. Vill du skapa den?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "" + +msgid "Theme Downloader" +msgstr "Tema Nedladdare" + +msgid "Theme Menu" +msgstr "" + +msgid "Theme Path" +msgstr "Tema-mapp" + +msgid "Theme Title:" +msgstr "Tema titel:" + +msgid "Themes by www.spiffy360.com" +msgstr "" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "" + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "Tid kvar:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Titel startare" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "Verktygstips" + +msgid "Transfer failed" +msgstr "" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX är skyddad" + +msgid "USB Port" +msgstr "" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "Avinstallera" + +msgid "Uninstall Game" +msgstr "Avinstallera spel" + +msgid "Uninstall Menu" +msgstr "Avinstallerings meny" + +msgid "Uninstall all" +msgstr "" + +msgid "Unknown" +msgstr "" + +msgid "Unlock USB Loader GX" +msgstr "" + +msgid "Unlocked" +msgstr "Upplåst" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "" + +msgid "Update" +msgstr "Uppdatera" + +msgid "Update All" +msgstr "Uppdatera alla" + +msgid "Update DOL" +msgstr "Updatera DOL" + +msgid "Update Files" +msgstr "Uppdatera Filer" + +msgid "Update Path" +msgstr "Sökväg till uppdatering" + +msgid "Update all Language Files" +msgstr "Uppdatera alla språk-filer" + +msgid "Update failed" +msgstr "Uppdatering misslyckades" + +msgid "Update successfull" +msgstr "" + +msgid "Updating Language Files:" +msgstr "Uppdatera språk-filer:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "Uppladdad ZIP fil installerad till homebrew-mappen" + +msgid "Use System Font" +msgstr "" + +msgid "Use global" +msgstr "" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "VIDTV-Patch" + +msgid "Version:" +msgstr "" + +#, c-format +msgid "Version: %s" +msgstr "" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Video-läge" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "" + +msgid "WDM Files Path" +msgstr "" + +msgid "WIP Patches Path" +msgstr "WIP patchssökväg" + +msgid "Waiting..." +msgstr "Väntar..." + +msgid "Warning" +msgstr "" + +msgid "Warning:" +msgstr "" + +msgid "What do you want to do?" +msgstr "" + +msgid "What do you want to update?" +msgstr "Vad vill du uppdatera?" + +msgid "What should be deleted for this game title:" +msgstr "" + +msgid "What to extract from NAND?" +msgstr "" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "WiFi funktioner" + +msgid "Widescreen Factor" +msgstr "" + +msgid "Widescreen Fix" +msgstr "Bredbild 16/9 Fix" + +msgid "Wii Games" +msgstr "" + +msgid "Wii Menu" +msgstr "Wii-meny" + +msgid "Wii Settings" +msgstr "Wii inställningar" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "Wii-ljus" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "" + +msgid "Wiird Debugger" +msgstr "" + +#, c-format +msgid "Write error on file: %s" +msgstr "" + +msgid "Writing GXGameCategories.xml" +msgstr "" + +msgid "Wrong Password" +msgstr "Fel Lösenord" + +msgid "Yes" +msgstr "Ja" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "" + +msgid "You cannot delete this category." +msgstr "" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "" + +msgid "available" +msgstr "tillgänglig" + +msgid "does not exist!" +msgstr "existerar inte!" + +msgid "does not exist! Loading game without cheats." +msgstr "existerar inte! Laddar spel utan fusk." + +msgid "files left" +msgstr "filer kvar" + +msgid "for FAT/NTFS support" +msgstr "för FAT/NTFS stöd" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "" + +msgid "for Ocarina" +msgstr "för Ocarina" + +msgid "for diverse patches" +msgstr "för diverse patcher" + +msgid "for his awesome tool LibWiiGui" +msgstr "för hans underbara verktyg LibWiiGui" + +msgid "for hosting the themes" +msgstr "för hostning av teman" + +msgid "for the USB Loader source" +msgstr "och släppet av källkoden" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "formaterad!" + +msgid "free" +msgstr "ledigt" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "Inget satt" + +msgid "of" +msgstr "av" + +msgid "seconds left" +msgstr "sekunder kvar" + +#~ msgid "Error 002 fix" +#~ msgstr "002 fel fix" + +#~ msgid "Boot/Standard" +#~ msgstr "Boot/Standard" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "Döp om spel på WBFS" + +#~ msgid "for hosting the update files" +#~ msgstr "för lagring av uppdateringar" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Sätt i en Wii-skiva!" + +#~ msgid "No cheats were selected" +#~ msgstr "Inga fusk har valda" + +#~ msgid "Not a Wii Disc" +#~ msgstr "Inte en Wii-skiva" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> Raderar biljetter..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> Raderar biljetter...FEL! " + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> Raderar biljetter...Ok! " + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> Raderar titel ...FEL! " + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> Raderar titel ...Ok!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> Raderar titel innehåll..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> Raderar titel innehåll...FEL! " + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> Raderar titel innehåll...Ok!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> Raderar titel..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> Gör klart installation..." + +#~ msgid ">> Installing content #" +#~ msgstr ">> Installerar innehåll #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> Installerar biljett..." + +#~ msgid ">> Installing title..." +#~ msgstr ">> Installerar titel..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> Läser WAD data..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> Läser WAD data...FEL! " + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> Läser WAD data...Ok!" + +#~ msgid "Done!" +#~ msgstr "Klar!" + +#~ msgid "Error..." +#~ msgstr "Fel..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "Gör klart installation... Ok!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "Installerar innehåll... Ok!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "Installerar biljett... Ok!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "Installerar titel... Ok!" + +#~ msgid "Installing wad" +#~ msgstr "Installerar wad" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "Läser WAD data... Ok!" + +#~ msgid "Uninstalling wad" +#~ msgstr "Avinstallerar wad" + +#~ msgid "New Disc Detected" +#~ msgstr "Ny skiva upptäckt" + +#~ msgid "USB Device not found" +#~ msgstr "USB-enhet ej hittad" + +#~ msgid "You need to select or format a partition" +#~ msgstr "Du måste välja eller formatera en partition" + +#~ msgid "Language File" +#~ msgstr "Språk fil" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Titlar från WiiTDB" + +#~ msgid "WiiTDB Files" +#~ msgstr "WiiTDB" + +#~ msgid "WiiTDB Path" +#~ msgstr "WiiTDB-sökväg" + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "för WiiTDB och lagring av omslag / skivbilder" + +#~ msgid "Install partitions" +#~ msgstr "Installera partitioner" + +#~ msgid " Wad Saved as:" +#~ msgstr "Wad sparad som:" + +#~ msgid "Delete ?" +#~ msgstr "Radera?" + +#~ msgid "Keep" +#~ msgstr "Behåll" + +#~ msgid "Author:" +#~ msgstr "Utgivare:" + +#~ msgid "Download Boxart image?" +#~ msgstr "Ladda ner omslagsbild?" + +#~ msgid "Download Discart image?" +#~ msgstr "Ladda ner skivbild?" + +#~ msgid "Downloading file" +#~ msgstr "Laddar ner fil:" + +#~ msgid "Missing files" +#~ msgstr "Filer som saknas" + +#~ msgid "files not found on the server!" +#~ msgstr "filerna hittades inte på servern!" + +#~ msgid "Disc Images" +#~ msgstr "Skivbilder" + +#~ msgid "Only Customs" +#~ msgstr "Endast anpassade" + +#~ msgid "Only Original" +#~ msgstr "Endast original" + +#~ msgid "Do you really want to delete:" +#~ msgstr "Vill du verkligen radera:" + +#~ msgid "Do you want to use the alternate DOL that is known to be correct?" +#~ msgstr "Vill du använda en alternativ DOL som är känd att fungera?" + +#~ msgid "BETA revisions" +#~ msgstr "BETA version" + +#~ msgid "Unlock console to use this option." +#~ msgstr "Lås upp konsolen för denna inställning." + +#~ msgid "Full Shutdown" +#~ msgstr "Stäng av helt" + +#~ msgid "GXtheme.cfg not found in any subfolder." +#~ msgstr "GXtheme.cfg kunde inte hittas i några undermappar." + +#~ msgid "If you don't have WiFi, press 1 to get an URL to get your WiiTDB.zip" +#~ msgstr "Om du inte har WiFi, tryck 1 för att få en URL till din WiiTDB.zip" + +#~ msgid "Paste it into your browser to get your WiiTDB.zip." +#~ msgstr "Klistra in det i din webbläsare för att hämta din WiiTDB.zip." + +#~ msgid "Shutdown to Idle" +#~ msgstr "Försätt i viloläge" + +#~ msgid "Your URL has been saved in %sWiiTDB_URL.txt." +#~ msgstr "Din URL har sparats som %sWiiTDB_URL.txt." + +#~ msgid "Can't create file" +#~ msgstr "Kunde inte skapa fil" + +#~ msgid "Connection lost..." +#~ msgstr "Uppkoppling förlorad..." + +#~ msgid "Download failed." +#~ msgstr "Nedladdning misslyckades." + +#~ msgid "Download request failed." +#~ msgstr "Nedladdnings begäran misslyckades." + +#~ msgid "Downloading Page List:" +#~ msgstr "Laddar ner lista:" + +#~ msgid "Theme Download Path" +#~ msgstr "Tema-mapp nedladdade" + +#~ msgid "Transfer failed." +#~ msgstr "Flytt misslyckades." + +#~ msgid "Unsupported format, try to extract manually." +#~ msgstr "Format stöds inte, försök extrahera manuelt." + +#~ msgid "and translaters for language files updates" +#~ msgstr "och översättarna." + +#~ msgid "Insert an SD-Card to save." +#~ msgstr "Sätt i ett SD-kort för att spara." + +#~ msgid "Insert an SD-Card to use this option." +#~ msgstr "Sätt i ett SD-kort för att använda denna inställning" + +#~ msgid "No SD-Card inserted!" +#~ msgstr "Inget SD-kort isatt!" + +#~ msgid "Waiting for USB Device" +#~ msgstr "Väntar på USB-enhet" + +#~ msgid "Back to Loader" +#~ msgstr "Tillbaka till loader" + +#~ msgid "FAT: Use directories" +#~ msgstr "FAT: Använd mappar" + +#~ msgid "All partitions" +#~ msgstr "Alla partitioner" + +#~ msgid "Game partition" +#~ msgstr "Spel partition" + +#~ msgid "Install 1:1 Copy" +#~ msgstr "Installera 1:1 Kopia" + +#~ msgid "An Error occured" +#~ msgstr "Ett fel har uppstått" + +#~ msgid "Are you sure you want to enable Parent Control?" +#~ msgstr "Är du säker på att du vill aktivera Föräldrakontroll?" + +#~ msgid "AutoPatch" +#~ msgstr "Autopatch" + +#~ msgid "Checking for Updates" +#~ msgstr "Letar efter uppdateringar" + +#~ msgid "Downloading" +#~ msgstr "Laddar ner" + +#~ msgid "Invalid PIN code" +#~ msgstr "Ogiltig PIN-kod" + +#~ msgid "Parental Control disabled" +#~ msgstr "Föräldrakontroll avaktiverad" + +#~ msgid "The wad file was installed. But It could not be deleted from the SD card." +#~ msgstr "Wad filen har blivit installerad. Men kunde inte raderas från SD-kortet." + +#~ msgid "The wad installation failed with error %ld" +#~ msgstr "Wad installation misslyckades med fel %ld" + +#~ msgid "Unable to open the wad that was just downloaded (%s)." +#~ msgstr "Kunde inte öppna den nedladdade wad filen (%s)." + +#~ msgid "Unlock Parental Control" +#~ msgstr "Lås upp föräldrakontroll" + +#~ msgid "Update to" +#~ msgstr "Uppdatera till" + +#~ msgid "Updating" +#~ msgstr "Uppdaterar" + +#~ msgid "Updating Language Files..." +#~ msgstr "Uppdatera språk-filer..." + +#~ msgid "Updating WiiTDB.zip" +#~ msgstr "Uppdaterar WiiTDB.zip" + +#~ msgid "You don't have Parental Control enabled. If you wish to use Parental Control, enable it in the Wii Settings." +#~ msgstr "Du har inte föräldrakontroll aktiverad. Om du vill använda föräldrakontroll, aktivera det i Wii inställningar." + +#~ msgid "%s : %s May not boot correctly if your System Menu is not up to date." +#~ msgstr "%s : %s Kanske inte kan starta korrekt om din system meny inte är den nyaste versionen." + +#~ msgid "BCA Codes Path changed" +#~ msgstr "BCA kodssökväg ändrad" + +#~ msgid "Back to Wii Menu" +#~ msgstr "Tillbaka till Wii-menyn" + +#~ msgid "Checking existing artwork" +#~ msgstr "Kontrollera befintliga konstverk" + +#~ msgid "Confirm" +#~ msgstr "Bekräfta" + +#~ msgid "Could not find a WBFS partition." +#~ msgstr "Kunde inte hitta WBFS partition." + +#~ msgid "Could not open WBFS partition" +#~ msgstr "Kunde inte öppna WBFS partition" + +#~ msgid "Could not read the disc." +#~ msgstr "Kunde inte läsa skiva." + +#~ msgid "Could not set USB." +#~ msgstr "Kunde inte ställa in USB." + +#~ msgid "Cover Path Changed" +#~ msgstr "Omslagsmapp ändrad" + +#~ msgid "DOL path changed" +#~ msgstr "DOL-sökväg ändrad" + +#~ msgid "Disc Path Changed" +#~ msgstr "Skivbildsmapp ändrad" + +#~ msgid "Display favorites" +#~ msgstr "Visa favoriter" + +#~ msgid "Do you want to retry for 30 secs?" +#~ msgstr "Vill du försöka igen i 30 sekunder?" + +#~ msgid "Enable Parental Control" +#~ msgstr "Aktivera Föräldrakontroll" + +#~ msgid "Force" +#~ msgstr "Tvinga" + +#~ msgid "GCT Cheatcodes Path changed" +#~ msgstr "Sökväg till fusk ändrad" + +#~ msgid "Homebrew Appspath changed" +#~ msgstr "Homebrew Apps ändrad" + +#~ msgid "Insert an SD-Card to download images." +#~ msgstr "Sätt i ett SD-kort för att ladda ner bilder." + +#~ msgid "Install not possible" +#~ msgstr "Installation inte möjlig" + +#~ msgid "Most likely it has dimensions that are not evenly divisible by 4." +#~ msgstr "Troligtvis har den mått som inte är jämnt dividerade med 4." + +#~ msgid "Network init error" +#~ msgstr "Fel vid nätverksstart" + +#~ msgid "No .dol or .elf files found." +#~ msgstr "Ingen .dol eller .elf fil hittades." + +#~ msgid "No Favorites" +#~ msgstr "Inga favoriter" + +#~ msgid "No USB Device" +#~ msgstr "Ingen USB-enhet" + +#~ msgid "No USB Device found." +#~ msgstr "Ingen USB-enhet hittad." + +#~ msgid "No WBFS or FAT/NTFS partition found" +#~ msgstr "Ingen WBFS eller FAT/NTFS partition hittad" + +#~ msgid "Normal Covers" +#~ msgstr "Vanliga omslag" + +#~ msgid "Not Found" +#~ msgstr "Hittades inte" + +#~ msgid "Not a DOL/ELF file." +#~ msgstr "Inte en DOL/ELF fil." + +#~ msgid "Reset to standard BGM?" +#~ msgstr "Återställ till standard BGM?" + +#~ msgid "Save Failed" +#~ msgstr "Sparande misslyckat" + +#~ msgid "Selected DOL" +#~ msgstr "Vald DOL" + +#~ msgid "Standard" +#~ msgstr "Standard" + +#~ msgid "TXT Cheatcodes Path changed" +#~ msgstr "TXTCheatcodes sökväg ändrad" + +#~ msgid "Theme Download Path changed" +#~ msgstr "Tema-mapp nedladdade ändrad" + +#~ msgid "Theme Path Changed" +#~ msgstr "Tema-mapp ändrad" + +#~ msgid "USB Loader GX will only run with Hermes CIOS rev 4! Please make sure you have revision 4 installed!" +#~ msgstr "USB Loader GX kommer endast köra med Hermes CIOS ver 4! Vänligen kontrollera att du har ver 4 installerad!" + +#~ msgid "Update Path changed." +#~ msgstr "Sökväg till uppdatering ändrad." + +#~ msgid "WIP Patches Path changed" +#~ msgstr "WIP patchssökväg ändrad" + +#~ msgid "WiiTDB Path changed." +#~ msgstr "WiiTDB-sökväg ändrad." + +#~ msgid "You are about to delete " +#~ msgstr "Då håller på att radera " + +#~ msgid "You are choosing to display favorites and you do not have any selected." +#~ msgstr "Du har valt att visa favoriter men du har inga favoriter valda." + +#~ msgid "You are using NTFS filesystem. Due to possible write errors to a NTFS partition, installing a game is not possible." +#~ msgstr "Du använder NTFS filsystem. Pågrund av möjliga skriv fel till en NTFS partition, så är det inte möjligt att installera spel." + +#~ msgid "You have attempted to load a bad image" +#~ msgstr "Du har försökt ladda en dålig bild" + +#~ msgid "does not exist! You Messed something up, Idiot." +#~ msgstr "existerar inte! Du har gjort något fel." + +#~ msgid "file left" +#~ msgstr "fil kvar" diff --git a/Languages/tchinese.lang b/Languages/tchinese.lang new file mode 100644 index 0000000..4645b9a --- /dev/null +++ b/Languages/tchinese.lang @@ -0,0 +1,2622 @@ +# USB Loader GX language source file. +# tchinese.lang - r1208 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:05+0200\n" +"PO-Revision-Date: 2010-02-15 21:00+0800\n" +"Last-Translator: Jane.H\n" +"Language-Team: kyogc, Miller, Mika Li, Jane.H\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr "不能下載。" + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr "已經被儲存。內容尚未驗證。部分代碼可能無法作用。如果你遇到問題,請用文字編輯器開啟文字檔以獲得更多的資訊。" + +msgid " is not on the server." +msgstr "不在伺服器上" + +#, c-format +msgid "%i files not found on the server!" +msgstr "伺服器上找不到%i個檔!" + +#, c-format +msgid "%i missing files" +msgstr "缺少%i個檔案" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (全年齡)" + +msgid "1 (Child 7+)" +msgstr "1 (7歲以上)" + +msgid "1 hour" +msgstr "1 小時" + +msgid "10 min" +msgstr "10 分鐘" + +msgid "2 (Teen 12+)" +msgstr "2 (12歲以上)" + +msgid "20 min" +msgstr "20 分鐘" + +msgid "2D Cover Path" +msgstr "2D封面路徑" + +msgid "3 (Mature 16+)" +msgstr "3 (16歲以上)" + +msgid "3 min" +msgstr "3 分鐘" + +msgid "30 min" +msgstr "30 分鐘" + +msgid "3D Cover Path" +msgstr "3D封面路徑" + +msgid "3D Covers" +msgstr "3D 封面" + +msgid "4 (Adults Only 18+)" +msgstr "4 (18歲以上成人)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 分鐘" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "自動" + +msgid "AXNextFrame" +msgstr "AXNextFrame" + +msgid "Add category" +msgstr "增加類別" + +msgid "Adjust Overscan X" +msgstr "調整X軸掃描" + +msgid "Adjust Overscan Y" +msgstr "調整Y軸掃描" + +msgid "After zoom" +msgstr "縮放大小後" + +msgid "All" +msgstr "全部" + +msgid "All Partitions" +msgstr "所有分割區" + +msgid "All files extracted." +msgstr "所有檔案已解壓縮。" + +msgid "All images downloaded successfully." +msgstr "所有圖片已下載成功。" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "USB Loader GX 所有功能已解鎖." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "可選擇Alt DOL檔" + +msgid "An example file was created here:" +msgstr "在這裡建立範本檔:" + +msgid "Animation Start" +msgstr "動畫縮圖啟動" + +msgid "App Language" +msgstr "語言設定" + +msgid "Apply" +msgstr "套用" + +msgid "Apr" +msgstr "四月" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "真的確定要刪除SD卡上全部選取的遊戲嗎?" + +msgid "Are you sure you want to delete this category?" +msgstr "確定要刪除此類別嗎?" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "確定要從GameTDB匯入遊戲類別嗎?" + +msgid "Are you sure you want to install on SD?" +msgstr "確定要安裝在SD卡嗎?" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "確定要鎖上 USB Loader GX嗎?" + +msgid "Are you sure you want to remount SD?" +msgstr "確定要重新掛載SD卡嗎?" + +msgid "Are you sure you want to reset?" +msgstr "確定要重新啟動嗎?" + +msgid "Are you sure?" +msgstr "確定?" + +msgid "Aspect Ratio" +msgstr "長寬比率" + +msgid "Attention!" +msgstr "注意!" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "八月" + +msgid "Author(s):" +msgstr "作者(群)" + +msgid "Auto" +msgstr "自動" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "自動初始化網路" + +msgid "BCA Codes Path" +msgstr "BAC代碼路徑" + +msgid "Back" +msgstr "返回" + +msgid "Back to HBC or Wii Menu" +msgstr "返回 HBC 或 Wii 系統選單" + +msgid "Backgroundmusic" +msgstr "背景音樂" + +msgid "Banner Animation" +msgstr "頻道動畫" + +msgid "Banner Animation Settings" +msgstr "頻道動畫設定" + +msgid "Banner On Channels" +msgstr "頻道動畫顯示在頻道" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "頻道格狀牆版面只能在AHBPROT模式下顯示! 請考慮安裝最新版的HBC" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "頻道視窗模式只能在AHBPROT模式下顯示! 請考慮安裝最新版的HBC" + +msgid "Big thanks to:" +msgstr "非常感謝:" + +msgid "Block Categories Menu" +msgstr "封鎖類別選單" + +msgid "Block Categories Modify" +msgstr "封鎖類別修改" + +msgid "Block Cover Downloads" +msgstr "封鎖封面下載" + +msgid "Block Custom Paths" +msgstr "封鎖自訂路徑" + +msgid "Block Feature Settings" +msgstr "封鎖功能設定" + +msgid "Block Game Install" +msgstr "封鎖遊戲安裝" + +msgid "Block Game Settings" +msgstr "封鎖遊戲設定" + +msgid "Block GameID Change" +msgstr "封鎖遊戲ID更改" + +msgid "Block Global Settings" +msgstr "封鎖整體設定" + +msgid "Block Gui Settings" +msgstr "封鎖介面設定" + +msgid "Block HBC Menu" +msgstr "封鎖 HBC 選單" + +msgid "Block Hard Drive Settings" +msgstr "封鎖硬碟設定" + +msgid "Block IOS Reload" +msgstr "封鎖 IOS 重新載入" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "封鎖 Loader 模式按鈕" + +msgid "Block Loader Settings" +msgstr "封鎖 Loader 設定" + +msgid "Block Parental Settings" +msgstr "封鎖親子設定" + +msgid "Block Priiloader Override" +msgstr "封鎖 使Priiloader無效" + +msgid "Block Reset Settings" +msgstr "封鎖重置設定" + +msgid "Block SD Reload Button" +msgstr "封鎖 SD 重新載入按鈕" + +msgid "Block Sound Settings" +msgstr "封鎖音效設定" + +msgid "Block Theme Downloader" +msgstr "封鎖主題下載" + +msgid "Block Theme Menu" +msgstr "封鎖主題選單" + +msgid "Block Title Launcher" +msgstr "封鎖 Title 啟動" + +msgid "Block Updates" +msgstr "封鎖更新" + +msgid "Boot Content" +msgstr "啟動內容" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "啟動?" + +msgid "Both" +msgstr "全部" + +msgid "Both Ports" +msgstr "兩個連接埠" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "緩衝頻道動畫檔案" + +msgid "Cache BNR Files Path" +msgstr "緩衝頻道動畫檔案路徑" + +msgid "Cache Titles" +msgstr "遊戲標題緩衝" + +msgid "Can't be formatted" +msgstr "無法格式化" + +msgid "Can't create directory" +msgstr "無法建立目錄" + +#, c-format +msgid "Can't create file: %s" +msgstr "無法建立檔案: %s" + +#, c-format +msgid "Can't create path: %s" +msgstr "無法建立路徑: %s" + +msgid "Can't delete:" +msgstr "無法刪除:" + +msgid "Can't mount or unknown disc format." +msgstr "無法掛載或未知光碟格式" + +#, fuzzy, c-format +msgid "Can't open file for write: %s" +msgstr "無法開啟檔案寫入" + +#, c-format +msgid "Can't open file: %s" +msgstr "無法開啟檔案: %s" + +#, c-format +msgid "Can't read file: %s" +msgstr "無法讀取檔案: %s" + +msgid "Cancel" +msgstr "取消" + +msgid "Cannot write to destination." +msgstr "無法寫入目的地。" + +msgid "Categories" +msgstr "類別" + +msgid "Categories:" +msgstr "類別:" + +msgid "Change Play Path" +msgstr "變更執行路徑" + +msgid "Channel Launcher" +msgstr "頻道啟動器" + +msgid "Channels" +msgstr "頻道" + +msgid "Cheatfile is blank" +msgstr "金手指檔是空的" + +msgid "Clear" +msgstr "清除" + +msgid "Click to Download Covers" +msgstr "點選下載封面" + +msgid "Click to change game ID" +msgstr "點選變更遊戲 ID" + +msgid "Clock" +msgstr "時鐘" + +msgid "Clock Scale Factor" +msgstr "時鐘比例倍數" + +msgid "Close" +msgstr "關閉" + +msgid "Code Download" +msgstr "金手指代碼下載" + +#, c-format +msgid "Coded by: %s" +msgstr "程式設計者: %s" + +msgid "Coding:" +msgstr "編譯:" + +msgid "Connection to server timed out." +msgstr "連接伺服器超時。" + +msgid "Console" +msgstr "控制台" + +msgid "Console Default" +msgstr "主機預設值" + +msgid "Console Locked" +msgstr "控制台已上鎖" + +msgid "Console must be unlocked for this option." +msgstr "對於此選項控制台必須解鎖才可用。" + +msgid "Console must be unlocked to be able to use this." +msgstr "控制台必須解鎖才可使用此項。" + +msgid "Console should be unlocked to modify it." +msgstr "控制台須解鎖才可變更設定。" + +msgid "Continue" +msgstr "繼續" + +msgid "Continue to install game?" +msgstr "繼續安裝遊戲?" + +msgid "Continue?" +msgstr "繼續嗎?" + +msgid "Controllevel" +msgstr "遊戲分級" + +msgid "Copy" +msgstr "複製" + +msgid "Copying Canceled" +msgstr "複製已取消" + +msgid "Copying GC game..." +msgstr "複製GameCube遊戲中..." + +msgid "Copying files..." +msgstr "複製檔案中..." + +msgid "Correct Password" +msgstr "密碼正確" + +msgid "Could not connect to the server." +msgstr "無法連接伺服器。" + +msgid "Could not create GCT file" +msgstr "無法建立 GCT 檔案" + +#, c-format +msgid "Could not create path: %s" +msgstr "無法建立路徑: %s" + +msgid "Could not extract files for:" +msgstr "無法解壓縮檔案:" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "無法從wiitdb.xml找到此遊戲資訊。" + +msgid "Could not get free device space for game." +msgstr "無法為遊戲取得裝置可用空間" + +msgid "Could not initialize DIP module!" +msgstr "無法啟動 DIP 模組!" + +msgid "Could not initialize network!" +msgstr "無法啟動網路!" + +msgid "Could not initialize network, time out!" +msgstr "無法啟動網路,已逾時" + +msgid "Could not open Disc" +msgstr "無法開啟光碟" + +msgid "Could not open the WiiTDB.xml file." +msgstr "無法開啟WiiTDB.xml檔。" + +msgid "Could not open wiitdb.xml." +msgstr "無法開啟wiitdb.xml。" + +msgid "Could not save." +msgstr "無法儲存" + +msgid "Could not write file." +msgstr "無法寫入檔案。" + +msgid "Could not write to:" +msgstr "無法寫入到:" + +msgid "Cover Download" +msgstr "下載封面" + +msgid "Create" +msgstr "產生" + +msgid "Credits" +msgstr "作者信息" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "自製頻道動畫" + +msgid "Custom Paths" +msgstr "自訂路徑" + +msgid "Customs" +msgstr "自訂" + +msgid "Customs/Original" +msgstr "自製/原始" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "DOL 路徑" + +msgid "Debug" +msgstr "除錯" + +msgid "Debug Wait" +msgstr "除錯 等待" + +msgid "Debugger Paused Start" +msgstr "偵錯器暫停啟動" + +msgid "Dec" +msgstr "十二月" + +msgid "Default" +msgstr "預設值" + +msgid "Default Gamesettings" +msgstr "初始化遊戲設定" + +msgid "Default Settings" +msgstr "初始化設定" + +msgid "Delete" +msgstr "刪除" + +msgid "Delete Cached Banner" +msgstr "刪除頻道緩衝" + +msgid "Delete Cheat GCT" +msgstr "刪除GCT金手指檔" + +msgid "Delete Cheat TXT" +msgstr "刪除TXT金手指檔" + +msgid "Delete Cover Artwork" +msgstr "刪除封面" + +msgid "Delete Disc Artwork" +msgstr "刪除光碟圖片" + +msgid "Delete category" +msgstr "刪除類別" + +msgid "Deleting directories..." +msgstr "刪除目錄中..." + +msgid "Deleting files..." +msgstr "刪除檔案中..." + +msgid "Design:" +msgstr "設計者:" + +msgid "Details" +msgstr "詳細資訊" + +msgid "Developed by" +msgstr "開發商" + +msgid "Developer:" +msgstr "開發者:" + +msgid "Devolution" +msgstr "Devolution" + +msgid "Devolution Loader Path" +msgstr "Devolution Loader路徑" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "Devolution的loader.bin檔無法載入。" + +msgid "Directory does not exist!" +msgstr "目錄不存在" + +msgid "Disc 1" +msgstr "光碟 1" + +msgid "Disc 2" +msgstr "光碟 2" + +msgid "Disc Artwork Download" +msgstr "下載光碟圖片" + +msgid "Disc Artwork Path" +msgstr "光碟圖片路徑" + +msgid "Disc Default" +msgstr "光碟預設" + +msgid "Disc Insert Detected" +msgstr "光碟插入檢查" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "光碟讀取錯誤" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "光碟2 需被安裝為未壓縮格式才可用DM(L) v2.6+執行,確定要安裝為壓縮格式嗎?" + +msgid "Discarts" +msgstr "光碟封面" + +msgid "DiskFlip" +msgstr "光碟滑動" + +msgid "Display" +msgstr "顯示" + +msgid "Display as a carousel" +msgstr "轉盤模式" + +msgid "Display as a channel grid" +msgstr "頻道格狀牆模式" + +msgid "Display as a grid" +msgstr "封面牆模式" + +msgid "Display as a list" +msgstr "表單模式" + +msgid "Display favorites only" +msgstr "只顯示最愛模式" + +msgid "Do you want to apply it now?" +msgstr "要套用設定嗎?" + +msgid "Do you want to apply this theme?" +msgstr "要套用這個佈景主題嗎?" + +msgid "Do you want to change language?" +msgstr "要變更語言嗎?" + +msgid "Do you want to continue with next game?" +msgstr "要繼續玩下一個遊戲嗎?" + +msgid "Do you want to copy now?" +msgstr "是否現在要複製?" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "是否要複製遊戲到SD卡或刪除SD卡上的遊戲?" + +msgid "Do you want to delete a game on SD?" +msgstr "是否要刪除SD卡上的遊戲?" + +msgid "Do you want to discard changes?" +msgstr "是否要放棄變更?" + +msgid "Do you want to download this theme?" +msgstr "是否要下載這個佈景主題嗎?" + +msgid "Do you want to extract all the save games?" +msgstr "是否要提取所有遊戲存檔嗎?" + +msgid "Do you want to extract the save game?" +msgstr "是否要提取這遊戲存檔嗎?" + +msgid "Do you want to format:" +msgstr "是否格式化:" + +msgid "Do you want to install selected games?" +msgstr "是否要安裝選取的遊戲?" + +msgid "Do you want to load the default theme?" +msgstr "是否要載入預設佈景主題嗎?" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "是否要重新初始化網路?" + +msgid "Do you want to start the game now?" +msgstr "是否現在要開始遊戲?" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "是否要同步所有FAT32分區可用空間資訊?" + +msgid "Do you wish to update/download all language files?" +msgstr "是否要更新/下載所有語言檔案嗎?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "下載" + +msgid "Download Now" +msgstr "現在下載" + +msgid "Download finished" +msgstr "下載完成" + +msgid "Downloading 3D Covers" +msgstr "下載 3D封面" + +msgid "Downloading Custom Banners" +msgstr "下載自製頻道動畫" + +msgid "Downloading Flat Covers" +msgstr "下載平面封面" + +msgid "Downloading Full HQ Covers" +msgstr "下載完整高畫質封面" + +msgid "Downloading Full LQ Covers" +msgstr "下載完整低畫質封面" + +msgid "Downloading custom Discarts" +msgstr "下載自製光碟圖片" + +msgid "Downloading file..." +msgstr "下載檔案中..." + +msgid "Downloading image:" +msgstr "下載圖片:" + +msgid "Downloading original Discarts" +msgstr "下載原始光碟圖片" + +msgid "Downloading pagelist:" +msgstr "下載頁面清單:" + +msgid "Dump NAND to EmuNand" +msgstr "轉存 NAND 到 模擬Nand" + +msgid "During zoom" +msgstr "在縮放大小時" + +msgid "Dutch" +msgstr "荷蘭文" + +msgid "ERROR" +msgstr "錯誤" + +msgid "ERROR:" +msgstr "錯誤:" + +msgid "ERROR: Can't set up theme." +msgstr "錯誤:無法設定佈景主題。" + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "模擬Nand 頻道" + +msgid "Emulated Nand" +msgstr "啟動模擬 Nand" + +msgid "English" +msgstr "英文" + +msgid "Enter Path" +msgstr "輸入路徑" + +msgid "Error" +msgstr "錯誤" + +msgid "Error !" +msgstr "錯誤 !" + +#, c-format +msgid "Error creating path: %s" +msgstr "建立路徑錯誤: %s" + +msgid "Error opening downloaded file" +msgstr "開啟下載檔案錯誤" + +msgid "Error reading Disc" +msgstr "讀取光碟錯誤" + +msgid "Error reading disc" +msgstr "讀取光碟錯誤" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "下載檔案時產生錯誤: %i" + +msgid "Error while downloding file" +msgstr "下載檔案過程錯誤" + +msgid "Error while opening the zip." +msgstr "開啟zip檔過程錯誤。" + +msgid "Error while transfering data." +msgstr "檔案傳輸過程錯誤。" + +msgid "Error while updating USB Loader GX." +msgstr "更新USB Loader GX過程錯誤。" + +msgid "Error writing the data." +msgstr "寫入資料錯誤。" + +msgid "Error:" +msgstr "錯誤:" + +msgid "Error: Not enough space on SD." +msgstr "錯誤:SD卡上空間不足" + +msgid "Errors occured." +msgstr "發生錯誤。" + +msgid "Everything" +msgstr "所有" + +msgid "Exit" +msgstr "退出" + +msgid "Exit to where?" +msgstr "退出到?" + +msgid "Export All Saves to EmuNand" +msgstr "輸出所有存檔到模擬Nand" + +msgid "Export Miis to EmuNand" +msgstr "輸出Miis到模擬Nand" + +msgid "Export SYSCONF to EmuNand" +msgstr "輸出SYSCONF到模擬Nand" + +msgid "Extract Miis to the Emu NAND?" +msgstr "提取Miis到模擬Nand" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "提取SYSCONF到模擬Nand" + +msgid "Extract Save to EmuNand" +msgstr "提取存檔到模擬Nand" + +msgid "Extracting file:" +msgstr "提取檔案:" + +msgid "Extracting files..." +msgstr "提取檔案中..." + +msgid "Extracting files:" +msgstr "提取檔案:" + +msgid "Extracting nand files:" +msgstr "提取 nand 檔案:" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "失敗" + +msgid "Failed copying file" +msgstr "複製檔案失敗" + +msgid "Failed formating" +msgstr "格式化失敗" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "所有檔案提取失敗。遊戲存檔可能不存在。" + +msgid "Failed to extract." +msgstr "提取失敗。" + +msgid "Failed to initialize the USB storage device." +msgstr "USB儲存裝置初始化失敗。" + +msgid "Failed to open partition" +msgstr "開啟磁區失敗" + +msgid "Failed to read ticket." +msgstr "讀取 ticket 失敗。" + +msgid "Failed to read tmd file." +msgstr "讀取 tmd 檔失敗。" + +msgid "Failed to read wad header." +msgstr "讀取 wad 檔資訊失敗。" + +msgid "Failed updating" +msgstr "更新失敗" + +msgid "Favorite Level" +msgstr "最愛等級" + +msgid "Features" +msgstr "功能" + +msgid "Features Settings" +msgstr "功能設定" + +msgid "Feb" +msgstr "二月" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "找不到該檔案。" + +msgid "File read/write error." +msgstr "檔案讀取/寫入錯誤。" + +msgid "Files extracted successfully." +msgstr "檔案提取成功。" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "檔案大小是 %i Byte。" + +msgid "Filesize is 0 Byte." +msgstr "檔案大小是0 Byte。" + +msgid "Flat Covers" +msgstr "平面封面" + +msgid "Flip-X" +msgstr "按鍵規則" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "字型比例倍數" + +msgid "Force 16:9" +msgstr "強制 16:9" + +msgid "Force 4:3" +msgstr "強制 4:3" + +msgid "Force NTSC" +msgstr "強制 NTSC" + +msgid "Force NTSC480p" +msgstr "強制 NTSC480p" + +msgid "Force PAL480p" +msgstr "強制 PAL480p" + +msgid "Force PAL50" +msgstr "強制 PAL50" + +msgid "Force PAL60" +msgstr "強制 PAL60" + +msgid "Force Titles from Disc" +msgstr "強制從光碟顯示標題" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "格式化" + +msgid "Formatting, please wait..." +msgstr "格式化中, 請稍候..." + +msgid "Found missing images." +msgstr "找到缺少圖片。" + +msgid "Frame" +msgstr "畫框數" + +msgid "Frame Projection Height" +msgstr "畫框投射高度" + +msgid "Frame Projection Width" +msgstr "畫框投射寬度" + +msgid "Frame Projection X-Offset" +msgstr "畫框投射X軸位移" + +msgid "Frame Projection Y-Offset" +msgstr "畫框投射Y軸位移" + +msgid "Frames" +msgstr "畫框數" + +msgid "Free Space" +msgstr "剩餘空間" + +msgid "French" +msgstr "法文" + +msgid "Full" +msgstr "全部" + +msgid "Full Cover Path" +msgstr "完整封面路徑" + +msgid "Full Covers" +msgstr "完整封面" + +msgid "Full Menu" +msgstr "完整選單" + +msgid "Full covers Download" +msgstr "完整封面下載" + +msgid "Full shutdown" +msgstr "關機" + +msgid "GAMEID_Gamename" +msgstr "GAMEID_遊戲名稱" + +msgid "GC Banner Scale" +msgstr "GC 頻道大小" + +msgid "GC Games" +msgstr "GC 遊戲" + +msgid "GC Install 32K Aligned" +msgstr "GC 安裝 32KB 邊界" + +msgid "GC Install Compressed" +msgstr "GC 安裝 壓縮" + +msgid "GCT Cheatcodes Path" +msgstr "金手指檔案路徑" + +msgid "GCT File created" +msgstr "GCT 檔案已產生" + +msgid "GUI Settings" +msgstr "介面設定" + +msgid "GXDraw" +msgstr "GXDraw" + +msgid "GXFlush" +msgstr "GXFlush" + +msgid "Game Cube Games Delete" +msgstr "GameCube 遊戲刪除" + +msgid "Game Cube Install Menu" +msgstr "GameCube 安裝畫面" + +msgid "Game ID" +msgstr "遊戲 ID" + +msgid "Game IOS" +msgstr "遊戲 IOS" + +msgid "Game Language" +msgstr "遊戲語言" + +msgid "Game Load" +msgstr "遊戲載入設定" + +msgid "Game Lock" +msgstr "遊戲上鎖" + +msgid "Game Only" +msgstr "僅遊戲" + +msgid "Game Region" +msgstr "遊戲區碼" + +msgid "Game Size" +msgstr "遊戲容量" + +msgid "Game Sound Mode" +msgstr "遊戲聲音模式" + +msgid "Game Sound Volume" +msgstr "遊戲聲音音量" + +msgid "Game Split Size" +msgstr "遊戲分割大小" + +msgid "Game Window Mode" +msgstr "遊戲視窗模式" + +msgid "Game is already installed:" +msgstr "已安裝過遊戲:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "遊戲/安裝磁區" + +msgid "GameCube" +msgstr "GameCube" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "GameCube 模式" + +msgid "GameCube Source" +msgstr "GameCube 來源" + +msgid "Gamename [GAMEID]" +msgstr "遊戲名稱 [GAMEID]" + +msgid "Games" +msgstr "遊戲數量" + +msgid "Generating GXGameCategories.xml" +msgstr "正在產生 GXGameCategories.xml" + +msgid "Genre:" +msgstr "類型:" + +msgid "German" +msgstr "德文" + +msgid "Getting file list..." +msgstr "讀取檔案清單..." + +msgid "Getting game folder size..." +msgstr "讀取遊戲資料夾大小..." + +msgid "Global Settings" +msgstr "整體設定" + +msgid "Grid Scroll Speed" +msgstr "格狀牆的捲動速度" + +msgid "HOME Menu" +msgstr "主選單" + +msgid "Hard Drive Settings" +msgstr "硬碟設定" + +msgid "High Quality" +msgstr "高畫質" + +msgid "High/Low" +msgstr "高/低" + +msgid "Homebrew Apps Path" +msgstr "HBC 應用程式路徑" + +msgid "Homebrew Channel" +msgstr "HBC" + +msgid "Homebrew Launcher" +msgstr "HBC 應用程式" + +msgid "Hooktype" +msgstr "掛載類型" + +msgid "Hour" +msgstr "小時制" + +msgid "How do you want to update?" +msgstr "是否執行更新?" + +msgid "How to Shutdown?" +msgstr "關機選項?" + +msgid "Import Categories" +msgstr "輸入類別" + +msgid "Import operation successfully completed." +msgstr "輸入操作順利完成。" + +msgid "Importing categories" +msgstr "正在輸入類別" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "正在接收檔案 %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "正在接收檔案 %0.2fMB" + +msgid "Individual" +msgstr "個別的" + +msgid "Initializing Network" +msgstr "正在啟動網路" + +msgid "Insert Disk" +msgstr "插入光碟" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "插入Wii或GameCube光碟!" + +msgid "Install" +msgstr "安裝" + +msgid "Install Canceled" +msgstr "安裝已取消" + +msgid "Install Directories" +msgstr "安裝目錄" + +msgid "Install Error!" +msgstr "安裝錯誤!" + +msgid "Install Partitions" +msgstr "安裝磁區" + +msgid "Install a game" +msgstr "安裝遊戲" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "已安裝完成" + +msgid "Installing Game Cube Game..." +msgstr "正在安裝GameCube遊戲..." + +msgid "Installing content" +msgstr "正在安裝程式主體" + +msgid "Installing game:" +msgstr "正在安裝遊戲:" + +msgid "Installing title..." +msgstr "正在安裝 title..." + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "輸入無效的IOS數值. 數值必須原值小1或介於 200 - 255 之間. " + +msgid "Invalid wad file." +msgstr "無效的 wad 檔。" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "請將這些訊息傳送至開發小組以幫助本軟體開發" + +msgid "Italian" +msgstr "義大利文" + +msgid "Jan" +msgstr "一月" + +msgid "Japanese" +msgstr "日文" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "手把" + +msgid "July" +msgstr "七月" + +msgid "June" +msgstr "六月" + +msgid "KPAD Read" +msgstr "KPAD 讀取" + +msgid "Keyboard" +msgstr "鍵盤" + +msgid "Korean" +msgstr "韓文" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "語言檔" + +msgid "Language change:" +msgstr "變更語言為:" + +msgid "Languagefiles Path" +msgstr "語言檔路徑" + +msgid "Languagepath changed." +msgstr "語言路徑已變更" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "用模擬nand啟動Wii遊戲僅能以d2x cIOS執行!首先變更遊戲IOS為d2x cIOS。" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "啟動模擬 nand 頻道僅能以d2x cIOS執行!首先變更遊戲IOS為d2x cIOS。 " + +msgid "Left" +msgstr "左" + +msgid "Like SysMenu" +msgstr "同系統選單" + +msgid "List on Gamelaunch" +msgstr "遊戲啟動時列出清單" + +msgid "Load" +msgstr "載入" + +msgid "Load From SD/USB" +msgstr "從 SD/USB 載入" + +#, c-format +msgid "Load file from: %s ?" +msgstr "檔案載入位置: %s" + +msgid "Load this DOL as alternate DOL?" +msgstr "載入這個 DOL 作為替代 DOL?" + +msgid "Loader Settings" +msgstr "Loader設定" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "正在載入預設語言" + +msgid "Loading standard music." +msgstr "正在載入預設音樂" + +msgid "Lock Console" +msgstr "鎖上控制台" + +msgid "Lock USB Loader GX" +msgstr "鎖上USB Loader GX" + +msgid "Locked" +msgstr "已鎖定" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "重複路徑" + +msgid "Loop Music" +msgstr "重複音樂" + +msgid "Loop Sound" +msgstr "重複音樂" + +msgid "Low Quality" +msgstr "低畫質" + +msgid "Low/High" +msgstr "低/高" + +msgid "MIOS (Default & Customs)" +msgstr "MIOS (預設 & 自訂)" + +msgid "Main DOL" +msgstr "主要的 DOL" + +msgid "Main GameCube Games Path" +msgstr "主要的 GameCube遊戲路徑" + +msgid "Main GameCube Path" +msgstr "主要的 GameCube路徑" + +msgid "Main Path" +msgstr "主要路徑" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "三月" + +msgid "Mark new games" +msgstr "標示新遊戲" + +msgid "May" +msgstr "五月" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "留言板更新" + +msgid "Motion+ Video" +msgstr "移動+視訊" + +msgid "Mount DVD drive" +msgstr "掛載DVD光碟" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "多重磁區" + +msgid "Music Loop Mode" +msgstr "音樂循環模式" + +msgid "Music Volume" +msgstr "音樂音量" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "Nand 頻道模擬器" + +msgid "Nand Channels" +msgstr "Nand 頻道" + +msgid "Nand Emu Channel Path" +msgstr "Nand 模擬頻道路徑" + +msgid "Nand Emu Path" +msgstr "Nand 模擬路徑" + +msgid "Nand Emulation" +msgstr "Nand 模擬器" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "Nand 模擬器僅可用D2X cIOS!" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "Nand 模擬器僅能在 FAT/FAT32 格式磁區執行!" + +msgid "Nand Saves Emulation" +msgstr "Nand 儲存模擬器" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "皆不顯示" + +msgid "Network is not initiated." +msgstr "網路無法啟動。" + +msgid "Next" +msgstr "往後" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "否" + +msgid "No Cheatfile found" +msgstr "金手指檔案未找到" + +msgid "No DOL file found on disc." +msgstr "光碟中未找到 DOL 檔案。" + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "沒有分割" + +msgid "No URL or Path specified." +msgstr "沒有指定URL或路徑。" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "沒找到WBFS 或 FAT/NTFS/EXT磁區" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "在config路徑沒找到Wiinnertag.xml檔。是否要建立一個範本檔?" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "金手指代碼未被選取! 是否已刪除金手指檔案?" + +msgid "No data could be read." +msgstr "無法讀取數據" + +msgid "No disc inserted." +msgstr "未插入光碟。" + +msgid "No favorites selected." +msgstr "沒有選取最愛。" + +msgid "No file missing!" +msgstr "沒有檔案缺少!" + +msgid "No games found on the disc" +msgstr "光碟中未找到遊戲" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "你的儲存裝置沒有語言檔可供更新!是否要下載新的語言檔?" + +msgid "No new updates." +msgstr "沒有可用更新。" + +msgid "No themes found on the site." +msgstr "在網站上找不到主題。" + +msgid "No themes found." +msgstr "找不到佈景主題。" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "沒有" + +msgid "Normal" +msgstr "一般" + +msgid "Not Initialized" +msgstr "尚未初始化" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "不是Wii或GameCube的光碟" + +msgid "Not a valid URL" +msgstr "不是有效的網址" + +msgid "Not a valid URL path" +msgstr "不是有效的網址路徑" + +msgid "Not a valid domain" +msgstr "不是有效的網域" + +msgid "Not enough free memory." +msgstr "剩餘記憶體不足。" + +msgid "Not enough free space on device." +msgstr "裝置上剩餘空間不足" + +msgid "Not enough free space!" +msgstr "剩餘空間不足!" + +msgid "Not enough memory for FST." +msgstr "FST 剩餘記憶體不足" + +msgid "Not enough memory." +msgstr "記憶體不足。" + +msgid "Not required" +msgstr "不需要" + +msgid "Not supported format!" +msgstr "未支援的格式!" + +msgid "Nothing selected to delete." +msgstr "未選擇刪除任何項目" + +msgid "Nothing selected to install." +msgstr "未選擇安裝任何項目" + +msgid "Nov" +msgstr "十一月" + +msgid "OFF" +msgstr "關閉" + +msgid "OK" +msgstr "確定" + +msgid "ON" +msgstr "開啟" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "系統睡眠主題" + +msgid "Ocarina" +msgstr "金手指" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "十月" + +msgid "Official Site:" +msgstr "官方網址:" + +msgid "Offset" +msgstr "偏移" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "僅遊戲分區" + +msgid "Only for Install" +msgstr "安裝遊戲時" + +msgid "Original" +msgstr "原始" + +msgid "Original/Customs" +msgstr "原始/自製" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "親子控制" + +msgid "Partial" +msgstr "部分的" + +msgid "Partition" +msgstr "分區" + +msgid "Password" +msgstr "密碼" + +msgid "Password Changed" +msgstr "密碼已變更" + +msgid "Password has been changed" +msgstr "密碼已被變更" + +msgid "Patch Country Strings" +msgstr "修改國別設定" + +msgid "Path Changed" +msgstr "路徑已變更" + +msgid "Permission denied." +msgstr "沒有權限。" + +msgid "Pick from a list" +msgstr "從清單中選取" + +msgid "Pixels" +msgstr "像素" + +msgid "Play Count" +msgstr "執行次數" + +msgid "Play Next" +msgstr "執行下一個" + +msgid "Play Once" +msgstr "播放一次" + +msgid "Play Previous" +msgstr "執行上一個" + +msgid "Playing Music:" +msgstr "播放音樂:" + +msgid "Please wait" +msgstr "請稍候" + +msgid "Please wait..." +msgstr "請稍候..." + +msgid "Power off the Wii" +msgstr "關閉 Wii 主機電源" + +msgid "Prev" +msgstr "往前" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "程序已完成。" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "顯示校正" + +msgid "Published by" +msgstr "出版商" + +msgid "Quick Boot" +msgstr "快速啟動" + +msgid "Random Directory Music" +msgstr "隨機選取音樂" + +msgid "Real Nand" +msgstr "真實的Nand" + +msgid "Receiving file from:" +msgstr "正在接收檔案來源:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "區碼修正" + +msgid "Released" +msgstr "發行" + +msgid "Reload SD" +msgstr "重新載入 SD 卡" + +msgid "Reloading game list now, please wait..." +msgstr "現在重新載入遊戲清單,請稍候..." + +msgid "Remember Unlock" +msgstr "儲存解鎖" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "移除更新" + +msgid "Rename Game Title" +msgstr "重新命名遊戲標題" + +msgid "Rename category" +msgstr "類別重新命名" + +msgid "Reset" +msgstr "重新啟動" + +msgid "Reset BG Music" +msgstr "重設背景音樂" + +msgid "Reset Playcounter" +msgstr "重設執行次數" + +msgid "Reset to default BGM?" +msgstr "重設為預設BGM嗎?" + +msgid "Restarting..." +msgstr "正在重新啟動..." + +msgid "Return" +msgstr "返回" + +msgid "Return To" +msgstr "返回到" + +msgid "Return to Wii Menu" +msgstr "返回 Wii 系統選單" + +msgid "Right" +msgstr "右" + +msgid "Rotating Disc" +msgstr "旋轉光碟" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "震動" + +msgid "SChinese" +msgstr "簡體中文" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "SD卡無法存取" + +msgid "SD GameCube Games Path" +msgstr "SD卡 GameCube遊戲路徑" + +msgid "SD GameCube Path" +msgstr "SD卡 GameCube路徑" + +msgid "SD Path" +msgstr "SD卡路徑" + +msgid "SFX Volume" +msgstr "音效音量" + +msgid "Save" +msgstr "儲存" + +msgid "Save Failed. No device inserted?" +msgstr "儲存失敗。沒有插入裝置?" + +msgid "Save Game List to" +msgstr "儲存遊戲清單至" + +msgid "Save List" +msgstr "儲存清單" + +msgid "Saved" +msgstr "已儲存" + +msgid "Savegame might not exist for this game." +msgstr "這個遊戲的遊戲存檔可能不存在。" + +msgid "Screensaver" +msgstr "螢幕保護" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "選取" + +msgid "Select DOL Offset" +msgstr "選取DOL補償" + +msgid "Select a DOL" +msgstr "選擇一個 DOL" + +msgid "Select a DOL from Game" +msgstr "從遊戲中選擇DOL" + +msgid "Select game categories" +msgstr "選擇遊戲類別" + +msgid "Select loader mode" +msgstr "選擇 loader 模式" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "選擇 titles 的來源。" + +msgid "Sept" +msgstr "九月" + +msgid "Set Search-Filter" +msgstr "關鍵字篩選" + +msgid "Settings" +msgstr "設定" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "顯示類別" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "顯示可用空間" + +msgid "Show Play Count" +msgstr "顯示遊戲執行次數" + +msgid "Show SD" +msgstr "顯示SD卡" + +msgid "Shutdown System" +msgstr "關閉系統" + +msgid "Shutdown Wii" +msgstr "關閉Wii主機" + +msgid "Skip Errors" +msgstr "略過錯誤" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "Sneek視訊修正" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "以字母順序排序" + +msgid "Sort by number of players" +msgstr "以玩家人數排序" + +msgid "Sort by rank" +msgstr "以等級排序" + +msgid "Sort order by most played" +msgstr "以執行次數排序" + +msgid "Sound" +msgstr "音效" + +msgid "Sound Settings" +msgstr "音效設定" + +msgid "Sound+BGM" +msgstr "音樂+音效" + +msgid "Sound+Quiet" +msgstr "音樂+靜音" + +msgid "Spanish" +msgstr "西班牙文" + +msgid "Special thanks to:" +msgstr "特別感謝:" + +msgid "Split each 2GB" +msgstr "每個分割為2GB" + +msgid "Split each 4GB" +msgstr "每個分割為4GB" + +msgid "Standby" +msgstr "待機" + +msgid "Start" +msgstr "開始" + +msgid "Success" +msgstr "成功" + +msgid "Success." +msgstr "成功。" + +msgid "Success:" +msgstr "成功:" + +msgid "Successfully Saved" +msgstr "已儲存成功" + +msgid "Successfully Updated" +msgstr "更新已完成" + +msgid "Successfully copied" +msgstr "複製已完成" + +msgid "Successfully deleted:" +msgstr "成功的刪除:" + +msgid "Successfully extracted theme." +msgstr "成功獲取主題。" + +msgid "Successfully installed:" +msgstr "成功安裝:" + +msgid "Successfully updated." +msgstr "更新已完成." + +msgid "Switching to channel list mode." +msgstr "正在切換頻道清單模式。" + +msgid "Sync FAT32 FS Info" +msgstr "同步FAT32檔案系統資訊" + +msgid "Synchronizing..." +msgstr "正在同步..." + +msgid "System Default" +msgstr "系統預設值" + +msgid "TChinese" +msgstr "繁體中文" + +msgid "TXT Cheatcodes Path" +msgstr "TXT 金手指檔案路徑" + +msgid "The .them file was not found in the zip." +msgstr "在zip檔中找不到主題檔.them" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "強制寬螢幕設定要求DIOS MIOS v2.1或更高版本。此設定將被忽略。" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "Miis將被提取到模擬nand及頻道的路徑. 注意: 所有存在的檔案將被覆寫" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "無須光碟加強版設定要求DIOS MIOS 2.2 更新版。此設定將被忽略。" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "SYSCONF檔將被提取到模擬nand及頻道的路徑. 注意: 所有存在的檔案將被覆寫" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "如果現在對SD卡做讀寫動作! 程式可能會中斷" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "所輸入的目錄不存在。是否要建立一個目錄嗎?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "遊戲存檔將被提取到模擬nand的存檔及頻道路徑. 注意: 所有存在的檔案將被覆寫" + +msgid "The game is on SD Card." +msgstr "此遊戲在SD卡上。" + +msgid "The game is on USB." +msgstr "此遊戲在USB上。" + +msgid "The save game will be extracted to your emu nand path." +msgstr "遊戲存檔將被提取到模擬 nand 路徑內。" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "遊戲存檔將被提取到模擬nand的存檔及頻道路徑內. 注意: 所有存在的檔案將被覆寫" + +msgid "The wad file was installed" +msgstr "wad檔已安裝" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "wad安裝失敗錯誤 %i" + +msgid "Theme Downloader" +msgstr "佈景主題下載" + +msgid "Theme Menu" +msgstr "佈景主題選單" + +msgid "Theme Path" +msgstr "佈景主題路徑" + +msgid "Theme Title:" +msgstr "佈景主題標題" + +msgid "Themes by www.spiffy360.com" +msgstr "佈景主題由www.spiffy360.com提供" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "這IOS是BootMii的ios。若你確定不是BootMii的IOS而你在這安裝其他的程式,請忽略這警告。" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "標題清單找不到這IOS。若你確定已安裝它,請忽略這警告。" + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "此遊戲為多重光碟。請選擇光碟啟動。" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "此路徑必須是在SD卡上!" + +msgid "Time left:" +msgstr "剩餘時間:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "系統頻道" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "從GameTDB顯示遊戲名稱" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "用光碟執行GameCube遊戲,你需在遊戲設定中設定GameCube 模式為MIOS。" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "提示訊息 延遲時間" + +msgid "Tooltips" +msgstr "提示訊息" + +msgid "Transfer failed" +msgstr "傳輸失敗" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX 被上鎖保護" + +msgid "USB Port" +msgstr "USB 連接埠" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "USB連接埠變更僅Hermes cIOS支援。" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "移除" + +msgid "Uninstall Game" +msgstr "移除遊戲" + +msgid "Uninstall Menu" +msgstr "移除選單" + +msgid "Uninstall all" +msgstr "移除全部" + +msgid "Unknown" +msgstr "未知的" + +msgid "Unlock USB Loader GX" +msgstr "USB Loader GX解鎖" + +msgid "Unlocked" +msgstr "已解鎖" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "不支援格式,請嘗試手動提取TempTheme.zip。" + +msgid "Update" +msgstr "更新" + +msgid "Update All" +msgstr "更新所有檔案" + +msgid "Update DOL" +msgstr "僅更新主程式" + +msgid "Update Files" +msgstr "更新檔案" + +msgid "Update Path" +msgstr "更新路徑" + +msgid "Update all Language Files" +msgstr "更新所有語言檔案" + +msgid "Update failed" +msgstr "更新失敗" + +msgid "Update successfull" +msgstr "更新成功" + +msgid "Updating Language Files:" +msgstr "正在更新語言檔案:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "已更新安裝在Homebrew目錄的ZIP檔案" + +msgid "Use System Font" +msgstr "使用系統字型" + +msgid "Use global" +msgstr "預設" + +msgid "VBI (Default)" +msgstr "VBI (預設)" + +msgid "VIDTV Patch" +msgstr "VIDTV 修改" + +msgid "Version:" +msgstr "版本:" + +#, c-format +msgid "Version: %s" +msgstr "版本: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "視訊格式" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "虛擬指針的速度" + +msgid "WDM Files Path" +msgstr "WDM檔案路徑" + +msgid "WIP Patches Path" +msgstr "WIP 修正檔路徑" + +msgid "Waiting..." +msgstr "等待中..." + +msgid "Warning" +msgstr "警告" + +msgid "Warning:" +msgstr "警告:" + +msgid "What do you want to do?" +msgstr "要做什麼?" + +msgid "What do you want to update?" +msgstr "要更新什麼?" + +msgid "What should be deleted for this game title:" +msgstr "這遊戲title應刪除什麼:" + +msgid "What to extract from NAND?" +msgstr "從 NAND 提取什麼?" + +msgid "Where should the game be installed to?" +msgstr "遊戲應安裝到何處" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "WiFi功能設定" + +msgid "Widescreen Factor" +msgstr "寬螢幕倍數" + +msgid "Widescreen Fix" +msgstr "寬螢幕校正" + +msgid "Wii Games" +msgstr "Wii 遊戲" + +msgid "Wii Menu" +msgstr "Wii系統選單" + +msgid "Wii Settings" +msgstr "Wii主機設定" + +msgid "WiiTDB.xml" +msgstr "WiiTDB.xml" + +msgid "WiiTDB.xml is up to date." +msgstr "WiiTDB.xml保持最新。" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "Wii LED燈" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "Wiinnertag" + +msgid "Wiinnertag Path" +msgstr "Wiinnertag路徑" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "程式啟動時Wiinnertag要求能夠自動連接網路。現在是否要啟動它?" + +msgid "Wiird Debugger" +msgstr "Wiird 偵錯器" + +#, c-format +msgid "Write error on file: %s" +msgstr "檔案寫入失敗: %s" + +msgid "Writing GXGameCategories.xml" +msgstr "正在寫入 GXGameCategories.xml" + +msgid "Wrong Password" +msgstr "密碼錯誤" + +msgid "Yes" +msgstr "是" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "你嘗試用低於 cIOS 249 rev18版本去選取 FAT32/NTFS/EXT 磁區,無法支援。若繼續請自行承擔風險。" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "你可選擇或格式化磁區或使用頻道 loader 模式。" + +msgid "You cannot delete this category." +msgstr "無法刪除此類別。" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "你需安裝 DIOS MIOS Lite v1.2 或更新版本。" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "縮放間隔 (速度) " + +msgid "and translators for language files updates" +msgstr "及對所有語言檔更新的翻譯者" + +msgid "available" +msgstr "可取得" + +msgid "does not exist!" +msgstr "不存在!" + +msgid "does not exist! Loading game without cheats." +msgstr "不存在!載入遊戲時無法啟動金手指。" + +msgid "files left" +msgstr "剩下的檔案" + +msgid "for FAT/NTFS support" +msgstr "FAT/NTFS 格式支援" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "設置 GameTDB 與封面 / 光碟圖片檔案存放空間" + +msgid "for Ocarina" +msgstr "的 金手指" + +msgid "for diverse patches" +msgstr "的多種修正" + +msgid "for his awesome tool LibWiiGui" +msgstr "的優秀工具 LibWiiGui" + +msgid "for hosting the themes" +msgstr "主要的主題" + +msgid "for the USB Loader source" +msgstr "與釋出USB Loader原始碼" + +msgid "for their work on the wiki page" +msgstr "與他們在wiki網頁的付出" + +msgid "formatted!" +msgstr "完成格式化!" + +msgid "free" +msgstr "剩餘" + +msgid "ms" +msgstr "毫秒" + +msgid "not set" +msgstr "未設定" + +msgid "of" +msgstr "的" + +msgid "seconds left" +msgstr "剩餘秒數" + +#~ msgid "Install WAD to EmuNand" +#~ msgstr "安裝 WAD 到模擬Nand" + +#~ msgid "WAD Installation" +#~ msgstr "WAD 安裝" + +#~ msgid "GameTDB Path" +#~ msgstr "GameTDB 路徑" + +#~ msgid "Anti" +#~ msgstr "防止" + +#~ msgid "Error 002 fix" +#~ msgstr "修正002錯誤" + +#~ msgid "Use Game Settings" +#~ msgstr "使用遊戲設定" + +#~ msgid "Main tester:" +#~ msgstr "主要測試者:" + +#~ msgid "USB Device not found." +#~ msgstr "找不到 USB 裝置" + +#~ msgid "Boot/Standard" +#~ msgstr "啟動/標準" + +#~ msgid "DEVO LED Activity" +#~ msgstr "DEVO LED燈 開啟" + +#~ msgid "DEVO MemCard Emulation" +#~ msgstr "DEVO 記憶卡模擬" + +#~ msgid "DML Auto" +#~ msgstr "DML 自動" + +#~ msgid "DML Debug" +#~ msgstr "DML除錯" + +#~ msgid "DML Force Widescreen" +#~ msgstr "DML 強制寬螢幕" + +#~ msgid "DML Japanese Patch" +#~ msgstr "DML 日文修正" + +#~ msgid "DML LED Activity" +#~ msgstr "DML LED燈 開啟" + +#~ msgid "DML NMM Mode" +#~ msgstr "DML 無需記憶卡模式" + +#~ msgid "DML No Disc+" +#~ msgstr "DML 無需光碟加強模式" + +#~ msgid "DML None" +#~ msgstr "無 DML模式" + +#~ msgid "DML PAD Hook" +#~ msgstr "DML PAD 掛載" + +#~ msgid "DML Progressive Patch" +#~ msgstr "DML 漸進式訊號修正" + +#~ msgid "DML Screenshot" +#~ msgstr "DML 螢幕截圖" + +#~ msgid "DML Video Mode" +#~ msgstr "DML 視訊模式" + +#~ msgid "To run GameCube games with DIOS MIOS you need to place them on an USB FAT32 partition." +#~ msgstr "用DIOS MIOS執行GameCube遊戲,你需放置遊戲在USB FAT32格式分割磁區。" + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' on a primary partition." +#~ msgstr "用DIOS MIOS執行GameCube遊戲,你需設定主要GameCube路徑在主要磁區。" + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' on the first partition of the Hard Drive." +#~ msgstr "用DIOS MIOS執行GameCube遊戲,你需設定主要GameCube路徑在硬碟的第一磁區。" + +#~ msgid "To run GameCube games with DIOS MIOS you need to set your 'Main GameCube Path' to an USB FAT32 partition." +#~ msgstr "用DIOS MIOS執行GameCube遊戲,你需設置「主要GameCube路徑」至USB FAT32格式分割磁區。" + +#~ msgid "To run GameCube games with DIOS MIOS you need to use a 512 bytes/sector Hard Drive." +#~ msgstr "用DIOS MIOS執行GameCube遊戲,你需使用硬碟的磁區為512位元組。" + +#~ msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Path." +#~ msgstr "用Devolution執行GameCube遊戲,你需在Devolution 路徑中放置loader.bin檔。" + +#~ msgid "You need to install Devolution or DIOS MIOS (Lite) to launch GameCube games from USB or SD card" +#~ msgstr "從USB裝置或SD卡啟動 GameCube 遊戲,需安裝 Devolution 或 DIOS MIOS (Lite)程式" + +#~ msgid "DML No Disc" +#~ msgstr "DML 無需光碟模式" + +#~ msgid "The No Disc setting is not used anymore by DIOS MIOS (Lite). Now you need to place a disc in your drive." +#~ msgstr "DIOS MIOS (Lite)的無需光碟設定不再被使用。現在需放置一片光碟到主機內。" + +#~ msgid "You need to install DIOS MIOS to run GameCube games from USB or DIOS MIOS Lite to run them from SD card" +#~ msgstr "你需安裝DIOS MIOS從USB裝置執行GameCube遊戲或安裝DIOS MIOS Lite從SD卡執行GameCube遊戲" + +#~ msgid "Custom Discarts" +#~ msgstr "自製光碟圖片" + +#~ msgid "Full HQ Covers" +#~ msgstr "完整高畫質封面" + +#~ msgid "Full LQ Covers" +#~ msgstr "完整低畫質封面" + +#~ msgid "Original Discarts" +#~ msgstr "原始光碟圖片" + +#~ msgid "GC Force Interlace" +#~ msgstr "GC 強制交錯" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "WBFS上的遊戲重新命名" + +#~ msgid "Do you want to discart changes?" +#~ msgstr "是否要放棄變更?" diff --git a/Languages/thai.lang b/Languages/thai.lang new file mode 100644 index 0000000..f06a9c3 --- /dev/null +++ b/Languages/thai.lang @@ -0,0 +1,2871 @@ +# USB Loader GX language source file. +# thai.lang - r826 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:05+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: Nitro_subzero \n" +"Language-Team: Nitro_subzero\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " ไม่สามารถดาวน์โหลดได้" + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " ถูกบันทึกแล้ว ข้อความยังไม่ถูกตรวจสอบ บางส่วนของโค๊ดอาจไม่สามารถทำงานได้ ถ้าคุณพบปัญหา เปิดโปรแกรมแก้ไขข้อความ เพื่อข้อมูลเพิ่มเติม." + +msgid " is not on the server." +msgstr " ไม่อยู่บนแม่ข่าย" + +#, c-format +msgid "%i files not found on the server!" +msgstr "" + +#, c-format +msgid "%i missing files" +msgstr "" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (ทุกคน)" + +msgid "1 (Child 7+)" +msgstr "1 (เด็ก 7+)" + +msgid "1 hour" +msgstr "1 ชม." + +msgid "10 min" +msgstr "10 นาที" + +msgid "2 (Teen 12+)" +msgstr "2 (วัยรุ่น 12+)" + +msgid "20 min" +msgstr "20 นาที" + +msgid "2D Cover Path" +msgstr "ที่เก็บ ปก 2D" + +msgid "3 (Mature 16+)" +msgstr "3 (เต็มวัย 16+)" + +msgid "3 min" +msgstr "3 นาที" + +msgid "30 min" +msgstr "30 นาที" + +msgid "3D Cover Path" +msgstr "ที่เก็บ ปก 3D" + +msgid "3D Covers" +msgstr "หน้าปก 3D" + +msgid "4 (Adults Only 18+)" +msgstr "4 (เฉพาะผู้ใหญ่ 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 นาที" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "อัตโนมัติ" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "" + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "" + +msgid "All Partitions" +msgstr "" + +msgid "All files extracted." +msgstr "" + +msgid "All images downloaded successfully." +msgstr "" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "ความสามารถทั้งหมดของ USB Loader GX ถูกเปิดให้ใช้." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "เปลี่ยน DOL " + +msgid "An example file was created here:" +msgstr "" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "ภาษาของโปรแกรม" + +msgid "Apply" +msgstr "" + +msgid "Apr" +msgstr "เมษ." + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "" + +msgid "Are you sure?" +msgstr "แน่ใจหรือไม่ ?" + +msgid "Aspect Ratio" +msgstr "" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "สค." + +msgid "Author(s):" +msgstr "" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "ทำการเชื่อมต่อเครือข่าย" + +msgid "BCA Codes Path" +msgstr "" + +msgid "Back" +msgstr "ย้อนกลับ" + +msgid "Back to HBC or Wii Menu" +msgstr "กลับไป HBC หรือ เมนู Wii" + +msgid "Backgroundmusic" +msgstr "ดนตรีเบื้องหลัง" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "ขอขอบคุณ:" + +msgid "Block Categories Menu" +msgstr "" + +msgid "Block Categories Modify" +msgstr "" + +msgid "Block Cover Downloads" +msgstr "" + +msgid "Block Custom Paths" +msgstr "" + +msgid "Block Feature Settings" +msgstr "" + +msgid "Block Game Install" +msgstr "" + +msgid "Block Game Settings" +msgstr "" + +msgid "Block GameID Change" +msgstr "" + +msgid "Block Global Settings" +msgstr "" + +msgid "Block Gui Settings" +msgstr "" + +msgid "Block HBC Menu" +msgstr "" + +msgid "Block Hard Drive Settings" +msgstr "" + +msgid "Block IOS Reload" +msgstr "โหลดบล๊อค IOS อีกครั้ง" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "" + +msgid "Block Parental Settings" +msgstr "" + +msgid "Block Priiloader Override" +msgstr "" + +msgid "Block Reset Settings" +msgstr "" + +msgid "Block SD Reload Button" +msgstr "" + +msgid "Block Sound Settings" +msgstr "" + +msgid "Block Theme Downloader" +msgstr "" + +msgid "Block Theme Menu" +msgstr "" + +msgid "Block Title Launcher" +msgstr "" + +msgid "Block Updates" +msgstr "" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "บูต?" + +msgid "Both" +msgstr "ทั้งคู่" + +msgid "Both Ports" +msgstr "" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "" + +msgid "Can't be formatted" +msgstr "ไม่สามารถฟอร์แมตได้" + +msgid "Can't create directory" +msgstr "ไม่สามารถสร้างไดเรคทอรี่ได้" + +#, c-format +msgid "Can't create file: %s" +msgstr "" + +#, c-format +msgid "Can't create path: %s" +msgstr "" + +msgid "Can't delete:" +msgstr "ไม่สามารถลบได้:" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "" + +#, c-format +msgid "Can't read file: %s" +msgstr "" + +msgid "Cancel" +msgstr "ยกเลิก" + +msgid "Cannot write to destination." +msgstr "" + +msgid "Categories" +msgstr "" + +msgid "Categories:" +msgstr "" + +msgid "Change Play Path" +msgstr "" + +msgid "Channel Launcher" +msgstr "" + +msgid "Channels" +msgstr "แชนแนล" + +msgid "Cheatfile is blank" +msgstr "ไฟล์สูตรโกง ว่างเปล่า" + +msgid "Clear" +msgstr "" + +msgid "Click to Download Covers" +msgstr "กดเพื่อดาวน์โหลดหน้าปก" + +msgid "Click to change game ID" +msgstr "กดเพื่อเปลี่ยน ID เกมส์" + +msgid "Clock" +msgstr "นาฬิกา" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "ปิด" + +msgid "Code Download" +msgstr "ดาวน์โหลดโค๊ด" + +#, c-format +msgid "Coded by: %s" +msgstr "โค๊ดโดย: %s" + +msgid "Coding:" +msgstr "โค๊ด:" + +msgid "Connection to server timed out." +msgstr "" + +msgid "Console" +msgstr "คอนโซล" + +msgid "Console Default" +msgstr "ค่าตั้งต้นของคอนโซล" + +msgid "Console Locked" +msgstr "คอนโซลถูกล๊อค" + +msgid "Console must be unlocked for this option." +msgstr "" + +msgid "Console must be unlocked to be able to use this." +msgstr "" + +msgid "Console should be unlocked to modify it." +msgstr "ปลดล๊อคคอนโซลก่อน ถึงจะทำการเปลี่ยนแปลงได้" + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "ทำต่อ เพื่อติดตั้งเกมส์?" + +msgid "Continue?" +msgstr "" + +msgid "Controllevel" +msgstr "ระดับการควบคุม" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "รหัสผ่านถูกต้อง" + +msgid "Could not connect to the server." +msgstr "" + +msgid "Could not create GCT file" +msgstr "ไม่สามารถสร้างไฟล์ GCT" + +#, c-format +msgid "Could not create path: %s" +msgstr "" + +msgid "Could not extract files for:" +msgstr "" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "" + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "ไม่สามารถเปิดใช้โมดูล DIP ได้ !" + +msgid "Could not initialize network!" +msgstr "ไม่สามารถเชื่อมต่อกับเครือข่ายได้ !" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "เปิดจากแผ่นไม่ได้ !" + +msgid "Could not open the WiiTDB.xml file." +msgstr "" + +msgid "Could not open wiitdb.xml." +msgstr "" + +msgid "Could not save." +msgstr "บันทึกไม่ได้" + +msgid "Could not write file." +msgstr "" + +msgid "Could not write to:" +msgstr "" + +msgid "Cover Download" +msgstr "ดาวน์โหลดปก" + +msgid "Create" +msgstr "สร้าง" + +msgid "Credits" +msgstr "เครดิต" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "กำหนด ที่เก็บ" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "กำหนดเอง/ดั้งเดิม" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "ที่เก็บ DOL" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "ธค." + +msgid "Default" +msgstr "ค่าแรกกำหนด" + +msgid "Default Gamesettings" +msgstr "ค่าแรกกำหนด" + +msgid "Default Settings" +msgstr "ค่าแรกกำหนด" + +msgid "Delete" +msgstr "ลบ" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "ลบไฟล์โกงเกมส์" + +msgid "Delete Cheat TXT" +msgstr "ลบ Cheat TXT" + +msgid "Delete Cover Artwork" +msgstr "ลบ ภาพกล่อง" + +msgid "Delete Disc Artwork" +msgstr "ลบ ภาพแผ่น" + +msgid "Delete category" +msgstr "" + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "ออกแบบ:" + +msgid "Details" +msgstr "" + +msgid "Developed by" +msgstr "พัฒนาโดย " + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "ไม่พบไดเรคทอรี่นี้ !" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "ดาวน์โหลดภาพแผ่น" + +msgid "Disc Artwork Path" +msgstr "ที่เก็บ ภาพแผ่น" + +msgid "Disc Default" +msgstr "ค่าตั้งต้นแผ่น" + +msgid "Disc Insert Detected" +msgstr "" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "สลับด้านแผ่น" + +msgid "Display" +msgstr "การแสดงผล" + +msgid "Display as a carousel" +msgstr "แสดงผลแบบ ม้าหมุน" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "แสดงผลแบบ ตาราง" + +msgid "Display as a list" +msgstr "แสดงผลแบบ รายการ" + +msgid "Display favorites only" +msgstr "" + +msgid "Do you want to apply it now?" +msgstr "" + +msgid "Do you want to apply this theme?" +msgstr "" + +msgid "Do you want to change language?" +msgstr "ต้องการจะเปลี่ยนภาษา ?" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "ต้องการดาวน์โหลดธีมนี้ ?" + +msgid "Do you want to extract all the save games?" +msgstr "" + +msgid "Do you want to extract the save game?" +msgstr "" + +msgid "Do you want to format:" +msgstr "ต้องการฟอร์แมต:" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "" + +msgid "Do you wish to update/download all language files?" +msgstr "ต้องการอัพเดทหรือดาวน์โหลด ไฟล์ภาษา ทั้งหมด?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "ดาวน์โหลด" + +msgid "Download Now" +msgstr "เริ่มการดาวน์โหลด" + +msgid "Download finished" +msgstr "ดาวน์โหลดเสร็จแล้ว" + +msgid "Downloading 3D Covers" +msgstr "" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "" + +msgid "Downloading Full HQ Covers" +msgstr "" + +msgid "Downloading Full LQ Covers" +msgstr "" + +msgid "Downloading custom Discarts" +msgstr "" + +msgid "Downloading file..." +msgstr "" + +msgid "Downloading image:" +msgstr "ภาพที่กำลังดาวน์โหลด:" + +msgid "Downloading original Discarts" +msgstr "" + +msgid "Downloading pagelist:" +msgstr "" + +msgid "Dump NAND to EmuNand" +msgstr "" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "เนเธอร์แลนด์" + +msgid "ERROR" +msgstr "ผิดพลาด" + +msgid "ERROR:" +msgstr "ผิดพลาด:" + +msgid "ERROR: Can't set up theme." +msgstr "" + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "" + +msgid "Emulated Nand" +msgstr "" + +msgid "English" +msgstr "อังกฤษ" + +msgid "Enter Path" +msgstr "" + +msgid "Error" +msgstr "ผิดพลาด" + +msgid "Error !" +msgstr "ผิดพลาด !" + +#, c-format +msgid "Error creating path: %s" +msgstr "" + +msgid "Error opening downloaded file" +msgstr "" + +msgid "Error reading Disc" +msgstr "อ่านแผ่นไม่ได้" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "" + +msgid "Error while downloding file" +msgstr "" + +msgid "Error while opening the zip." +msgstr "" + +msgid "Error while transfering data." +msgstr "ผิดพลาดขณะรับส่งข้อมูล" + +msgid "Error while updating USB Loader GX." +msgstr "" + +msgid "Error writing the data." +msgstr "" + +msgid "Error:" +msgstr "ผิดพลาด:" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "" + +msgid "Everything" +msgstr "" + +msgid "Exit" +msgstr "" + +msgid "Exit to where?" +msgstr "" + +msgid "Export All Saves to EmuNand" +msgstr "" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "" + +msgid "Extracting file:" +msgstr "" + +msgid "Extracting files..." +msgstr "กำลังขยายไฟล์..." + +msgid "Extracting files:" +msgstr "" + +msgid "Extracting nand files:" +msgstr "" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "ฟอร์แมตไม่ได้" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "" + +msgid "Failed to extract." +msgstr "ขยายไฟล์ไม่ได้" + +msgid "Failed to initialize the USB storage device." +msgstr "" + +msgid "Failed to open partition" +msgstr "ไม่สามารถเข้าถึงพาร์ทิชั่นได้" + +msgid "Failed to read ticket." +msgstr "" + +msgid "Failed to read tmd file." +msgstr "" + +msgid "Failed to read wad header." +msgstr "" + +msgid "Failed updating" +msgstr "" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "" + +msgid "Features Settings" +msgstr "" + +msgid "Feb" +msgstr "กพ." + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "ไม่พบไฟล์" + +msgid "File read/write error." +msgstr "" + +msgid "Files extracted successfully." +msgstr "" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "" + +msgid "Filesize is 0 Byte." +msgstr "" + +msgid "Flat Covers" +msgstr "" + +msgid "Flip-X" +msgstr "กลับ-X" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "" + +msgid "Force NTSC480p" +msgstr "" + +msgid "Force PAL480p" +msgstr "" + +msgid "Force PAL50" +msgstr "" + +msgid "Force PAL60" +msgstr "" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "ฟอร์แมต" + +msgid "Formatting, please wait..." +msgstr "กำลังฟอร์แมต,รอสักครู่..." + +msgid "Found missing images." +msgstr "" + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "พื้นที่ว่าง" + +msgid "French" +msgstr "ฝรั่งเศส" + +msgid "Full" +msgstr "" + +msgid "Full Cover Path" +msgstr "" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "" + +msgid "GAMEID_Gamename" +msgstr "" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "ที่เก็บ สูตรโกง" + +msgid "GCT File created" +msgstr "ไฟล์ GCT ถูกสร้าง" + +msgid "GUI Settings" +msgstr "ปรับแต่งหน้าจอ" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "เกมส์ ID" + +msgid "Game IOS" +msgstr "" + +msgid "Game Language" +msgstr "ภาษาเกมส์" + +msgid "Game Load" +msgstr "โหลดเกมส์" + +msgid "Game Lock" +msgstr "" + +msgid "Game Only" +msgstr "" + +msgid "Game Region" +msgstr "โซนของเกมส์" + +msgid "Game Size" +msgstr "ขนาดของเกมส์" + +msgid "Game Sound Mode" +msgstr "โหมดเสียงในเกมส์" + +msgid "Game Sound Volume" +msgstr "ระดับเสียงในเกมส์" + +msgid "Game Split Size" +msgstr "" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "เกมส์นี้ถูกติดตั้งอยู่แล้ว:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "" + +msgid "Games" +msgstr "เกมส์" + +msgid "Generating GXGameCategories.xml" +msgstr "" + +msgid "Genre:" +msgstr "" + +msgid "German" +msgstr "เยอรมัน" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "เมนู HOME" + +msgid "Hard Drive Settings" +msgstr "" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "ที่เก็บโปรแกรม Homebrew" + +msgid "Homebrew Channel" +msgstr "" + +msgid "Homebrew Launcher" +msgstr "Homebrew Launcher" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "ชั่วโมง" + +msgid "How do you want to update?" +msgstr "ต้องการอัพเดทแบบไหน ?" + +msgid "How to Shutdown?" +msgstr "ต้องการปิดแบบไหน ?" + +msgid "Import Categories" +msgstr "" + +msgid "Import operation successfully completed." +msgstr "" + +msgid "Importing categories" +msgstr "" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "ดาวน์โหลดไฟล์ %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "ดาวน์โหลดไฟล์ %0.2fMB" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "เชื่อมต่อเครือข่าย" + +msgid "Insert Disk" +msgstr "ใส่แผ่น" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "ติดตั้ง" + +msgid "Install Canceled" +msgstr "" + +msgid "Install Directories" +msgstr "" + +msgid "Install Error!" +msgstr "ผิดพลาดขณะติดตั้ง!" + +msgid "Install Partitions" +msgstr "" + +msgid "Install a game" +msgstr "ติดตั้งเกมส์" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "" + +msgid "Installing game:" +msgstr "กำลังติดตั้งเกมส์:" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "ดูเหมือนว่าคุณมีข้อมูลที่จำเป็นต่อการพัฒนาโปรแกรม กรุณาส่งข้อมูลนั้นให้ทีมพัฒนาด้วย." + +msgid "Italian" +msgstr "อิตาลี" + +msgid "Jan" +msgstr "มค." + +msgid "Japanese" +msgstr "ญี่ปุ่น" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "กค." + +msgid "June" +msgstr "มิย." + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "แป้นพิมพ์" + +msgid "Korean" +msgstr "เกาหลี" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "" + +msgid "Language change:" +msgstr "เปลี่ยนภาษา:" + +msgid "Languagefiles Path" +msgstr "" + +msgid "Languagepath changed." +msgstr "ที่เก็บไฟล์ภาษาถูกเปลี่ยนแปลง" + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Left" +msgstr "ซ้าย" + +msgid "Like SysMenu" +msgstr "คล้าย SysMenu" + +msgid "List on Gamelaunch" +msgstr "" + +msgid "Load" +msgstr "โหลด" + +msgid "Load From SD/USB" +msgstr "โหลดจาก SD/USB" + +#, c-format +msgid "Load file from: %s ?" +msgstr "โหลดไฟล์จาก: %s ?" + +msgid "Load this DOL as alternate DOL?" +msgstr "โหลด DOL นี้เป็น alternate DOL?" + +msgid "Loader Settings" +msgstr "" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "โหลดภาษามาตราฐาน." + +msgid "Loading standard music." +msgstr "โหลดเพลงมาตราฐาน" + +msgid "Lock Console" +msgstr "ล๊อค Console" + +msgid "Lock USB Loader GX" +msgstr "" + +msgid "Locked" +msgstr "ล๊อค" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "" + +msgid "Loop Music" +msgstr "" + +msgid "Loop Sound" +msgstr "เล่นเสียงซ้ำ" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "มีค." + +msgid "Mark new games" +msgstr "" + +msgid "May" +msgstr "พค." + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "" + +msgid "Motion+ Video" +msgstr "" + +msgid "Mount DVD drive" +msgstr "เชื่อม DVD ไดร์ฟ" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "" + +msgid "Music Loop Mode" +msgstr "" + +msgid "Music Volume" +msgstr "ความดังเสียงเพลง" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "" + +msgid "Nand Channels" +msgstr "" + +msgid "Nand Emu Channel Path" +msgstr "" + +msgid "Nand Emu Path" +msgstr "" + +msgid "Nand Emulation" +msgstr "" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "ไม่ทั้งสอง" + +msgid "Network is not initiated." +msgstr "" + +msgid "Next" +msgstr "ต่อไป" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "ไม่" + +msgid "No Cheatfile found" +msgstr "ไม่พบไฟล์โกงเกมส์" + +msgid "No DOL file found on disc." +msgstr "ไม่มีไฟล์ DOL ในแผ่น" + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "" + +msgid "No URL or Path specified." +msgstr "" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "ไม่มีข้อมูลที่อ่านไม่ได้" + +msgid "No disc inserted." +msgstr "" + +msgid "No favorites selected." +msgstr "" + +msgid "No file missing!" +msgstr "ไม่มีไฟล์ที่หายไป" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "" + +msgid "No new updates." +msgstr "ไม่มีไฟล์ Update ตัวใหม่" + +msgid "No themes found on the site." +msgstr "ไม่พบธีมบนเวบไซต์" + +msgid "No themes found." +msgstr "" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "" + +msgid "Normal" +msgstr "ปกติ" + +msgid "Not Initialized" +msgstr "" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "" + +msgid "Not a valid URL path" +msgstr "" + +msgid "Not a valid domain" +msgstr "" + +msgid "Not enough free memory." +msgstr "มีหน่วยความจำเหลือไม่พอ" + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "มีที่ว่างเหลือไม่พอ !" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "" + +msgid "Not required" +msgstr "" + +msgid "Not supported format!" +msgstr "ไม่รองรับรูปแบบไฟล์นี้" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "พย." + +msgid "OFF" +msgstr "ปิด" + +msgid "OK" +msgstr "ตกลง" + +msgid "ON" +msgstr "เปิด" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "ตค." + +msgid "Official Site:" +msgstr "เวบไซต์อย่างเป็นทางการ:" + +msgid "Offset" +msgstr "" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "" + +msgid "Only for Install" +msgstr "เฉพาะติดตั้งเท่านั้น" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "ของแท้/ดัดแปลง" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "กำหนดอายุ" + +msgid "Partial" +msgstr "" + +msgid "Partition" +msgstr "พาร์ติชั่น" + +msgid "Password" +msgstr "รหัสผ่าน" + +msgid "Password Changed" +msgstr "รหัสผ่านถูกเปลี่ยนแปลง" + +msgid "Password has been changed" +msgstr "รหัสผ่านถูกเปลี่ยนแปลง" + +msgid "Patch Country Strings" +msgstr "แก้อักขระประเทศ" + +msgid "Path Changed" +msgstr "" + +msgid "Permission denied." +msgstr "" + +msgid "Pick from a list" +msgstr "เลือกจากรายการ" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "จำนวนที่เล่น" + +msgid "Play Next" +msgstr "" + +msgid "Play Once" +msgstr "" + +msgid "Play Previous" +msgstr "" + +msgid "Playing Music:" +msgstr "" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "รอสักครู่" + +msgid "Power off the Wii" +msgstr "ปิดเครื่อง Wii" + +msgid "Prev" +msgstr "ที่ผ่านมา" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "ปุ่มเตรียมตัว" + +msgid "Published by" +msgstr "เผยแพร่โดย" + +msgid "Quick Boot" +msgstr "บูตแบบเร็ว" + +msgid "Random Directory Music" +msgstr "" + +msgid "Real Nand" +msgstr "" + +msgid "Receiving file from:" +msgstr "ได้รับไฟล์จาก:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "" + +msgid "Released" +msgstr "ปล่อย" + +msgid "Reload SD" +msgstr "โหลด SD ใหม่" + +msgid "Reloading game list now, please wait..." +msgstr "" + +msgid "Remember Unlock" +msgstr "" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "" + +msgid "Rename Game Title" +msgstr "" + +msgid "Rename category" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Reset BG Music" +msgstr "" + +msgid "Reset Playcounter" +msgstr "เคลียร์การนับจำนวนที่เล่น" + +msgid "Reset to default BGM?" +msgstr "" + +msgid "Restarting..." +msgstr "รีสตารท์..." + +msgid "Return" +msgstr "กลับ" + +msgid "Return To" +msgstr "" + +msgid "Return to Wii Menu" +msgstr "กลับไปที่เมนู Wii" + +msgid "Right" +msgstr "ขวา" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "สั่น" + +msgid "SChinese" +msgstr "จีน" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "ความดังของ SFX" + +msgid "Save" +msgstr "บันทึก" + +msgid "Save Failed. No device inserted?" +msgstr "" + +msgid "Save Game List to" +msgstr "บันทึกรายชื่อเกมส์ไปที่" + +msgid "Save List" +msgstr "" + +msgid "Saved" +msgstr "บันทึกแล้ว" + +msgid "Savegame might not exist for this game." +msgstr "" + +msgid "Screensaver" +msgstr "รักษาหน้าจอ" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "" + +msgid "Select DOL Offset" +msgstr "" + +msgid "Select a DOL" +msgstr "เลือก DOL" + +msgid "Select a DOL from Game" +msgstr "" + +msgid "Select game categories" +msgstr "" + +msgid "Select loader mode" +msgstr "" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "" + +msgid "Sept" +msgstr "กย." + +msgid "Set Search-Filter" +msgstr "กำหนดเงื่อนไขการค้นหา" + +msgid "Settings" +msgstr "กำหนดค่า" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "" + +msgid "Show Play Count" +msgstr "" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "ปิดระบบ" + +msgid "Shutdown Wii" +msgstr "" + +msgid "Skip Errors" +msgstr "" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "เรียงตามตัวอักษร" + +msgid "Sort by number of players" +msgstr "" + +msgid "Sort by rank" +msgstr "เรียงตามอันดับ" + +msgid "Sort order by most played" +msgstr "เรียงตามความถี่ในการเล่น" + +msgid "Sound" +msgstr "เสียง" + +msgid "Sound Settings" +msgstr "" + +msgid "Sound+BGM" +msgstr "เสียง+BGM" + +msgid "Sound+Quiet" +msgstr "เสียง+เงียบ" + +msgid "Spanish" +msgstr "สเปน" + +msgid "Special thanks to:" +msgstr "ขอขอบคุณอย่างสูง:" + +msgid "Split each 2GB" +msgstr "" + +msgid "Split each 4GB" +msgstr "" + +msgid "Standby" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "สำเร็จ" + +msgid "Success." +msgstr "" + +msgid "Success:" +msgstr "สำเร็จ:" + +msgid "Successfully Saved" +msgstr "บันทึกสำเร็จ" + +msgid "Successfully Updated" +msgstr "อัพเดทสำเร็จ" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "ลบสำเร็จ:" + +msgid "Successfully extracted theme." +msgstr "ขยายไฟล์ธีมสำเร็จ." + +msgid "Successfully installed:" +msgstr "ติดตั้งสำเร็จ:" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "" + +msgid "Sync FAT32 FS Info" +msgstr "" + +msgid "Synchronizing..." +msgstr "" + +msgid "System Default" +msgstr "ค่าเริ่มต้นของระบบ" + +msgid "TChinese" +msgstr "จีนโบราณ" + +msgid "TXT Cheatcodes Path" +msgstr "ที่เก็บ TXTCheatcodes" + +msgid "The .them file was not found in the zip." +msgstr "" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "ไม่พบไดเรคทอรี่นี้ ต้องการสร้างใหม่รึไม่ ?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "" + +msgid "Theme Downloader" +msgstr "ตัวช่วยดาวน์โหลดธีม" + +msgid "Theme Menu" +msgstr "" + +msgid "Theme Path" +msgstr "ที่อยู่ Theme" + +msgid "Theme Title:" +msgstr "ชื่อธีม:" + +msgid "Themes by www.spiffy360.com" +msgstr "" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "" + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "เหลือเวลาอีก:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Title Launcher" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "คำแนะนำ" + +msgid "Transfer failed" +msgstr "" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX 5 ถูกป้องกัน" + +msgid "USB Port" +msgstr "" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "ถอนการติดตั้ง" + +msgid "Uninstall Game" +msgstr "ถอนการติดตั้ง" + +msgid "Uninstall Menu" +msgstr "ถอนการติดตั้ง" + +msgid "Uninstall all" +msgstr "" + +msgid "Unknown" +msgstr "" + +msgid "Unlock USB Loader GX" +msgstr "" + +msgid "Unlocked" +msgstr "ปลดล๊อค" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "" + +msgid "Update" +msgstr "อัพเดท" + +msgid "Update All" +msgstr "อัทเดททั้งหมด" + +msgid "Update DOL" +msgstr "อัพเดท DOL" + +msgid "Update Files" +msgstr "อัพเดทไฟล์" + +msgid "Update Path" +msgstr "ที่อยู่ Update" + +msgid "Update all Language Files" +msgstr "อัพเดทภาษาทั้งหมด" + +msgid "Update failed" +msgstr "อัพเดทล้มเหลว" + +msgid "Update successfull" +msgstr "" + +msgid "Updating Language Files:" +msgstr "กำลังอัพเดทไฟล์ภาษา:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "อัพโหลดไฟล์ zip ไปที่ไดเรคทอรี่ homebrew" + +msgid "Use System Font" +msgstr "" + +msgid "Use global" +msgstr "" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "ปรับแก้ VIDTV" + +msgid "Version:" +msgstr "" + +#, c-format +msgid "Version: %s" +msgstr "เวอร์ชั่น: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "โหมดการแสดงผลภาพ" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "" + +msgid "WDM Files Path" +msgstr "" + +msgid "WIP Patches Path" +msgstr "" + +msgid "Waiting..." +msgstr "กำลังรอ..." + +msgid "Warning" +msgstr "" + +msgid "Warning:" +msgstr "" + +msgid "What do you want to do?" +msgstr "" + +msgid "What do you want to update?" +msgstr "คุณต้องการอัพเดทอะไร ?" + +msgid "What should be deleted for this game title:" +msgstr "" + +msgid "What to extract from NAND?" +msgstr "" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "ความสามารถของ Wi Fi" + +msgid "Widescreen Factor" +msgstr "" + +msgid "Widescreen Fix" +msgstr "จอกว้าง" + +msgid "Wii Games" +msgstr "" + +msgid "Wii Menu" +msgstr "เมนู Wii" + +msgid "Wii Settings" +msgstr "การปรับแต่ง Wii" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "ความสว่างของ Wii" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "" + +msgid "Wiird Debugger" +msgstr "" + +#, c-format +msgid "Write error on file: %s" +msgstr "" + +msgid "Writing GXGameCategories.xml" +msgstr "" + +msgid "Wrong Password" +msgstr "รหัสผ่านผิดพลาด" + +msgid "Yes" +msgstr "ใช่" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "" + +msgid "You cannot delete this category." +msgstr "" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "" + +msgid "available" +msgstr "ว่างอยู่" + +msgid "does not exist!" +msgstr "ไม่มี!" + +msgid "does not exist! Loading game without cheats." +msgstr "ไม่มี! โหลดเกมส์โดยไม่ใช้การโกงเกมส์." + +msgid "files left" +msgstr "ไฟล์ที่ยังเหลือ" + +msgid "for FAT/NTFS support" +msgstr "" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "" + +msgid "for Ocarina" +msgstr "สำหรับ Ocarina" + +msgid "for diverse patches" +msgstr "แก้ diverse" + +msgid "for his awesome tool LibWiiGui" +msgstr "สำหรับสุดยอด tool ของเค้า LibWiiGui" + +msgid "for hosting the themes" +msgstr "สำหรับให้ฝากธีม" + +msgid "for the USB Loader source" +msgstr "สำหรับรหัสโปรแกรม USB Loader" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "ฟอร์แมต!" + +msgid "free" +msgstr "ว่างอยู่" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "ไม่ได้กำหนด" + +msgid "of" +msgstr "จาก" + +msgid "seconds left" +msgstr "วินาทีที่เหลือ" + +#~ msgid "Anti" +#~ msgstr "ต้าน" + +#~ msgid "Error 002 fix" +#~ msgstr "แก้ไข Error002" + +#~ msgid "Boot/Standard" +#~ msgstr "บูต/มาตราฐาน" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "เปลี่ยนชื่อเกมส์บน WBFS" + +#~ msgid "for hosting the update files" +#~ msgstr "สำหรับที่เก็บไฟล์อัพเดท" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "ใส่แผ่น Wii !" + +#~ msgid "No cheats were selected" +#~ msgstr "ไม่ได้เลือกการโกงเกมส์ไว้" + +#~ msgid "Not a Wii Disc" +#~ msgstr "ไม่ใช่แผ่นเกมส์ Wii" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> ลบ Tickets..." + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> ลบ tickets...ผิดพลาด ! " + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> ลบ tickets...สำเร็จ ! " + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> ลบ Title...ผิดพลาด ! " + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> ลบ Title...สำเร็จ ! " + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> ลบเนื้อหา Title..." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> ลบเนื้อหา Title...ผิดพลาด ! " + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> ลบเนื้อหา Title...สำเร็จ ! " + +#~ msgid ">> Deleting title..." +#~ msgstr ">> ลบ Title..." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> ติดตั้งเสร็จแล้ว..." + +#~ msgid ">> Installing content #" +#~ msgstr ">> กำลังติดตั้ง เนื้อหา #" + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> กำลังติดตั้ง ticket..." + +#~ msgid ">> Installing title..." +#~ msgstr ">> กำลังติดตั้ง title..." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> กำลังอ่านข้อมูล WAD..." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> กำลังอ่านข้อมูล WAD...ผิดพลาด ! " + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> กำลังอ่านข้อมูล WAD...สำเร็จ !" + +#~ msgid "Done!" +#~ msgstr "เสร็จ!" + +#~ msgid "Error..." +#~ msgstr "ผิดพลาด..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "การติดตั้งเสร็จแล้ว !" + +#~ msgid "Installing content... Ok!" +#~ msgstr "ติดตั้งเนื้อหา... สำเร็จ!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "ติดตั้ง ticket... สำเร็จ!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "ติดตั้ง Title... สำเร็จ!" + +#~ msgid "Installing wad" +#~ msgstr "ติดตั้ง WAD" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "อ่านข้อมูล WAD... สำเร็จ!" + +#~ msgid "Uninstalling wad" +#~ msgstr "ถอนการติดตั้ง wad" + +#~ msgid "New Disc Detected" +#~ msgstr "พบแผ่นเกมส์ใหม่" + +#~ msgid "USB Device not found" +#~ msgstr "ไม่พบอุปกรณ์ USB" + +#~ msgid "Language File" +#~ msgstr "ไฟล์ภาษา" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "Title จาก WiiTDB" + +#~ msgid "WiiTDB Files" +#~ msgstr "ไฟล์ WiiTDB" + +#~ msgid "WiiTDB Path" +#~ msgstr "ที่อยู่ WiiTDB" + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "สำหรับ WiiTDB และ ปก/รูปแผ่นดิสก์" + +#~ msgid " Wad Saved as:" +#~ msgstr " บันทึก Wad เป็น:" + +#~ msgid "Delete ?" +#~ msgstr "ลบ ?" + +#~ msgid "Keep" +#~ msgstr "เก็บ" + +#~ msgid "Author:" +#~ msgstr "ผู้แต่ง:" + +#~ msgid "Download Boxart image?" +#~ msgstr "ดาวน์โหลดภาพกล่อง ?" + +#~ msgid "Download Discart image?" +#~ msgstr "ดาวน์โหลดภาพแผ่น ?" + +#~ msgid "Downloading file" +#~ msgstr "กำลังดาวน์โหลดไฟล์:" + +#~ msgid "Missing files" +#~ msgstr "ไฟล์ที่หาไม่พบ" + +#~ msgid "files not found on the server!" +#~ msgstr "ไม่พบไฟล์/i บนเซิฟเวอร์!" + +#~ msgid "Disc Images" +#~ msgstr "ภาพแผ่น" + +#~ msgid "Only Customs" +#~ msgstr "เฉพาะที่ดัดแปลง" + +#~ msgid "Only Original" +#~ msgstr "เฉพาะของแท้" + +#~ msgid "Do you really want to delete:" +#~ msgstr "ต้องการที่จะลบใช่ไหม:" + +#~ msgid "Do you want to use the alternate DOL that is known to be correct?" +#~ msgstr "ต้องการจะใช้ alt DOL เฉพาะที่รู้ว่าถูกต้อง?" + +#~ msgid "Unlock console to use this option." +#~ msgstr "ปลดล๊อค Console ก่อน เพื่อใช้ตัวเลือกนี้" + +#~ msgid "Full Shutdown" +#~ msgstr "ปิดอย่างสมบรูณ์" + +#~ msgid "If you don't have WiFi, press 1 to get an URL to get your WiiTDB.zip" +#~ msgstr "ถ้าไม่มี Wifi กด 1 เพื่อแสดง URL สำหรับดาวน์โหลด WiiTDB.zip" + +#~ msgid "Paste it into your browser to get your WiiTDB.zip." +#~ msgstr "วางในเวบบราวเซอร์เพื่อดึงข้อมูล WiiTDB.zip" + +#~ msgid "Shutdown to Idle" +#~ msgstr "เข้าโหมด Idle" + +#~ msgid "Your URL has been saved in %sWiiTDB_URL.txt." +#~ msgstr "URL ของคุณถูกบันทึกใน %sWiiTDB_URL.txt." + +#~ msgid "Can't create file" +#~ msgstr "สร้างไฟล์ไม่ได้" + +#~ msgid "Download failed." +#~ msgstr "ดาวน์โหลดไม่ได้" + +#~ msgid "Download request failed." +#~ msgstr "ดาวน์โหลดไม่ได้" + +#~ msgid "Downloading Page List:" +#~ msgstr "รายการที่กำลังดาวน์โหลด:" + +#~ msgid "Theme Download Path" +#~ msgstr "ตำแหน่งที่ดาวน์โหลดธีม" + +#~ msgid "Transfer failed." +#~ msgstr "ถ่ายโอนไม่ได้" + +#~ msgid "Unsupported format, try to extract manually." +#~ msgstr "ไม่สนับสนุนไฟล์นี้ ลองขยายไฟล์เอง" + +#~ msgid "and translaters for language files updates" +#~ msgstr "และผู้แปลภาษาสำหรับการอัพเดท" + +#~ msgid "Insert an SD-Card to save." +#~ msgstr "ใส่ SD card เพื่อบันทึก" + +#~ msgid "Insert an SD-Card to use this option." +#~ msgstr "ใส่ SD card เพื่อใช้ตัวเลือกนี้ " + +#~ msgid "No SD-Card inserted!" +#~ msgstr "ไม่ได้เสียบ SD card!" + +#~ msgid "Waiting for USB Device" +#~ msgstr "กำลังรออุปกรณ์ USB" + +#~ msgid "Back to Loader" +#~ msgstr "กลับไปที่ Loader" + +#~ msgid "An Error occured" +#~ msgstr "พบความผิดพลาด" + +#~ msgid "AutoPatch" +#~ msgstr "แก้ไขอัตโนมัติ" + +#~ msgid "Checking for Updates" +#~ msgstr "ตรวจสอบหาอัพเดท" + +#~ msgid "Downloading" +#~ msgstr "กำลังดาวน์โหลด" + +#~ msgid "The wad file was installed. But It could not be deleted from the SD card." +#~ msgstr "ไฟล์ Wad ถูกติดตั้งแล้ว แต่ไม่สามารถลบจาก SD card ได้" + +#~ msgid "The wad installation failed with error %ld" +#~ msgstr "การติดตั้งไฟล์ Wad ล้มเหลวด้วยข้อผิดพลาด %ld" + +#~ msgid "Unable to open the wad that was just downloaded (%s)." +#~ msgstr "ไม่สามารถเปิดไฟล์ Wad ที่เพิ่งดาวน์โหลดมาได้ (%s)." + +#~ msgid "Update to" +#~ msgstr "อัพเดทเป็น" + +#~ msgid "Updating" +#~ msgstr "กำลังอัพเดท" + +#~ msgid "Updating Language Files..." +#~ msgstr "กำลังอัพเดทไฟล์ภาษา..." + +#~ msgid "Updating WiiTDB.zip" +#~ msgstr "กำลังอัพเดทไฟล์ WiiTDB.zip" + +#~ msgid "%s : %s May not boot correctly if your System Menu is not up to date." +#~ msgstr "%s : %s อาจทำงานผิดปกติ ถ้าระบบของคุณไม่ทันสมัย" + +#~ msgid "Back to Wii Menu" +#~ msgstr "กลับไป เมนู Wii" + +#~ msgid "Checking existing artwork" +#~ msgstr "ตรวจหาอาร์ตเวิรค์" + +#~ msgid "Confirm" +#~ msgstr "ยืนยัน" + +#~ msgid "Could not find a WBFS partition." +#~ msgstr "ไม่พบ WBFS พาร์ติชั่น" + +#~ msgid "Could not open WBFS partition" +#~ msgstr "ไม่สามารถเปิด WBFS พาร์ติชั่นได้" + +#~ msgid "Could not read the disc." +#~ msgstr "อ่านแผ่นไม่ได้ !" + +#~ msgid "Could not set USB." +#~ msgstr "ไม่สามารถตั้งค่า USB ได้" + +#~ msgid "Cover Path Changed" +#~ msgstr "ที่เก็บ ปก ถูกเปลี่ยนแปลง" + +#~ msgid "DOL path changed" +#~ msgstr "ที่เก็บ DOL ถูกเปลี่ยนแปลง" + +#~ msgid "Disc Path Changed" +#~ msgstr "ที่เก็บ ภาพแผ่น ถูกเปลี่ยนแปลง" + +#~ msgid "Display favorites" +#~ msgstr "แสดง แบบเกมส์ที่ชอบ" + +#~ msgid "Do you want to retry for 30 secs?" +#~ msgstr "ต้องการลองใหม่ทุก 30 วินาที?" + +#~ msgid "Force" +#~ msgstr "บังคับ" + +#~ msgid "GCT Cheatcodes Path changed" +#~ msgstr "ที่เก็บ สูตรโกง ถูกเปลี่ยนแปลง" + +#~ msgid "Homebrew Appspath changed" +#~ msgstr "ที่เก็บโปรแกรม Homebrew ถูกเปลี่ยนแปลง" + +#~ msgid "Insert an SD-Card to download images." +#~ msgstr "ใส่ SD card เพื่อดาวน์โหลดภาพ" + +#~ msgid "Most likely it has dimensions that are not evenly divisible by 4." +#~ msgstr "ดูเหมือนว่าขนาดจะหารด้วย 4 ไม่ลงตัว" + +#~ msgid "Network init error" +#~ msgstr "การเชื่อมต่อเครือข่ายผิดพลาด" + +#~ msgid "No .dol or .elf files found." +#~ msgstr "ไม่พบไฟล์ .dol หรือ .elf" + +#~ msgid "No Favorites" +#~ msgstr "ไม่พบเกมส์ที่ชื่นชอบ" + +#~ msgid "No USB Device" +#~ msgstr "ไม่ได้เสียบอุปกรณ์ USB" + +#~ msgid "No USB Device found." +#~ msgstr "ไม่พบอุปกรณ์ USB" + +#~ msgid "Normal Covers" +#~ msgstr "หน้าปกแบบปกติ" + +#~ msgid "Not Found" +#~ msgstr "ไม่พบ" + +#~ msgid "Not a DOL/ELF file." +#~ msgstr "ไม่ใช่ไฟล์ DOL หรือ ELF" + +#~ msgid "Save Failed" +#~ msgstr "การบันทึกไม่สำเร็จ" + +#~ msgid "Selected DOL" +#~ msgstr "DOL ที่เลือก" + +#~ msgid "Standard" +#~ msgstr "มาตราฐาน" + +#~ msgid "TXT Cheatcodes Path changed" +#~ msgstr "ที่เก็บ TXTCheatcodes ถูกเปลี่ยนแปลง" + +#~ msgid "Theme Download Path changed" +#~ msgstr "ตำแหน่งที่ดาวน์โหลดธีมเปลี่ยนแปลง" + +#~ msgid "Theme Path Changed" +#~ msgstr "ที่อยู่ Theme ถูกเปลี่ยนแปลง" + +#~ msgid "Update Path changed." +#~ msgstr "ที่อยู่ Update ถูกเปลี่ยน" + +#~ msgid "WiiTDB Path changed." +#~ msgstr "ที่อยู่ WiiTDB ถูกเปลี่ยนแปลง" + +#~ msgid "You are about to delete " +#~ msgstr "คุณกำลังจะลบ " + +#~ msgid "You are choosing to display favorites and you do not have any selected." +#~ msgstr "คุณเลือกจะแสดงเกมส์ที่ชอบ แต่คุณไม่ได้กำหนดเกมส์ที่ชื่นชอบไว้" + +#~ msgid "You have attempted to load a bad image" +#~ msgstr "คุณพยายามที่จะโหลดรูปภาพที่เสียหาย" + +#~ msgid "does not exist! You Messed something up, Idiot." +#~ msgstr "ไม่มี! คุณทำให้มันเละไปแล้ว ไอ้โง่ อิอิ." + +#~ msgid "file left" +#~ msgstr "ไฟล์ที่ยังเหลือ" diff --git a/Languages/turkish.lang b/Languages/turkish.lang new file mode 100644 index 0000000..fb82362 --- /dev/null +++ b/Languages/turkish.lang @@ -0,0 +1,2880 @@ +# USB Loader GX language source file. +# turkish.lang - r848 +# don't delete/change this line (é). +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-15 16:05+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"Last-Translator: omercigingelini\n" +"Language-Team: omercigingelini\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" + +msgid " could not be downloaded." +msgstr " indirilemedi." + +msgid " has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." +msgstr " kaydedildi. Metin doğrulanmadı. Bazı kodlar birlikteyken doğru çalışmayabilir. Herhangi bir problem yaşarsanız, daha fazla bilgi için metin dosyasını gerçek bir metin editörüyle açın" + +msgid " is not on the server." +msgstr " sunucuda mevcut değil" + +#, c-format +msgid "%i files not found on the server!" +msgstr "" + +#, c-format +msgid "%i missing files" +msgstr "" + +#, c-format +msgid "%i wad file(s) not processed!" +msgstr "" + +#, c-format +msgid "%i wad found." +msgstr "" + +#, c-format +msgid "%s only accepts GameCube backups in ISO format." +msgstr "" + +#, c-format +msgid "%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder." +msgstr "" + +msgid "--== Devolution" +msgstr "" + +msgid "--== Nintendont" +msgstr "" + +msgid "--== DIOS MIOS (Lite) " +msgstr "" + +msgid "--== DM(L) + Nintendont" +msgstr "" + +msgid "/\\/\\" +msgstr "" + +msgid "0 (Everyone)" +msgstr "0 (Herkes)" + +msgid "1 (Child 7+)" +msgstr "1 (Çocuk 7+)" + +msgid "1 hour" +msgstr "1 saat" + +msgid "10 min" +msgstr "10 dakika" + +msgid "2 (Teen 12+)" +msgstr "2 (Genç 12+)" + +msgid "20 min" +msgstr "20 dakika" + +msgid "2D Cover Path" +msgstr "2D Kapak Yolu" + +msgid "3 (Mature 16+)" +msgstr "3 (Yetişkin 16+)" + +msgid "3 min" +msgstr "3 dakika" + +msgid "30 min" +msgstr "30 dakika" + +msgid "3D Cover Path" +msgstr "3D Kapak Yolu" + +msgid "3D Covers" +msgstr "3B Kapaklar" + +msgid "4 (Adults Only 18+)" +msgstr "4 (Sadece Yetişkin 18+)" + +msgid "480p Pixel Fix Patch" +msgstr "" + +msgid "5 min" +msgstr "5 dakika" + +msgid "=== GameCube Settings" +msgstr "" + +msgid "AUTO" +msgstr "OTOMATIK" + +msgid "AXNextFrame" +msgstr "" + +msgid "Add category" +msgstr "" + +msgid "Adjust Overscan X" +msgstr "" + +msgid "Adjust Overscan Y" +msgstr "" + +msgid "After zoom" +msgstr "" + +msgid "All" +msgstr "" + +msgid "All Partitions" +msgstr "" + +msgid "All files extracted." +msgstr "" + +msgid "All images downloaded successfully." +msgstr "" + +msgid "All the features of USB Loader GX are unlocked." +msgstr "USB Loader GX'in tüm özellikleri kilitli." + +msgid "All wad files processed successfully." +msgstr "" + +msgid "Alternate DOL" +msgstr "Alternatif DOL" + +msgid "An example file was created here:" +msgstr "" + +msgid "Animation Start" +msgstr "" + +msgid "App Language" +msgstr "Program Lisani" + +msgid "Apply" +msgstr "" + +msgid "Apr" +msgstr "Nis" + +msgid "Are you really sure you want to delete all selected games from the SD card?" +msgstr "" + +msgid "Are you sure you want to delete this category?" +msgstr "" + +msgid "Are you sure you want to import game categories from GameTDB?" +msgstr "" + +msgid "Are you sure you want to install on SD?" +msgstr "" + +msgid "Are you sure you want to lock USB Loader GX?" +msgstr "" + +msgid "Are you sure you want to remount SD?" +msgstr "" + +msgid "Are you sure you want to reset?" +msgstr "" + +msgid "Are you sure?" +msgstr "Emin misiniz?" + +msgid "Aspect Ratio" +msgstr "" + +msgid "Attention!" +msgstr "" + +msgid "Attention: All savegames will be deleted." +msgstr "" + +msgid "Aug" +msgstr "Ağu" + +msgid "Author(s):" +msgstr "" + +msgid "Auto" +msgstr "" + +msgid "Auto Boot" +msgstr "" + +msgid "AutoInit Network" +msgstr "Ağı ototanımla" + +msgid "BCA Codes Path" +msgstr "BCA Kod Yolu" + +msgid "Back" +msgstr "Geri" + +msgid "Back to HBC or Wii Menu" +msgstr "HBC veya Wii Menüye dönüş" + +msgid "Backgroundmusic" +msgstr "Arkaplan müziği" + +msgid "Banner Animation" +msgstr "" + +msgid "Banner Animation Settings" +msgstr "" + +msgid "Banner On Channels" +msgstr "" + +msgid "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Banner window is only available with AHBPROT! Please consider installing new HBC version." +msgstr "" + +msgid "Big thanks to:" +msgstr "Teşekkürler:" + +msgid "Block Categories Menu" +msgstr "" + +msgid "Block Categories Modify" +msgstr "" + +msgid "Block Cover Downloads" +msgstr "" + +msgid "Block Custom Paths" +msgstr "" + +msgid "Block Feature Settings" +msgstr "" + +msgid "Block Game Install" +msgstr "" + +msgid "Block Game Settings" +msgstr "" + +msgid "Block GameID Change" +msgstr "" + +msgid "Block Global Settings" +msgstr "" + +msgid "Block Gui Settings" +msgstr "" + +msgid "Block HBC Menu" +msgstr "" + +msgid "Block Hard Drive Settings" +msgstr "" + +msgid "Block IOS Reload" +msgstr "IOS Yüklemesini Engelle" + +msgid "Block Loader Layout Button" +msgstr "" + +msgid "Block Loader Mode Button" +msgstr "" + +msgid "Block Loader Settings" +msgstr "" + +msgid "Block Parental Settings" +msgstr "" + +msgid "Block Priiloader Override" +msgstr "" + +msgid "Block Reset Settings" +msgstr "" + +msgid "Block SD Reload Button" +msgstr "" + +msgid "Block Sound Settings" +msgstr "" + +msgid "Block Theme Downloader" +msgstr "" + +msgid "Block Theme Menu" +msgstr "" + +msgid "Block Title Launcher" +msgstr "" + +msgid "Block Updates" +msgstr "" + +msgid "Boot Content" +msgstr "" + +msgid "Boot Neek System Menu" +msgstr "" + +msgid "Boot?" +msgstr "Başlat?" + +msgid "Both" +msgstr "İkisi de" + +msgid "Both Ports" +msgstr "" + +msgid "CC Rumble" +msgstr "" + +msgid "Cache BNR Files" +msgstr "" + +msgid "Cache BNR Files Path" +msgstr "" + +msgid "Cache Titles" +msgstr "" + +msgid "Can't be formatted" +msgstr "Biçimlendirilemiyor" + +msgid "Can't create directory" +msgstr "Klasör olusturulamiyor" + +#, c-format +msgid "Can't create file: %s" +msgstr "" + +#, c-format +msgid "Can't create path: %s" +msgstr "" + +msgid "Can't delete:" +msgstr "Silinemiyor" + +msgid "Can't mount or unknown disc format." +msgstr "" + +#, c-format +msgid "Can't open file for write: %s" +msgstr "" + +#, c-format +msgid "Can't open file: %s" +msgstr "" + +#, c-format +msgid "Can't read file: %s" +msgstr "" + +msgid "Cancel" +msgstr "Iptal" + +msgid "Cannot write to destination." +msgstr "" + +msgid "Categories" +msgstr "" + +msgid "Categories:" +msgstr "" + +msgid "Change Play Path" +msgstr "" + +msgid "Channel Launcher" +msgstr "" + +msgid "Channels" +msgstr "Kanallar" + +msgid "Cheatfile is blank" +msgstr "Hile dosyası boş" + +msgid "Clear" +msgstr "" + +msgid "Click to Download Covers" +msgstr "Kapak Indirmek için Tıklayın" + +msgid "Click to change game ID" +msgstr "Oyun ID sini değiştirmek için tıklayın" + +msgid "Clock" +msgstr "Saat" + +msgid "Clock Scale Factor" +msgstr "" + +msgid "Close" +msgstr "Kapat" + +msgid "Code Download" +msgstr "Kod İndirme" + +#, c-format +msgid "Coded by: %s" +msgstr "%s tarafından kodlandı" + +msgid "Coding:" +msgstr "Kodlama:" + +msgid "Connection to server timed out." +msgstr "" + +msgid "Console" +msgstr "Konsol" + +msgid "Console Default" +msgstr "Konsol Ayari" + +msgid "Console Locked" +msgstr "Konsol Kilitli" + +msgid "Console must be unlocked for this option." +msgstr "" + +msgid "Console must be unlocked to be able to use this." +msgstr "" + +msgid "Console should be unlocked to modify it." +msgstr "Degiştirmek için konsolun kilidini açmalısın." + +msgid "Continue" +msgstr "" + +msgid "Continue to install game?" +msgstr "Oyunu kurmaya devam et?" + +msgid "Continue?" +msgstr "" + +msgid "Controllevel" +msgstr "Kontrol seviyesi" + +msgid "Copy" +msgstr "" + +msgid "Copying Canceled" +msgstr "" + +msgid "Copying GC game..." +msgstr "" + +msgid "Copying files..." +msgstr "" + +msgid "Correct Password" +msgstr "Doğru Şifre" + +msgid "Could not connect to the server." +msgstr "" + +msgid "Could not create GCT file" +msgstr "GCT dosyası oluşturulamadı" + +#, c-format +msgid "Could not create path: %s" +msgstr "" + +msgid "Could not extract files for:" +msgstr "" + +msgid "Could not find info for this game in the wiitdb.xml." +msgstr "" + +msgid "Could not get free device space for game." +msgstr "" + +msgid "Could not initialize DIP module!" +msgstr "DIP modülü başlatılamadı!" + +msgid "Could not initialize network!" +msgstr "Ağa bağlanılamadı!" + +msgid "Could not initialize network, time out!" +msgstr "" + +msgid "Could not open Disc" +msgstr "Disk açılamadı" + +msgid "Could not open the WiiTDB.xml file." +msgstr "" + +msgid "Could not open wiitdb.xml." +msgstr "" + +msgid "Could not save." +msgstr "Kaydedilemedi" + +msgid "Could not write file." +msgstr "" + +msgid "Could not write to:" +msgstr "" + +msgid "Cover Download" +msgstr "Kapak Indirme" + +msgid "Create" +msgstr "Oluştur" + +msgid "Credits" +msgstr "Emekçiler" + +msgid "Crop Overscan" +msgstr "" + +msgid "Current neek files are not neek2o. Game autoboot disabled." +msgstr "" + +msgid "Custom Banners" +msgstr "" + +msgid "Custom Paths" +msgstr "Kişisel Yollar" + +msgid "Customs" +msgstr "" + +msgid "Customs/Original" +msgstr "Kişisel/Orjinal" + +msgid "D Buttons" +msgstr "" + +msgid "DOL Path" +msgstr "DOL Yolu" + +msgid "Debug" +msgstr "" + +msgid "Debug Wait" +msgstr "" + +msgid "Debugger Paused Start" +msgstr "" + +msgid "Dec" +msgstr "Ara" + +msgid "Default" +msgstr "Varsayılan" + +msgid "Default Gamesettings" +msgstr "Varsayılan Oyun ayarları" + +msgid "Default Settings" +msgstr "Varsayılan Ayarlar" + +msgid "Delete" +msgstr "Sil" + +msgid "Delete Cached Banner" +msgstr "" + +msgid "Delete Cheat GCT" +msgstr "GCT Hile sil" + +msgid "Delete Cheat TXT" +msgstr "TXT Hile sil" + +msgid "Delete Cover Artwork" +msgstr "Kapak Görselini Sil" + +msgid "Delete Disc Artwork" +msgstr "Disk Görselini Sil" + +msgid "Delete category" +msgstr "" + +msgid "Deleting directories..." +msgstr "" + +msgid "Deleting files..." +msgstr "" + +msgid "Design:" +msgstr "Tasarım:" + +msgid "Details" +msgstr "" + +msgid "Developed by" +msgstr "Geliştirme" + +msgid "Developer:" +msgstr "" + +msgid "Devolution" +msgstr "" + +msgid "Devolution Loader Path" +msgstr "" + +msgid "Devolution's loader.bin file can't be loaded." +msgstr "" + +msgid "Directory does not exist!" +msgstr "Klasör bulunamadı!" + +msgid "Disc 1" +msgstr "" + +msgid "Disc 2" +msgstr "" + +msgid "Disc Artwork Download" +msgstr "Disk Görseli Indirme" + +msgid "Disc Artwork Path" +msgstr "Disk Görsel Yolu" + +msgid "Disc Default" +msgstr "Disk Varsayılanı" + +msgid "Disc Insert Detected" +msgstr "" + +msgid "Disc Read Delay" +msgstr "" + +msgid "Disc read error." +msgstr "" + +msgid "Disc-Select Prompt" +msgstr "" + +msgid "Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?" +msgstr "" + +msgid "Discarts" +msgstr "" + +msgid "DiskFlip" +msgstr "DiskÇevir" + +msgid "Display" +msgstr "Görüntü" + +msgid "Display as a carousel" +msgstr "Dönel görünüm" + +msgid "Display as a channel grid" +msgstr "" + +msgid "Display as a grid" +msgstr "Izgara görünümü" + +msgid "Display as a list" +msgstr "Liste görünümü" + +msgid "Display favorites only" +msgstr "" + +msgid "Do you want to apply it now?" +msgstr "" + +msgid "Do you want to apply this theme?" +msgstr "" + +msgid "Do you want to change language?" +msgstr "Dili değiştirmek istiyor musunuz?" + +msgid "Do you want to continue with next game?" +msgstr "" + +msgid "Do you want to copy now?" +msgstr "" + +msgid "Do you want to copy the game to SD or delete a game on SD?" +msgstr "" + +msgid "Do you want to delete a game on SD?" +msgstr "" + +msgid "Do you want to discard changes?" +msgstr "" + +msgid "Do you want to download this theme?" +msgstr "Bu temayı indirmek istiyor musunuz?" + +msgid "Do you want to extract all the save games?" +msgstr "" + +msgid "Do you want to extract the save game?" +msgstr "" + +msgid "Do you want to format:" +msgstr "Formatlamak istiyor musunuz:" + +msgid "Do you want to install selected games?" +msgstr "" + +msgid "Do you want to load the default theme?" +msgstr "" + +msgid "Do you want to move the file(s)? Any existing ones will be deleted!" +msgstr "" + +msgid "Do you want to re-init network?" +msgstr "" + +msgid "Do you want to start the game now?" +msgstr "" + +msgid "Do you want to sync free space info sector on all FAT32 partitions?" +msgstr "" + +msgid "Do you wish to update/download all language files?" +msgstr "Tüm dil dosyalarını indirmek/güncellemek istiyor musunuz?" + +msgid "Dol Video Patch" +msgstr "" + +msgid "Download" +msgstr "İndir" + +msgid "Download Now" +msgstr "Şimdi indir" + +msgid "Download finished" +msgstr "Indirme tamamlandı" + +msgid "Downloading 3D Covers" +msgstr "" + +msgid "Downloading Custom Banners" +msgstr "" + +msgid "Downloading Flat Covers" +msgstr "" + +msgid "Downloading Full HQ Covers" +msgstr "" + +msgid "Downloading Full LQ Covers" +msgstr "" + +msgid "Downloading custom Discarts" +msgstr "" + +msgid "Downloading file..." +msgstr "" + +msgid "Downloading image:" +msgstr "İndirilen resim:" + +msgid "Downloading original Discarts" +msgstr "" + +msgid "Downloading pagelist:" +msgstr "" + +msgid "Dump NAND to EmuNand" +msgstr "" + +msgid "During zoom" +msgstr "" + +msgid "Dutch" +msgstr "Flaman" + +msgid "ERROR" +msgstr "HATA" + +msgid "ERROR:" +msgstr "HATA:" + +msgid "ERROR: Can't set up theme." +msgstr "" + +msgid "EmuNAND Wad Manager" +msgstr "" + +msgid "EmuNand Channels" +msgstr "" + +msgid "Emulated Nand" +msgstr "" + +msgid "English" +msgstr "Ingilizce" + +msgid "Enter Path" +msgstr "" + +msgid "Error" +msgstr "Hata" + +msgid "Error !" +msgstr "Hata !" + +#, c-format +msgid "Error creating path: %s" +msgstr "" + +msgid "Error opening downloaded file" +msgstr "" + +msgid "Error reading Disc" +msgstr "Disk Okuma Hatası" + +msgid "Error reading disc" +msgstr "" + +#, c-format +msgid "Error when downloading file: %i" +msgstr "" + +msgid "Error while downloding file" +msgstr "" + +msgid "Error while opening the zip." +msgstr "" + +msgid "Error while transfering data." +msgstr "Veri iletiminde hata." + +msgid "Error while updating USB Loader GX." +msgstr "" + +msgid "Error writing the data." +msgstr "" + +msgid "Error:" +msgstr "Hata:" + +msgid "Error: Not enough space on SD." +msgstr "" + +msgid "Errors occured." +msgstr "" + +msgid "Everything" +msgstr "" + +msgid "Exit" +msgstr "" + +msgid "Exit to where?" +msgstr "" + +msgid "Export All Saves to EmuNand" +msgstr "" + +msgid "Export Miis to EmuNand" +msgstr "" + +msgid "Export SYSCONF to EmuNand" +msgstr "" + +msgid "Extract Miis to the Emu NAND?" +msgstr "" + +msgid "Extract SYSCONF to the Emu NAND?" +msgstr "" + +msgid "Extract Save to EmuNand" +msgstr "" + +msgid "Extracting file:" +msgstr "" + +msgid "Extracting files..." +msgstr "Dosyalar çıkarılıyor..." + +msgid "Extracting files:" +msgstr "" + +msgid "Extracting nand files:" +msgstr "" + +msgid "F-Zero AX" +msgstr "" + +msgid "Failed" +msgstr "" + +msgid "Failed copying file" +msgstr "" + +msgid "Failed formating" +msgstr "Biçimlendirme başarısız" + +msgid "Failed to extract all files. Savegame might not exist." +msgstr "" + +msgid "Failed to extract." +msgstr "Çıkartma başarısız" + +msgid "Failed to initialize the USB storage device." +msgstr "" + +msgid "Failed to open partition" +msgstr "Bölüm açılamadı" + +msgid "Failed to read ticket." +msgstr "" + +msgid "Failed to read tmd file." +msgstr "" + +msgid "Failed to read wad header." +msgstr "" + +msgid "Failed updating" +msgstr "" + +msgid "Favorite Level" +msgstr "" + +msgid "Features" +msgstr "" + +msgid "Features Settings" +msgstr "" + +msgid "Feb" +msgstr "Şub" + +msgid "File" +msgstr "" + +msgid "File not found." +msgstr "Dosya bulunamadı" + +msgid "File read/write error." +msgstr "" + +msgid "Files extracted successfully." +msgstr "" + +#, c-format +msgid "Filesize is %i Byte." +msgstr "" + +msgid "Filesize is 0 Byte." +msgstr "" + +msgid "Flat Covers" +msgstr "" + +msgid "Flip-X" +msgstr "Çevir-X" + +msgid "Folder" +msgstr "" + +msgid "Font Scale Factor" +msgstr "" + +msgid "Force 16:9" +msgstr "" + +msgid "Force 4:3" +msgstr "" + +msgid "Force NTSC" +msgstr "" + +msgid "Force NTSC480p" +msgstr "" + +msgid "Force PAL480p" +msgstr "" + +msgid "Force PAL50" +msgstr "" + +msgid "Force PAL60" +msgstr "" + +msgid "Force Titles from Disc" +msgstr "" + +msgid "Force Widescreen" +msgstr "" + +msgid "Format" +msgstr "Biçimlendir" + +msgid "Formatting, please wait..." +msgstr "Biçimlendiriliyor, bekleyiniz..." + +msgid "Found missing images." +msgstr "" + +msgid "Frame" +msgstr "" + +msgid "Frame Projection Height" +msgstr "" + +msgid "Frame Projection Width" +msgstr "" + +msgid "Frame Projection X-Offset" +msgstr "" + +msgid "Frame Projection Y-Offset" +msgstr "" + +msgid "Frames" +msgstr "" + +msgid "Free Space" +msgstr "Boş Yer" + +msgid "French" +msgstr "Fransızca" + +msgid "Full" +msgstr "" + +msgid "Full Cover Path" +msgstr "" + +msgid "Full Covers" +msgstr "" + +msgid "Full Menu" +msgstr "" + +msgid "Full covers Download" +msgstr "" + +msgid "Full shutdown" +msgstr "" + +msgid "GAMEID_Gamename" +msgstr "" + +msgid "GC Banner Scale" +msgstr "" + +msgid "GC Games" +msgstr "" + +msgid "GC Install 32K Aligned" +msgstr "" + +msgid "GC Install Compressed" +msgstr "" + +msgid "GCT Cheatcodes Path" +msgstr "GCT Hile Yolu" + +msgid "GCT File created" +msgstr "GCT Dosyası oluşturuldu" + +msgid "GUI Settings" +msgstr "GUI Ayarları" + +msgid "GXDraw" +msgstr "" + +msgid "GXFlush" +msgstr "" + +msgid "Game Cube Games Delete" +msgstr "" + +msgid "Game Cube Install Menu" +msgstr "" + +msgid "Game ID" +msgstr "Oyun ID" + +msgid "Game IOS" +msgstr "" + +msgid "Game Language" +msgstr "Oyun Dili" + +msgid "Game Load" +msgstr "Oyun Yükle" + +msgid "Game Lock" +msgstr "" + +msgid "Game Only" +msgstr "" + +msgid "Game Region" +msgstr "Oyun Bölgesi" + +msgid "Game Size" +msgstr "Oyun Boyutu" + +msgid "Game Sound Mode" +msgstr "Oyun Ses Modu" + +msgid "Game Sound Volume" +msgstr "Oyun Ses Düzeyi" + +msgid "Game Split Size" +msgstr "" + +msgid "Game Window Mode" +msgstr "" + +msgid "Game is already installed:" +msgstr "Oyun zaten kurulu:" + +msgid "Game's IOS" +msgstr "" + +msgid "Game/Install Partition" +msgstr "" + +msgid "GameCube" +msgstr "" + +msgid "GameCube Controller" +msgstr "" + +msgid "GameCube Mode" +msgstr "" + +msgid "GameCube Source" +msgstr "" + +msgid "Gamename [GAMEID]" +msgstr "" + +msgid "Games" +msgstr "Oyunlar" + +msgid "Generating GXGameCategories.xml" +msgstr "" + +msgid "Genre:" +msgstr "" + +msgid "German" +msgstr "Almanca" + +msgid "Getting file list..." +msgstr "" + +msgid "Getting game folder size..." +msgstr "" + +msgid "Global Settings" +msgstr "" + +msgid "Grid Scroll Speed" +msgstr "" + +msgid "HOME Menu" +msgstr "HOME Menü" + +msgid "Hard Drive Settings" +msgstr "" + +msgid "High Quality" +msgstr "" + +msgid "High/Low" +msgstr "" + +msgid "Homebrew Apps Path" +msgstr "Homebrew Yazılımlarının Yolu" + +msgid "Homebrew Channel" +msgstr "" + +msgid "Homebrew Launcher" +msgstr "Homebrew Başlatıcı" + +msgid "Hooktype" +msgstr "" + +msgid "Hour" +msgstr "Saat" + +msgid "How do you want to update?" +msgstr "Nasıl güncellemek istiyorsun?" + +msgid "How to Shutdown?" +msgstr "Nasıl Kapansın?" + +msgid "Import Categories" +msgstr "" + +msgid "Import operation successfully completed." +msgstr "" + +msgid "Importing categories" +msgstr "" + +#, c-format +msgid "Incoming file %0.2fKB" +msgstr "Gelen dosya %0.2fKB" + +#, c-format +msgid "Incoming file %0.2fMB" +msgstr "Gelen dosya %0.2fMB" + +msgid "Individual" +msgstr "" + +msgid "Initializing Network" +msgstr "Ağa Bağlanıyor" + +msgid "Insert Disk" +msgstr "Diski Takın" + +msgid "Insert a Wii or a Game Cube Disc!" +msgstr "" + +msgid "Install" +msgstr "Kur" + +msgid "Install Canceled" +msgstr "" + +msgid "Install Directories" +msgstr "" + +msgid "Install Error!" +msgstr "Kurulum Hatasi!" + +msgid "Install Partitions" +msgstr "" + +msgid "Install a game" +msgstr "Oyun kur" + +msgid "Install error - Cleaning incomplete data." +msgstr "" + +msgid "Install finished" +msgstr "" + +msgid "Installing Game Cube Game..." +msgstr "" + +msgid "Installing content" +msgstr "" + +msgid "Installing game:" +msgstr "Kurulan oyun:" + +msgid "Installing title..." +msgstr "" + +msgid "Invalid IOS number entered. Number must be -1 for inherit or 200 - 255." +msgstr "" + +msgid "Invalid wad file." +msgstr "" + +msgid "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." +msgstr "İşimize yarabilecek bilgilere sahip gibi gözüküyorsunuz. Lütfen bu bilgiyi Geliştirme takımına iletin." + +msgid "Italian" +msgstr "Italyanca" + +msgid "Jan" +msgstr "Oca" + +msgid "Japanese" +msgstr "Japonca" + +msgid "Japanese Patch" +msgstr "" + +msgid "Joypad" +msgstr "" + +msgid "July" +msgstr "Tem" + +msgid "June" +msgstr "Haz" + +msgid "KPAD Read" +msgstr "" + +msgid "Keyboard" +msgstr "Klavye" + +msgid "Korean" +msgstr "Korece" + +msgid "LED Activity" +msgstr "" + +msgid "Language Files" +msgstr "" + +msgid "Language change:" +msgstr "Dil değişimi:" + +msgid "Languagefiles Path" +msgstr "" + +msgid "Languagepath changed." +msgstr "Dil dosya yolu değişti." + +msgid "Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first." +msgstr "" + +msgid "Left" +msgstr "Sol" + +msgid "Like SysMenu" +msgstr "Sistem Menüsü Gibi" + +msgid "List on Gamelaunch" +msgstr "" + +msgid "Load" +msgstr "Yükle" + +msgid "Load From SD/USB" +msgstr "SD/USB den yükle" + +#, c-format +msgid "Load file from: %s ?" +msgstr "Dosya %s 'ten yüklensin mi?" + +msgid "Load this DOL as alternate DOL?" +msgstr "Bu DOL alternatif DOL olarak mı yüklensin?" + +msgid "Loader Settings" +msgstr "" + +msgid "Loader's IOS" +msgstr "" + +msgid "Loading standard language." +msgstr "Standart dil yükleniyor." + +msgid "Loading standard music." +msgstr "Standart müzik yükleniyor." + +msgid "Lock Console" +msgstr "Konsolu Kilitle" + +msgid "Lock USB Loader GX" +msgstr "" + +msgid "Locked" +msgstr "Kilitlendi" + +msgid "Log to file" +msgstr "" + +msgid "Loop Directory" +msgstr "" + +msgid "Loop Music" +msgstr "" + +msgid "Loop Sound" +msgstr "Döngüdeki Ses" + +msgid "Low Quality" +msgstr "" + +msgid "Low/High" +msgstr "" + +msgid "MIOS (Default & Customs)" +msgstr "" + +msgid "Main DOL" +msgstr "" + +msgid "Main GameCube Games Path" +msgstr "" + +msgid "Main GameCube Path" +msgstr "" + +msgid "Main Path" +msgstr "" + +msgid "Manual (40~120)" +msgstr "" + +msgid "Mar" +msgstr "" + +msgid "Mark new games" +msgstr "Yeni oyunlari imle" + +msgid "May" +msgstr "" + +msgid "Memory Card Blocks Size" +msgstr "" + +msgid "Memory Card Emulation" +msgstr "" + +msgid "Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk." +msgstr "" + +msgid "Messageboard Update" +msgstr "" + +msgid "Motion+ Video" +msgstr "" + +msgid "Mount DVD drive" +msgstr "DVD sürücüsü bağla" + +msgid "Mount USB at launch" +msgstr "" + +msgid "Move File" +msgstr "" + +msgid "Multiple Partitions" +msgstr "" + +msgid "Music Loop Mode" +msgstr "" + +msgid "Music Volume" +msgstr "Ses Seviyesi" + +msgid "NMM Mode" +msgstr "" + +msgid "Nand Chan. Emulation" +msgstr "" + +msgid "Nand Channels" +msgstr "" + +msgid "Nand Emu Channel Path" +msgstr "" + +msgid "Nand Emu Path" +msgstr "" + +msgid "Nand Emulation" +msgstr "" + +msgid "Nand Emulation is only available on D2X cIOS!" +msgstr "" + +msgid "Nand Emulation only works on FAT/FAT32 partitions!" +msgstr "" + +msgid "Nand Saves Emulation" +msgstr "" + +msgid "Native Controller" +msgstr "" + +msgid "Neek" +msgstr "" + +msgid "Neek NAND path selection failed." +msgstr "" + +msgid "Neek kernel file not found." +msgstr "" + +msgid "Neek kernel loading failed." +msgstr "" + +msgid "Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead." +msgstr "" + +msgid "Neither" +msgstr "Hiçbiri" + +msgid "Network is not initiated." +msgstr "" + +msgid "Next" +msgstr "Ileri" + +msgid "Nintendont" +msgstr "" + +msgid "Nintendont Loader Path" +msgstr "" + +msgid "No" +msgstr "Hayır" + +msgid "No Cheatfile found" +msgstr "Hile dosyası bulunamadı" + +msgid "No DOL file found on disc." +msgstr "Diskte DOL dosyası bulunamadı" + +msgid "No Disc+" +msgstr "" + +msgid "No Splitting" +msgstr "" + +msgid "No URL or Path specified." +msgstr "" + +msgid "No WBFS or FAT/NTFS/EXT partition found" +msgstr "" + +msgid "No Wiinnertag.xml found in the config path. Do you want an example file created?" +msgstr "" + +msgid "No change" +msgstr "" + +msgid "No cheats were selected! Should the GCT file be deleted?" +msgstr "" + +msgid "No data could be read." +msgstr "Hiç veri okunamadı." + +msgid "No disc inserted." +msgstr "" + +msgid "No favorites selected." +msgstr "" + +msgid "No file missing!" +msgstr "Kayıp dosya yok!" + +msgid "No games found on the disc" +msgstr "" + +msgid "No language files to update on your devices! Do you want to download new language files?" +msgstr "" + +msgid "No new updates." +msgstr "Güncelleme yok" + +msgid "No themes found on the site." +msgstr "Bu sitede tema bulunamadı" + +msgid "No themes found." +msgstr "" + +msgid "No wad file found in this folder." +msgstr "" + +msgid "NoSSL only" +msgstr "" + +msgid "None" +msgstr "" + +msgid "Normal" +msgstr "" + +msgid "Not Initialized" +msgstr "" + +msgid "Not a Wii or a Game Cube Disc" +msgstr "" + +msgid "Not a valid URL" +msgstr "" + +msgid "Not a valid URL path" +msgstr "" + +msgid "Not a valid domain" +msgstr "" + +msgid "Not enough free memory." +msgstr "Yeterli boş hafıza yok" + +msgid "Not enough free space on device." +msgstr "" + +msgid "Not enough free space!" +msgstr "Yeterli boş yer yok!" + +msgid "Not enough memory for FST." +msgstr "" + +msgid "Not enough memory." +msgstr "" + +msgid "Not required" +msgstr "" + +msgid "Not supported format!" +msgstr "Desteklenmeyen format!" + +msgid "Nothing selected to delete." +msgstr "" + +msgid "Nothing selected to install." +msgstr "" + +msgid "Nov" +msgstr "Kas" + +msgid "OFF" +msgstr "KAPALI" + +msgid "OK" +msgstr "" + +msgid "ON" +msgstr "AÇIK" + +msgid "ON (Multi)" +msgstr "" + +msgid "OSReport" +msgstr "" + +msgid "OSSleepThread" +msgstr "" + +msgid "Ocarina" +msgstr "" + +msgid "Ocarina is not supported with neek2o yet. Launch game anyway?" +msgstr "" + +msgid "Oct" +msgstr "Eki" + +msgid "Official Site:" +msgstr "Resmi Site:" + +msgid "Offset" +msgstr "" + +msgid "Ok" +msgstr "" + +msgid "One Line A" +msgstr "" + +msgid "One Line B" +msgstr "" + +msgid "Only Game Partition" +msgstr "" + +msgid "Only for Install" +msgstr "Sadece Kurulum için" + +msgid "Original" +msgstr "" + +msgid "Original/Customs" +msgstr "Orjinal/Kişisel" + +msgid "PAD Hook" +msgstr "" + +msgid "PAL50 Patch" +msgstr "" + +msgid "Parental Control" +msgstr "Ebeveyn kontrolü" + +msgid "Partial" +msgstr "" + +msgid "Partition" +msgstr "Bölüm" + +msgid "Password" +msgstr "Parola" + +msgid "Password Changed" +msgstr "Parola degiştirildi" + +msgid "Password has been changed" +msgstr "Parola değiştirildi" + +msgid "Patch Country Strings" +msgstr "Ülke İsimlerini Yamala" + +msgid "Path Changed" +msgstr "" + +msgid "Permission denied." +msgstr "" + +msgid "Pick from a list" +msgstr "Listeden seç" + +msgid "Pixels" +msgstr "" + +msgid "Play Count" +msgstr "Oynama Sayısı" + +msgid "Play Next" +msgstr "" + +msgid "Play Once" +msgstr "" + +msgid "Play Previous" +msgstr "" + +msgid "Playing Music:" +msgstr "" + +msgid "Please wait" +msgstr "" + +msgid "Please wait..." +msgstr "Lütfen bekleyin.." + +msgid "Power off the Wii" +msgstr "Wii'yi kapat" + +msgid "Prev" +msgstr "Önceki" + +msgid "Private Server" +msgstr "" + +msgid "Process finished." +msgstr "" + +msgid "Progressive Patch" +msgstr "" + +msgid "Prompts Buttons" +msgstr "Hız ve Butonlar" + +msgid "Published by" +msgstr "Yayıncı" + +msgid "Quick Boot" +msgstr "Hızlı Başlatma" + +msgid "Random Directory Music" +msgstr "" + +msgid "Real Nand" +msgstr "" + +msgid "Receiving file from:" +msgstr "Dosyanın alındığı yer:" + +msgid "Region Free" +msgstr "" + +msgid "Region Patch" +msgstr "" + +msgid "Released" +msgstr "Çıktı" + +msgid "Reload SD" +msgstr "SD'yi yeniden yükle" + +msgid "Reloading game list now, please wait..." +msgstr "" + +msgid "Remember Unlock" +msgstr "" + +msgid "Remove Read Speed Limit" +msgstr "" + +msgid "Remove update" +msgstr "" + +msgid "Rename Game Title" +msgstr "" + +msgid "Rename category" +msgstr "" + +msgid "Reset" +msgstr "" + +msgid "Reset BG Music" +msgstr "" + +msgid "Reset Playcounter" +msgstr "Sayacı sıfırla" + +msgid "Reset to default BGM?" +msgstr "" + +msgid "Restarting..." +msgstr "Yeniden başlatılıyor" + +msgid "Return" +msgstr "Dönüş" + +msgid "Return To" +msgstr "" + +msgid "Return to Wii Menu" +msgstr "Wii Menü ye Dön" + +msgid "Right" +msgstr "Sağ" + +msgid "Rotating Disc" +msgstr "" + +msgid "Round" +msgstr "" + +msgid "Rumble" +msgstr "Titreşim" + +msgid "SChinese" +msgstr "Basitleştirilmis Çince" + +msgid "SD" +msgstr "" + +msgid "SD Card could not be accessed." +msgstr "" + +msgid "SD GameCube Games Path" +msgstr "" + +msgid "SD GameCube Path" +msgstr "" + +msgid "SD Path" +msgstr "" + +msgid "SFX Volume" +msgstr "Efekt Seviyesi" + +msgid "Save" +msgstr "Kaydet" + +msgid "Save Failed. No device inserted?" +msgstr "" + +msgid "Save Game List to" +msgstr "Oyun Listesini kaydet" + +msgid "Save List" +msgstr "" + +msgid "Saved" +msgstr "Kaydedildi" + +msgid "Savegame might not exist for this game." +msgstr "" + +msgid "Screensaver" +msgstr "Ekran Koruyucu" + +msgid "Screenshot" +msgstr "" + +msgid "Select" +msgstr "Seç" + +msgid "Select DOL Offset" +msgstr "" + +msgid "Select a DOL" +msgstr "Bir DOL seç" + +msgid "Select a DOL from Game" +msgstr "" + +msgid "Select game categories" +msgstr "" + +msgid "Select loader mode" +msgstr "" + +msgid "Select the NAND Emu Path to use." +msgstr "" + +msgid "Select titles sources." +msgstr "" + +msgid "Sept" +msgstr "Eyl" + +msgid "Set Search-Filter" +msgstr "Arama Filtresi Ayarla" + +msgid "Settings" +msgstr "Ayarlar" + +msgid "Settings File" +msgstr "" + +msgid "Show Categories" +msgstr "" + +msgid "Show Favorite on banner" +msgstr "" + +msgid "Show Free Space" +msgstr "" + +msgid "Show Play Count" +msgstr "" + +msgid "Show SD" +msgstr "" + +msgid "Shutdown System" +msgstr "Sistemi Kapat" + +msgid "Shutdown Wii" +msgstr "" + +msgid "Skip Errors" +msgstr "" + +msgid "Skip IPL" +msgstr "" + +msgid "Sneek Video Patch" +msgstr "" + +msgid "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." +msgstr "" + +msgid "Sort alphabetically" +msgstr "Alfabetik Diz" + +msgid "Sort by number of players" +msgstr "" + +msgid "Sort by rank" +msgstr "Puana göre diz" + +msgid "Sort order by most played" +msgstr "En çok oynanana göre diz" + +msgid "Sound" +msgstr "Ses" + +msgid "Sound Settings" +msgstr "" + +msgid "Sound+BGM" +msgstr "Ses+BGM" + +msgid "Sound+Quiet" +msgstr "Ses+Quiet" + +msgid "Spanish" +msgstr "Ispanyolca" + +msgid "Special thanks to:" +msgstr "Özel tesekkürler" + +msgid "Split each 2GB" +msgstr "" + +msgid "Split each 4GB" +msgstr "" + +msgid "Standby" +msgstr "" + +msgid "Start" +msgstr "" + +msgid "Success" +msgstr "Başarılı" + +msgid "Success." +msgstr "" + +msgid "Success:" +msgstr "Başarılı:" + +msgid "Successfully Saved" +msgstr "Başarıyla Kaydedildi" + +msgid "Successfully Updated" +msgstr "Başarıyla Güncellendi" + +msgid "Successfully copied" +msgstr "" + +msgid "Successfully deleted:" +msgstr "Başarıyla silindi:" + +msgid "Successfully extracted theme." +msgstr "Tema başarıyla çıkarıldı." + +msgid "Successfully installed:" +msgstr "Başarıyla kuruldu:" + +msgid "Successfully updated." +msgstr "" + +msgid "Switching to channel list mode." +msgstr "" + +msgid "Sync FAT32 FS Info" +msgstr "" + +msgid "Synchronizing..." +msgstr "" + +msgid "System Default" +msgstr "Sistem Varsayılanı" + +msgid "TChinese" +msgstr "Geleneksel Çince" + +msgid "TXT Cheatcodes Path" +msgstr "TXT Hile Yolu" + +msgid "The .them file was not found in the zip." +msgstr "" + +msgid "The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored." +msgstr "" + +msgid "The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored." +msgstr "" + +msgid "The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The application might crash if there is currently a read/write access to the SD card!" +msgstr "" + +msgid "The entered directory does not exist. Would you like to create it?" +msgstr "Girilen klasör mevcut değil. Oluşturmak ister misin?" + +msgid "The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The game is on SD Card." +msgstr "" + +msgid "The game is on USB." +msgstr "" + +msgid "The save game will be extracted to your emu nand path." +msgstr "" + +msgid "The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten." +msgstr "" + +msgid "The wad file was installed" +msgstr "" + +#, c-format +msgid "The wad installation failed with error %i" +msgstr "" + +msgid "Theme Downloader" +msgstr "Tema İndirici" + +msgid "Theme Menu" +msgstr "" + +msgid "Theme Path" +msgstr "Tema Yolu" + +msgid "Theme Title:" +msgstr "Tema Başlığı:" + +msgid "Themes by www.spiffy360.com" +msgstr "" + +msgid "This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning." +msgstr "" + +msgid "This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning." +msgstr "" + +msgid "This Nintendont version does not support games on USB." +msgstr "" + +msgid "This Nintendont version is not correctly supported. Auto boot disabled." +msgstr "" + +msgid "This game has multiple discs. Please select the disc to launch." +msgstr "" + +msgid "This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu." +msgstr "" + +msgid "This path must be on SD!" +msgstr "" + +msgid "Time left:" +msgstr "Kalan zaman:" + +msgid "Timer Fix" +msgstr "" + +msgid "Title Launcher" +msgstr "Başlık Başlatıcı" + +msgid "Titles Path" +msgstr "" + +msgid "Titles from GameTDB" +msgstr "" + +msgid "To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to place them on an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less." +msgstr "" + +msgid "To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path." +msgstr "" + +msgid "To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path." +msgstr "" + +#, c-format +msgid "To use HID with %s you need the %s file." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive." +msgstr "" + +msgid "To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition." +msgstr "" + +msgid "To use neek you need to use a 512 bytes/sector Hard Drive." +msgstr "" + +#, c-format +msgid "To use ocarina with %s you need the %s file." +msgstr "" + +msgid "Tooltip Delay" +msgstr "" + +msgid "Tooltips" +msgstr "Yardımlar" + +msgid "Transfer failed" +msgstr "" + +msgid "Triforce Arcade Mode" +msgstr "" + +msgid "Two Lines" +msgstr "" + +msgid "USB" +msgstr "" + +msgid "USB Device not initialized." +msgstr "" + +msgid "USB Loader GX is protected" +msgstr "USB Loader GX koruma altında" + +msgid "USB Port" +msgstr "" + +msgid "USB Port changing is only supported on Hermes cIOS." +msgstr "" + +msgid "USB-HID Controller" +msgstr "" + +msgid "USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?" +msgstr "" + +msgid "USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?" +msgstr "" + +msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." +msgstr "" + +msgid "Uninstall" +msgstr "Kaldır" + +msgid "Uninstall Game" +msgstr "Oyun Kaldır" + +msgid "Uninstall Menu" +msgstr "Kaldırma Menüsü" + +msgid "Uninstall all" +msgstr "" + +msgid "Unknown" +msgstr "" + +msgid "Unlock USB Loader GX" +msgstr "" + +msgid "Unlocked" +msgstr "Kilit açıldı" + +msgid "Unsupported format, try to extract manually TempTheme.zip." +msgstr "" + +msgid "Update" +msgstr "Güncelleme" + +msgid "Update All" +msgstr "Hepsini Güncelle" + +msgid "Update DOL" +msgstr "DOL Güncelle" + +msgid "Update Files" +msgstr "Dosyaları Güncelle" + +msgid "Update Path" +msgstr "Güncelleme Yolu" + +msgid "Update all Language Files" +msgstr "Tüm Dil Dosyalarını Güncelle" + +msgid "Update failed" +msgstr "Güncelleme başarısız" + +msgid "Update successfull" +msgstr "" + +msgid "Updating Language Files:" +msgstr "Güncellenen Dil Dosyaları:" + +msgid "Uploaded ZIP file installed to homebrew directory." +msgstr "ZIp dosyası homebrew klasörüne kuruldu" + +msgid "Use System Font" +msgstr "" + +msgid "Use global" +msgstr "" + +msgid "VBI (Default)" +msgstr "" + +msgid "VIDTV Patch" +msgstr "VIDTV Yaması" + +msgid "Version:" +msgstr "" + +#, c-format +msgid "Version: %s" +msgstr "Vesiyon: %s" + +msgid "Video Deflicker" +msgstr "" + +msgid "Video Mode" +msgstr "Video Modu" + +msgid "Video Scale Value" +msgstr "" + +msgid "Video offset" +msgstr "" + +msgid "Video scale" +msgstr "" + +msgid "Virtual Pointer Speed" +msgstr "" + +msgid "WDM Files Path" +msgstr "" + +msgid "WIP Patches Path" +msgstr "" + +msgid "Waiting..." +msgstr "Beklemede..." + +msgid "Warning" +msgstr "" + +msgid "Warning:" +msgstr "" + +msgid "What do you want to do?" +msgstr "" + +msgid "What do you want to update?" +msgstr "Neyi güncelleme istiyorsun?" + +msgid "What should be deleted for this game title:" +msgstr "" + +msgid "What to extract from NAND?" +msgstr "" + +msgid "Where should the game be installed to?" +msgstr "" + +msgid "Where to dump NAND?" +msgstr "" + +msgid "Which device do you want to use for Nintendont files?" +msgstr "" + +msgid "Which mode do you want to use?" +msgstr "" + +msgid "WiFi Features" +msgstr "WiFi Özellikleri" + +msgid "Widescreen Factor" +msgstr "" + +msgid "Widescreen Fix" +msgstr "Genişekran Çözümü" + +msgid "Wii Games" +msgstr "" + +msgid "Wii Menu" +msgstr "Wii Menü" + +msgid "Wii Settings" +msgstr "Wii Ayarları" + +msgid "WiiTDB.xml" +msgstr "" + +msgid "WiiTDB.xml is up to date." +msgstr "" + +msgid "WiiU Widescreen" +msgstr "" + +msgid "Wiilight" +msgstr "" + +msgid "Wiimmfi.de" +msgstr "" + +msgid "Wiinnertag" +msgstr "" + +msgid "Wiinnertag Path" +msgstr "" + +msgid "Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?" +msgstr "" + +msgid "Wiird Debugger" +msgstr "" + +#, c-format +msgid "Write error on file: %s" +msgstr "" + +msgid "Writing GXGameCategories.xml" +msgstr "" + +msgid "Wrong Password" +msgstr "Yanlış Parola" + +msgid "Yes" +msgstr "Evet" + +msgid "You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk." +msgstr "" + +msgid "You can select or format a partition or use the channel loader mode." +msgstr "" + +msgid "You cannot delete this category." +msgstr "" + +msgid "You need neek2o to load EmuNAND from sub-folders." +msgstr "" + +msgid "You need to install DIOS MIOS Lite v1.2 or a newer version." +msgstr "" + +msgid "You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card." +msgstr "" + +msgid "Your current GameCube partition is not compatible. Please update Nintendont." +msgstr "" + +msgid "Zoom Duration (Speed)" +msgstr "" + +msgid "and translators for language files updates" +msgstr "" + +msgid "available" +msgstr "mevcut" + +msgid "does not exist!" +msgstr "oluşturulmamış!" + +msgid "does not exist! Loading game without cheats." +msgstr "oluşturulmamış! Oyun hileler olmadan yükleniyor" + +msgid "files left" +msgstr "dosyalar kaldı" + +msgid "for FAT/NTFS support" +msgstr "" + +msgid "for GameTDB and hosting covers / disc images" +msgstr "" + +msgid "for Ocarina" +msgstr "Ocarina için" + +msgid "for diverse patches" +msgstr "çeşitli yamalar için" + +msgid "for his awesome tool LibWiiGui" +msgstr "LibWiiGui awesome tool için" + +msgid "for hosting the themes" +msgstr "tema sunucusu icin" + +msgid "for the USB Loader source" +msgstr "USB Loader kaynak kodu için" + +msgid "for their work on the wiki page" +msgstr "" + +msgid "formatted!" +msgstr "biçimlendirildi!" + +msgid "free" +msgstr "boş" + +msgid "ms" +msgstr "" + +msgid "not set" +msgstr "ayarlanmadı" + +msgid "of" +msgstr "./" + +msgid "seconds left" +msgstr "saniye kaldı" + +#~ msgid "Error 002 fix" +#~ msgstr "Error 002 düzeltmesi" + +#~ msgid "Boot/Standard" +#~ msgstr "Boot/Standart" + +#~ msgid "Rename Game on WBFS" +#~ msgstr "WBFS'deki oyunu yeniden isimlendir" + +#~ msgid "for hosting the update files" +#~ msgstr "güncelleme dosyalarını sunduğu için" + +#~ msgid "Insert a Wii Disc!" +#~ msgstr "Bir Wii Diski Takın!" + +#~ msgid "No cheats were selected" +#~ msgstr "Hile seçilmedi" + +#~ msgid "Not a Wii Disc" +#~ msgstr "Wii Diski Değil" + +#~ msgid ">> Deleting tickets..." +#~ msgstr ">> Biletler siliniyor" + +#~ msgid ">> Deleting tickets...ERROR! " +#~ msgstr ">> Biletler siliniyor..HATA!" + +#~ msgid ">> Deleting tickets...Ok! " +#~ msgstr ">> Biletler siliniyor..OK!" + +#~ msgid ">> Deleting title ...ERROR! " +#~ msgstr ">> Başlık siliniyor ..HATA!" + +#~ msgid ">> Deleting title ...Ok!" +#~ msgstr ">> Başlık siliniyor ..Ok!" + +#~ msgid ">> Deleting title contents..." +#~ msgstr ">> Başlık içeriği siliniyor.." + +#~ msgid ">> Deleting title contents...ERROR! " +#~ msgstr ">> Başlık içeriği siliniyor..HATA!" + +#~ msgid ">> Deleting title contents...Ok!" +#~ msgstr ">> Başlık içeriği siliniyor..Ok!" + +#~ msgid ">> Deleting title..." +#~ msgstr ">> Başlık siliniyor.." + +#~ msgid ">> Finishing installation..." +#~ msgstr ">> Kurulum bitiriliyor.." + +#~ msgid ">> Installing content #" +#~ msgstr ">> Kurulan başlık # " + +#~ msgid ">> Installing ticket..." +#~ msgstr ">> Bilet kuruluyor.." + +#~ msgid ">> Installing title..." +#~ msgstr ">> Başlık kuruluyor.." + +#~ msgid ">> Reading WAD data..." +#~ msgstr ">> WAD Bilgisi okunuyor.." + +#~ msgid ">> Reading WAD data...ERROR! " +#~ msgstr ">> WAD Bilgisi okunuyor..HATA!" + +#~ msgid ">> Reading WAD data...Ok!" +#~ msgstr ">> WAD Bilgisi okunuyor..OK!" + +#~ msgid "Done!" +#~ msgstr "Tamam!" + +#~ msgid "Error..." +#~ msgstr "Hata..." + +#~ msgid "Finishing installation... Ok!" +#~ msgstr "Kurulum bitiriliyor.. OK!" + +#~ msgid "Installing content... Ok!" +#~ msgstr "İçerik kuruluyor.. OK!" + +#~ msgid "Installing ticket... Ok!" +#~ msgstr "Bilet kuruluyor.. OK!" + +#~ msgid "Installing title... Ok!" +#~ msgstr "Başlık kuruluyor.. OK!" + +#~ msgid "Installing wad" +#~ msgstr "Wad kuruluyor" + +#~ msgid "Reading WAD data... Ok!" +#~ msgstr "Wad verisi okunuyor..OK!" + +#~ msgid "Uninstalling wad" +#~ msgstr "Wad Kaldırılıyor" + +#~ msgid "New Disc Detected" +#~ msgstr "Yeni Disk Bulundu" + +#~ msgid "USB Device not found" +#~ msgstr "USB Aygıtı bulunamadı" + +#~ msgid "You need to select or format a partition" +#~ msgstr "Bir bölüm seçmeniz ya da formatlamanız gerekiyor" + +#~ msgid "Language File" +#~ msgstr "Dil dosyası" + +#~ msgid "Titles from WiiTDB" +#~ msgstr "WiiTDB deki Başlıklar" + +#~ msgid "WiiTDB Files" +#~ msgstr "WiiTDB Dosyaları" + +#~ msgid "WiiTDB Path" +#~ msgstr "WiiTDB Yaması" + +#~ msgid "for WiiTDB and hosting covers / disc images" +#~ msgstr "WiiTDB ve kapak/disk resimlerini sunduğu için" + +#~ msgid " Wad Saved as:" +#~ msgstr " Kaydedilen Wad:" + +#~ msgid "Delete ?" +#~ msgstr "Silinsin mi?" + +#~ msgid "Keep" +#~ msgstr "Sakla" + +#~ msgid "Author:" +#~ msgstr "Yazar:" + +#~ msgid "Download Boxart image?" +#~ msgstr "Kutu resmi indirilsin mi?" + +#~ msgid "Download Discart image?" +#~ msgstr "Disk resmi indirilsin mi?" + +#~ msgid "Downloading file" +#~ msgstr "Indirilen dosya" + +#~ msgid "Missing files" +#~ msgstr "Kayıp dosyalar" + +#~ msgid "files not found on the server!" +#~ msgstr "dosyalar sunucuda bulunamadı!" + +#~ msgid "Disc Images" +#~ msgstr "Disk Resimleri" + +#~ msgid "Only Customs" +#~ msgstr "Sadece Kişiseller" + +#~ msgid "Only Original" +#~ msgstr "Sadece Orjinal" + +#~ msgid "Do you really want to delete:" +#~ msgstr "Gerçekten silmek istiyor musunuz:" + +#~ msgid "Do you want to use the alternate DOL that is known to be correct?" +#~ msgstr "Doğru olduğu bilinen alternatif DOL ü kullanmak ister misiniz?" + +#~ msgid "Unlock console to use this option." +#~ msgstr "Bu seçeneği kullanmak için konsol kilidini açın" + +#~ msgid "Full Shutdown" +#~ msgstr "Tam Kapama" + +#~ msgid "If you don't have WiFi, press 1 to get an URL to get your WiiTDB.zip" +#~ msgstr "Eğer WiFi yoksa, WiiTDB.zip dosyasını alabileceğiniz URL için 1'e basın" + +#~ msgid "Paste it into your browser to get your WiiTDB.zip." +#~ msgstr "WiiTDP.zip için bu adresi tarayıcıya yapıştırın" + +#~ msgid "Shutdown to Idle" +#~ msgstr "Sistemi Beklemeye Al" + +#~ msgid "Your URL has been saved in %sWiiTDB_URL.txt." +#~ msgstr "URL %sWiiTDB_URL.txt dosyasına kaydedildi" + +#~ msgid "Can't create file" +#~ msgstr "Dosya oluşturulamıyor" + +#~ msgid "Download failed." +#~ msgstr "İndirme başarısız" + +#~ msgid "Download request failed." +#~ msgstr "İndirme isteği başarısız" + +#~ msgid "Downloading Page List:" +#~ msgstr "İndirilen Sayfa Listesi:" + +#~ msgid "Theme Download Path" +#~ msgstr "Tema İndirme Yolu" + +#~ msgid "Transfer failed." +#~ msgstr "Transfer başarısız" + +#~ msgid "Unsupported format, try to extract manually." +#~ msgstr "Desteklenmeyen format,elle çıkartmayı deneyin" + +#~ msgid "and translaters for language files updates" +#~ msgstr "ve dil dosya güncellemelerinin çevirmenleri" + +#~ msgid "Insert an SD-Card to save." +#~ msgstr "Kaydedebilmek için SD takın." + +#~ msgid "Insert an SD-Card to use this option." +#~ msgstr "Bu seçeneği kullanmak için SD takın." + +#~ msgid "No SD-Card inserted!" +#~ msgstr "SD-Card takılı değil!" + +#~ msgid "Waiting for USB Device" +#~ msgstr "USB Aygıtı için Bekleniyor" + +#~ msgid "Back to Loader" +#~ msgstr "Yükleyiciye dönüş" + +#~ msgid "FAT: Use directories" +#~ msgstr "FAT: Klasörleri kullanın" + +#~ msgid "An Error occured" +#~ msgstr "Bir Hata oluştu" + +#~ msgid "AutoPatch" +#~ msgstr "OtoYama" + +#~ msgid "Checking for Updates" +#~ msgstr "Güncellemeler kontrol ediliyor" + +#~ msgid "Downloading" +#~ msgstr "Indiriliyor" + +#~ msgid "The wad file was installed. But It could not be deleted from the SD card." +#~ msgstr "Wad dosyası kuruldu. Fakat SD den silinemedi" + +#~ msgid "The wad installation failed with error %ld" +#~ msgstr "Wad kurulumu %ld hatasıyla başarısız oldu" + +#~ msgid "Unable to open the wad that was just downloaded (%s)." +#~ msgstr "Az önce indirilen wad açılamıyor(%s)" + +#~ msgid "Update to" +#~ msgstr "Güncellenecek" + +#~ msgid "Updating" +#~ msgstr "Güncelleniyor" + +#~ msgid "Updating Language Files..." +#~ msgstr "Dil Dosyaları Güncelleniyor..." + +#~ msgid "Updating WiiTDB.zip" +#~ msgstr "WiiTDB.zip güncelleniyor" + +#~ msgid "%s : %s May not boot correctly if your System Menu is not up to date." +#~ msgstr "%s: Sisteminiz güncel değil %s doğru şekilde başlatılamayabilir" + +#~ msgid "BCA Codes Path changed" +#~ msgstr "BCA Kod Yolu değişti" + +#~ msgid "Back to Wii Menu" +#~ msgstr "Wii Menüye dönüş" + +#~ msgid "Checking existing artwork" +#~ msgstr "Hazır görsel kontrol ediliyor" + +#~ msgid "Confirm" +#~ msgstr "Onayla" + +#~ msgid "Could not find a WBFS partition." +#~ msgstr "WBFS bölümü bulunamadı" + +#~ msgid "Could not open WBFS partition" +#~ msgstr "WBFS bölümü açılamadı" + +#~ msgid "Could not read the disc." +#~ msgstr "Disk okunamadı" + +#~ msgid "Could not set USB." +#~ msgstr "USB ayarlanamadı" + +#~ msgid "Cover Path Changed" +#~ msgstr "Kapak Yolu Değiştir" + +#~ msgid "DOL path changed" +#~ msgstr "DOL yolu değiştirildi" + +#~ msgid "Disc Path Changed" +#~ msgstr "Disk Yolu Değiştirildi" + +#~ msgid "Display favorites" +#~ msgstr "Görüntü favorileri" + +#~ msgid "Do you want to retry for 30 secs?" +#~ msgstr "30 saniye sonra denemek ister misiniz?" + +#~ msgid "Force" +#~ msgstr "Zorla" + +#~ msgid "GCT Cheatcodes Path changed" +#~ msgstr "GCT Hile Yolu değiştirildi" + +#~ msgid "Homebrew Appspath changed" +#~ msgstr "Homebrew Yazılım Yolu değişti" + +#~ msgid "Insert an SD-Card to download images." +#~ msgstr "Resimleri indirebilmek için SD takın." + +#~ msgid "Most likely it has dimensions that are not evenly divisible by 4." +#~ msgstr "Muhtemelen 4 ile tam bölünemeyen boyutları var." + +#~ msgid "Network init error" +#~ msgstr "Ag baslatma hatasi" + +#~ msgid "No .dol or .elf files found." +#~ msgstr ".dol veya .elf dosyası bulunamadı" + +#~ msgid "No Favorites" +#~ msgstr "Hiç Favori yok" + +#~ msgid "No USB Device" +#~ msgstr "USB Aygıtı yok" + +#~ msgid "No USB Device found." +#~ msgstr "USB Aygıtı bulunamadı" + +#~ msgid "Normal Covers" +#~ msgstr "Normal Kapaklar" + +#~ msgid "Not Found" +#~ msgstr "Bulunamadı" + +#~ msgid "Not a DOL/ELF file." +#~ msgstr "DOL/ELF dosyası değil" + +#~ msgid "Save Failed" +#~ msgstr "Kaydedilemedi" + +#~ msgid "Selected DOL" +#~ msgstr "Seçilen DOL" + +#~ msgid "Standard" +#~ msgstr "Standart" + +#~ msgid "TXT Cheatcodes Path changed" +#~ msgstr "TXT Hile Yolu değiştirildi" + +#~ msgid "Theme Download Path changed" +#~ msgstr "Tema İndirme Yolu değişti" + +#~ msgid "Theme Path Changed" +#~ msgstr "Tema Yolu Değişti" + +#~ msgid "USB Loader GX will only run with Hermes CIOS rev 4! Please make sure you have revision 4 installed!" +#~ msgstr "USB Loader GX sadece Hermes CIOS rev4 ile çalışır! Lütfen rev4 ün yüklü olduğundan emin olun!" + +#~ msgid "Update Path changed." +#~ msgstr "Güncelleme yolu değiştirildi." + +#~ msgid "WiiTDB Path changed." +#~ msgstr "WiiTDB Yolu değişti" + +#~ msgid "You are about to delete " +#~ msgstr "Silmek üzeresiniz" + +#~ msgid "You are choosing to display favorites and you do not have any selected." +#~ msgstr "Favorileri göstermeyi seçtiniz ama hiç seçili yok" + +#~ msgid "You have attempted to load a bad image" +#~ msgstr "Bozuk bir resim yüklemeye çalıştın" + +#~ msgid "does not exist! You Messed something up, Idiot." +#~ msgstr "oluşturulmamış! Saçmaladın, mal." + +#~ msgid "file left" +#~ msgstr "dosya kaldı" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2f7f7c4 --- /dev/null +++ b/Makefile @@ -0,0 +1,302 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif + +include $(DEVKITPPC)/wii_rules +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := boot +BUILD := build +SOURCES := source \ + source/GUI \ + source/Controls \ + source/system \ + source/libs/libwbfs \ + source/language \ + source/mload \ + source/mload/modules \ + source/patches \ + source/usbloader \ + source/xml \ + source/network \ + source/settings \ + source/settings/menus \ + source/prompts \ + source/wad \ + source/banner \ + source/Channels \ + source/BoxCover \ + source/GameCube \ + source/cheats \ + source/homebrewboot \ + source/themes \ + source/menu \ + source/memory \ + source/FileOperations \ + source/ImageOperations \ + source/SoundOperations \ + source/SystemMenu \ + source/utils \ + source/utils/minizip \ + source/usbloader/wbfs +DATA := data \ + data/images \ + data/fonts \ + data/sounds \ + data/binary +INCLUDES := source + +#--------------------------------------------------------------------------------- +# Default cIOS to load into to load the settings +#--------------------------------------------------------------------------------- +ifndef $(IOS) +IOS = 58 +endif + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +CFLAGS = -g -ggdb -O3 -Wall -Wno-multichar -Wno-unused-parameter -Wextra $(MACHDEP) $(INCLUDE) -D_GNU_SOURCE -DBUILD_IOS=$(IOS) +CXXFLAGS = $(CFLAGS) +LDFLAGS = -g -ggdb $(MACHDEP) -Wl,-Map,$(notdir $@).map,--section-start,.init=0x80B00000,-wrap,malloc,-wrap,free,-wrap,memalign,-wrap,calloc,-wrap,realloc,-wrap,malloc_usable_size + +ifeq ($(BUILDMODE),channel) +CFLAGS += -DFULLCHANNEL +CXXFLAGS += -DFULLCHANNEL +endif + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lcustomfat -lcustomntfs -lcustomext2fs -lvorbisidec -lmad -lfreetype \ + -lgd -ljpeg -lpng -lzip -lm -lz -lwiiuse -lwiidrc -lbte -lasnd -logc -lruntimeiospatch +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(DEVKITPPC)/lib $(CURDIR) +#PORTLIBS := /opt/devkitpro/portlibs/ppc +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- +export PROJECTDIR := $(CURDIR) +export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +export DEPSDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +SVNREV := $(shell bash ./svnrev.sh) +IMPORTFILES := $(shell bash ./filelist.sh) +export CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +export CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +ELFFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.elf))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.bin))) +TTFFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.ttf))) +PNGFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.png))) +OGGFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.ogg))) +PCMFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.pcm))) +WAVFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.wav))) +DOLFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.dol))) +MP3FILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.mp3))) +BNRFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.bnr))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) \ + $(TTFFILES:.ttf=.ttf.o) $(PNGFILES:.png=.png.o) $(addsuffix .o,$(DOLFILES)) \ + $(OGGFILES:.ogg=.ogg.o) $(PCMFILES:.pcm=.pcm.o) $(MP3FILES:.mp3=.mp3.o) \ + $(WAVFILES:.wav=.wav.o) $(addsuffix .o,$(ELFFILES)) $(addsuffix .o,$(BINFILES)) \ + $(BNRFILES:.bnr=.bnr.o) $(CURDIR)/data/magic_patcher.o + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) -I$(LIBOGC_INC) \ + -I$(PORTLIBS)/include -I$(PORTLIBS)/include/freetype2 +# -I/opt/devkitpro/portlibs/ppc/include -I/opt/devkitpro/portlibs/ppc/include/freetype2 + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) -L$(CURDIR)/source/libs/libfat/ \ + -L$(CURDIR)/source/libs/libntfs/ -L$(CURDIR)/source/libs/libext2fs/ \ + -L$(CURDIR)/source/libs/libruntimeiospatch/ -L$(CURDIR)/source/libs/libdrc/ \ + -L$(LIBOGC_LIB) -L$(PORTLIBS)/lib + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) lang all clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ +ifneq ($(IOS),249) + @rm -f $(BUILD)/CSettings.o +endif + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +channel: + @[ -d build ] || mkdir -p build + @$(MAKE) BUILDMODE=channel --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +lang: + @[ -d build ] || mkdir -p build + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile language + +#--------------------------------------------------------------------------------- +theme: + @[ -d build ] || mkdir -p build + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile language + +#--------------------------------------------------------------------------------- +all: + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile lang + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol +#--------------------------------------------------------------------------------- +run: + $(MAKE) + @echo Done building ... + @echo Now Run That Shit ... + + wiiload $(OUTPUT).dol + +#--------------------------------------------------------------------------------- +send: + wiiload $(OUTPUT).dol + +#--------------------------------------------------------------------------------- +reload: + wiiload -r $(OUTPUT).dol +#--------------------------------------------------------------------------------- +release: + $(MAKE) + cp boot.dol ./USBLoaderGX/boot.dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +language: $(wildcard $(PROJECTDIR)/Languages/*.lang) $(wildcard $(PROJECTDIR)/Themes/*.them) +#--------------------------------------------------------------------------------- +# This rule links in binary data with .ttf, .png, and .mp3 extensions +#--------------------------------------------------------------------------------- + +%.elf.o : %.elf + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.dol.o : %.dol + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.ttf.o : %.ttf + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.png.o : %.png + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.ogg.o : %.ogg + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.pcm.o : %.pcm + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.wav.o : %.wav + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.mp3.o : %.mp3 + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.certs.o : %.certs + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.dat.o : %.dat + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.bin.o : %.bin + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.tik.o : %.tik + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.tmd.o : %.tmd + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +%.bnr.o : %.bnr + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +export PATH := $(PROJECTDIR)/gettext-bin:$(PATH) + +%.pot: $(CFILES) $(CPPFILES) + @echo Updating Languagefiles ... + @touch $(PROJECTDIR)/Languages/$(TARGET).pot + @xgettext -C -cTRANSLATORS --from-code=utf-8 --sort-output --no-wrap --no-location -ktr -ktrNOOP -o$(PROJECTDIR)/Languages/$(TARGET).pot -p $@ $^ + @echo Updating Themefiles ... + @touch $(PROJECTDIR)/Themes/$(TARGET).pot + @xgettext -C -cTRANSLATORS --from-code=utf-8 -F --no-wrap --add-location -kthInt -kthFloat -kthColor -kthAlign -o$(PROJECTDIR)/Themes/$(TARGET).pot -p $@ $^ + +%.lang: $(PROJECTDIR)/Languages/$(TARGET).pot + @msgmerge -U -N --no-wrap --no-location --backup=none -q $@ $< + @touch $@ + +%.them: $(PROJECTDIR)/Themes/$(TARGET).pot + @msgmerge -U -N --no-wrap --no-location --backup=none -q $@ $< + @touch $@ + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/README.md b/README.md new file mode 100644 index 0000000..855a2de --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# USBLoaderGX +An up-to-date version of the famous USB Loader GX to include the latest feature of Nintendont like BBA emulation, bug fixes and up to date code + +This work is based on the USB Loader GX r1272 by cyan06 and dimok789 available at : https://sourceforge.net/projects/usbloadergx/ on the 24/08/2020 + +## New features : + +- Nintendont BBA emulation can be enabled in the loader settings as well as on a per game basis. + You can also choose which network profile BBA will use. + +## Installation : + +1) Download the latest release from this git https://github.com/AsayuGit/USBLoaderGX/releases (Currently r1273) +2) Copy the USBLoaderGX folder in the apps folder on your SD card or USB device +3) Launch the USBLoaderGX from the Homebrew Channel +4) Enjoy diff --git a/Themes/Default.them b/Themes/Default.them new file mode 100644 index 0000000..53cd693 --- /dev/null +++ b/Themes/Default.them @@ -0,0 +1,941 @@ +# USB Loader GX theme source file. +# don't delete/change this line (é). +# ONLY the value before the '-' char needs to be entered in msgstr "" +# not the complete text. +# It is important that the image folder is defined for the images to load. +# The image folder should be in the same folder as the .them file and include the theme images. +msgid "" +msgstr "" +"Project-Id-Version: USB Loader GX\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-05-19 12:24+0200\n" +"PO-Revision-Date: 2009-10-01 01:00+0200\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Theme-Title: Example\n" +"Image-Folder: Example\n" +"Last-Themer: Example\n" +"Theme-Team: Example\n" +"Theme-Version: Example\n" + +msgid "0 - game bannergrid layout pos x" +msgstr "" + +msgid "-50 - game bannergrid layout pos y" +msgstr "" + +msgid "r=237 g=237 b=237 a=255 - banner icon frame color" +msgstr "" + +msgid "r=52 g=190 b=237 a=255 - banner icon highlite color" +msgstr "" + +msgid "r=130 g=130 b=130 a=0 - banner icon frame edge tev color 1" +msgstr "" + +msgid "r=180 g=180 b=180 a=255 - banner icon frame edge tev color 2" +msgstr "" + +msgid "r=255 g=255 b=255 a=255 - banner icon frame edge tev color 3" +msgstr "" + +msgid "255 - tooltip alpha" +msgstr "" + +msgid "right - checkbox browser scrollbar align hor" +msgstr "" + +msgid "top - checkbox browser scrollbar align ver" +msgstr "" + +msgid "0 - checkbox browser scrollbar pos x" +msgstr "" + +msgid "5 - checkbox browser scrollbar pos y" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - checkbox browser text color" +msgstr "" + +msgid "left - carousel layout left arrow align hor" +msgstr "" + +msgid "top - carousel layout left arrow align ver" +msgstr "" + +msgid "20 - carousel layout left arrow pos x" +msgstr "" + +msgid "65 - carousel layout left arrow pos y" +msgstr "" + +msgid "right - carousel layout right arrow align hor" +msgstr "" + +msgid "top - carousel layout right arrow align ver" +msgstr "" + +msgid "-20 - carousel layout right arrow pos x" +msgstr "" + +msgid "65 - carousel layout right arrow pos y" +msgstr "" + +msgid "r=55 g=190 b=237 a=255 - carousel game name text color" +msgstr "" + +msgid "0 - game grid layout pos x" +msgstr "" + +msgid "20 - game grid layout pos y" +msgstr "" + +msgid "9 - game list browser page size" +msgstr "" + +msgid "right - game browser scrollbar align hor" +msgstr "" + +msgid "top - game browser scrollbar align ver" +msgstr "" + +msgid "0 - game browser scrollbar pos x" +msgstr "" + +msgid "5 - game browser scrollbar pos y" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - game browser list text color" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - game browser list text color over" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - keyboard text color" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - keyboard key text color" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - numpad text color" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - numpad key text color" +msgstr "" + +msgid "right - options browser scrollbar align hor" +msgstr "" + +msgid "top - options browser scrollbar align ver" +msgstr "" + +msgid "0 - options browser scrollbar pos x" +msgstr "" + +msgid "5 - options browser scrollbar pos y" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - settings text color" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - prompt windows button text color" +msgstr "" + +msgid "r=55 g=190 b=237 a=255 - hdd info color" +msgstr "" + +msgid "center - hdd info align hor" +msgstr "" + +msgid "top - hdd info align ver" +msgstr "" + +msgid "0 - hdd info pos x" +msgstr "" + +msgid "400 - hdd info pos y" +msgstr "" + +msgid "r=55 g=190 b=237 a=255 - game count color" +msgstr "" + +msgid "center - game count align hor" +msgstr "" + +msgid "top - game count align ver" +msgstr "" + +msgid "0 - game count pos x" +msgstr "" + +msgid "420 - game count pos y" +msgstr "" + +msgid "16 - install btn pos x" +msgstr "" + +msgid "355 - install btn pos y" +msgstr "" + +msgid "371 - settings btn pos y" +msgstr "" + +msgid "64 - settings btn pos x" +msgstr "" + +msgid "371 - home menu btn pos y" +msgstr "" + +msgid "489 - home menu btn pos x" +msgstr "" + +msgid "355 - power off btn pos y" +msgstr "" + +msgid "576 - power off btn pos x" +msgstr "" + +msgid "160 - sd card btn pos x" +msgstr "" + +msgid "395 - sd card btn pos y" +msgstr "" + +msgid "405 - HBC btn pos y" +msgstr "" + +msgid "410 - HBC btn pos x" +msgstr "" + +msgid "26 - cover/download btn pos x" +msgstr "" + +msgid "58 - cover/download btn pos y" +msgstr "" + +msgid "305 - gameID btn pos y" +msgstr "" + +msgid "68 - gameID btn pos x" +msgstr "" + +msgid "r=138 g=138 b=138 a=240 - clock color" +msgstr "" + +msgid "1.0 - Overrided clock scale factor. 1.0=allow user setting" +msgstr "" + +msgid "left - clock align hor" +msgstr "" + +msgid "top - clock align ver" +msgstr "" + +msgid "275 - clock pos x" +msgstr "" + +msgid "335 - clock pos y" +msgstr "" + +msgid "168 - list layout favorite btn pos x" +msgstr "" + +msgid "214 - list layout favorite btn pos x widescreen" +msgstr "" + +msgid "13 - list layout favorite btn pos y" +msgstr "" + +msgid "208 - list layout search btn pos x" +msgstr "" + +msgid "246 - list layout search btn pos x widescreen" +msgstr "" + +msgid "13 - list layout search btn pos y" +msgstr "" + +msgid "248 - list layout abc/sort btn pos x" +msgstr "" + +msgid "278 - list layout abc/sort btn pos x widescreen" +msgstr "" + +msgid "13 - list layout abc/sort btn pos y" +msgstr "" + +msgid "288 - list layout loadermode btn pos x" +msgstr "" + +msgid "310 - list layout loadermode btn pos x widescreen" +msgstr "" + +msgid "13 - list layout loadermode btn pos y" +msgstr "" + +msgid "328 - list layout category btn pos x" +msgstr "" + +msgid "342 - list layout category btn pos x widescreen" +msgstr "" + +msgid "13 - list layout category btn pos y" +msgstr "" + +msgid "368 - list layout list btn pos x" +msgstr "" + +msgid "374 - list layout list btn pos x widescreen" +msgstr "" + +msgid "13 - list layout list btn pos y" +msgstr "" + +msgid "406 - list layout grid btn pos x widescreen" +msgstr "" + +msgid "408 - list layout grid btn pos x" +msgstr "" + +msgid "13 - list layout grid btn pos y" +msgstr "" + +msgid "438 - list layout carousel btn pos x widescreen" +msgstr "" + +msgid "448 - list layout carousel btn pos x" +msgstr "" + +msgid "13 - list layout carousel btn pos y" +msgstr "" + +msgid "470 - list layout bannergrid btn pos x widescreen" +msgstr "" + +msgid "488 - list layout bannergrid btn pos x" +msgstr "" + +msgid "13 - list layout bannergrid btn pos y" +msgstr "" + +msgid "502 - list layout lock btn pos x widescreen" +msgstr "" + +msgid "528 - list layout lock btn pos x" +msgstr "" + +msgid "13 - list layout lock btn pos y" +msgstr "" + +msgid "534 - list layout dvd btn pos x widescreen" +msgstr "" + +msgid "568 - list layout dvd btn pos x" +msgstr "" + +msgid "13 - list layout dvd btn pos y" +msgstr "" + +msgid "280 - game list layout height" +msgstr "" + +msgid "396 - game list layout width" +msgstr "" + +msgid "200 - game list layout pos x" +msgstr "" + +msgid "49 - game list layout pos y" +msgstr "" + +msgid "100 - grid layout favorite btn pos x" +msgstr "" + +msgid "144 - grid layout favorite btn pos x widescreen" +msgstr "" + +msgid "13 - grid layout favorite btn pos y" +msgstr "" + +msgid "140 - grid layout search btn pos x" +msgstr "" + +msgid "176 - grid layout search btn pos x widescreen" +msgstr "" + +msgid "13 - grid layout search btn pos y" +msgstr "" + +msgid "180 - grid layout abc/sort btn pos x" +msgstr "" + +msgid "208 - grid layout abc/sort btn pos x widescreen" +msgstr "" + +msgid "13 - grid layout abc/sort btn pos y" +msgstr "" + +msgid "220 - grid layout loadermode btn pos x" +msgstr "" + +msgid "240 - grid layout loadermode btn pos x widescreen" +msgstr "" + +msgid "13 - grid layout loadermode btn pos y" +msgstr "" + +msgid "260 - grid layout category btn pos x" +msgstr "" + +msgid "272 - grid layout category btn pos x widescreen" +msgstr "" + +msgid "13 - grid layout category btn pos y" +msgstr "" + +msgid "300 - grid layout list btn pos x" +msgstr "" + +msgid "304 - grid layout list btn pos x widescreen" +msgstr "" + +msgid "13 - grid layout list btn pos y" +msgstr "" + +msgid "336 - grid layout grid btn pos x widescreen" +msgstr "" + +msgid "340 - grid layout grid btn pos x" +msgstr "" + +msgid "13 - grid layout grid btn pos y" +msgstr "" + +msgid "368 - grid layout carousel btn pos x widescreen" +msgstr "" + +msgid "380 - grid layout carousel btn pos x" +msgstr "" + +msgid "13 - grid layout carousel btn pos y" +msgstr "" + +msgid "400 - grid layout bannergrid btn pos x widescreen" +msgstr "" + +msgid "420 - grid layout bannergrid btn pos x" +msgstr "" + +msgid "13 - grid layout bannergrid btn pos y" +msgstr "" + +msgid "432 - grid layout lock btn pos x widescreen" +msgstr "" + +msgid "460 - grid layout lock btn pos x" +msgstr "" + +msgid "13 - grid layout lock btn pos y" +msgstr "" + +msgid "464 - grid layout dvd btn pos x widescreen" +msgstr "" + +msgid "500 - grid layout dvd btn pos x" +msgstr "" + +msgid "13 - grid layout dvd btn pos y" +msgstr "" + +msgid "400 - game grid layout height" +msgstr "" + +msgid "640 - game grid layout width" +msgstr "" + +msgid "100 - carousel layout favorite btn pos x" +msgstr "" + +msgid "144 - carousel layout favorite btn pos x widescreen" +msgstr "" + +msgid "13 - carousel layout favorite btn pos y" +msgstr "" + +msgid "140 - carousel layout search btn pos x" +msgstr "" + +msgid "176 - carousel layout search btn pos x widescreen" +msgstr "" + +msgid "13 - carousel layout search btn pos y" +msgstr "" + +msgid "180 - carousel layout abc/sort btn pos x" +msgstr "" + +msgid "208 - carousel layout abc/sort btn pos x widescreen" +msgstr "" + +msgid "13 - carousel layout abc/sort btn pos y" +msgstr "" + +msgid "220 - carousel layout loadermode btn pos x" +msgstr "" + +msgid "240 - carousel layout loadermode btn pos x widescreen" +msgstr "" + +msgid "13 - carousel layout loadermode btn pos y" +msgstr "" + +msgid "260 - carousel layout category btn pos x" +msgstr "" + +msgid "272 - carousel layout category btn pos x widescreen" +msgstr "" + +msgid "13 - carousel layout category btn pos y" +msgstr "" + +msgid "300 - carousel layout list btn pos x" +msgstr "" + +msgid "304 - carousel layout list btn pos x widescreen" +msgstr "" + +msgid "13 - carousel layout list btn pos y" +msgstr "" + +msgid "336 - carousel layout grid btn pos x widescreen" +msgstr "" + +msgid "340 - carousel layout grid btn pos x" +msgstr "" + +msgid "13 - carousel layout grid btn pos y" +msgstr "" + +msgid "368 - carousel layout carousel btn pos x widescreen" +msgstr "" + +msgid "380 - carousel layout carousel btn pos x" +msgstr "" + +msgid "13 - carousel layout carousel btn pos y" +msgstr "" + +msgid "400 - carousel layout bannergrid btn pos x widescreen" +msgstr "" + +msgid "420 - carousel layout bannergrid btn pos x" +msgstr "" + +msgid "13 - carousel layout bannergrid btn pos y" +msgstr "" + +msgid "432 - carousel layout lock btn pos x widescreen" +msgstr "" + +msgid "460 - carousel layout lock btn pos x" +msgstr "" + +msgid "13 - carousel layout lock btn pos y" +msgstr "" + +msgid "464 - carousel layout dvd btn pos x widescreen" +msgstr "" + +msgid "500 - carousel layout dvd btn pos x" +msgstr "" + +msgid "13 - carousel layout dvd btn pos y" +msgstr "" + +msgid "400 - game carousel layout height" +msgstr "" + +msgid "640 - game carousel layout width" +msgstr "" + +msgid "-20 - game carousel layout pos y" +msgstr "" + +msgid "0 - game carousel layout pos x" +msgstr "" + +msgid "100 - bannergrid layout favorite btn pos x" +msgstr "" + +msgid "144 - bannergrid layout favorite btn pos x widescreen" +msgstr "" + +msgid "13 - bannergrid layout favorite btn pos y" +msgstr "" + +msgid "140 - bannergrid layout search btn pos x" +msgstr "" + +msgid "176 - bannergrid layout search btn pos x widescreen" +msgstr "" + +msgid "13 - bannergrid layout search btn pos y" +msgstr "" + +msgid "180 - bannergrid layout abc/sort btn pos x" +msgstr "" + +msgid "208 - bannergrid layout abc/sort btn pos x widescreen" +msgstr "" + +msgid "13 - bannergrid layout abc/sort btn pos y" +msgstr "" + +msgid "220 - bannergrid layout loadermode btn pos x" +msgstr "" + +msgid "240 - bannergrid layout loadermode btn pos x widescreen" +msgstr "" + +msgid "13 - bannergrid layout loadermode btn pos y" +msgstr "" + +msgid "260 - bannergrid layout category btn pos x" +msgstr "" + +msgid "272 - bannergrid layout category btn pos x widescreen" +msgstr "" + +msgid "13 - bannergrid layout category btn pos y" +msgstr "" + +msgid "300 - bannergrid layout list btn pos x" +msgstr "" + +msgid "304 - bannergrid layout list btn pos x widescreen" +msgstr "" + +msgid "13 - bannergrid layout list btn pos y" +msgstr "" + +msgid "336 - bannergrid layout grid btn pos x widescreen" +msgstr "" + +msgid "340 - bannergrid layout grid btn pos x" +msgstr "" + +msgid "13 - bannergrid layout grid btn pos y" +msgstr "" + +msgid "368 - bannergrid layout carousel btn pos x widescreen" +msgstr "" + +msgid "380 - bannergrid layout carousel btn pos x" +msgstr "" + +msgid "13 - bannergrid layout carousel btn pos y" +msgstr "" + +msgid "400 - bannergrid layout bannergrid btn pos x widescreen" +msgstr "" + +msgid "420 - bannergrid layout bannergrid btn pos x" +msgstr "" + +msgid "13 - bannergrid layout bannergrid btn pos y" +msgstr "" + +msgid "432 - bannergrid layout lock btn pos x widescreen" +msgstr "" + +msgid "460 - bannergrid layout lock btn pos x" +msgstr "" + +msgid "13 - bannergrid layout lock btn pos y" +msgstr "" + +msgid "464 - bannergrid layout dvd btn pos x widescreen" +msgstr "" + +msgid "500 - bannergrid layout dvd btn pos x" +msgstr "" + +msgid "13 - bannergrid layout dvd btn pos y" +msgstr "" + +msgid "1 - show hdd info: 1 for on and 0 for off" +msgstr "" + +msgid "1 - show game count: 1 for on and 0 for off" +msgstr "" + +msgid "center - category switch prompt align hor" +msgstr "" + +msgid "middle - category switch prompt align ver" +msgstr "" + +msgid "0 - category switch prompt pos x" +msgstr "" + +msgid "0 - category switch prompt pos y" +msgstr "" + +msgid "r=55 g=190 b=237 a=255 - game id text color" +msgstr "" + +msgid "r=55 g=190 b=237 a=255 - region info text color" +msgstr "" + +msgid "30 - region info text pos y" +msgstr "" + +msgid "68 - region info text pos x" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - banner window playcount text color" +msgstr "" + +msgid "0 - banner window play count pos x" +msgstr "" + +msgid "215 - banner window play count pos y" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - category prompt title text color" +msgstr "" + +msgid "center - category prompt title text align hor" +msgstr "" + +msgid "top - category prompt title text align ver" +msgstr "" + +msgid "0 - category prompt title text pos x" +msgstr "" + +msgid "10 - category prompt title text pos y" +msgstr "" + +msgid "center - category prompt browser align hor" +msgstr "" + +msgid "top - category prompt browser align ver" +msgstr "" + +msgid "0 - category prompt browser pos x" +msgstr "" + +msgid "45 - category prompt browser pos y" +msgstr "" + +msgid "left - category prompt add button text align hor" +msgstr "" + +msgid "top - category prompt add button text align ver" +msgstr "" + +msgid "10 - category prompt add button text pos x" +msgstr "" + +msgid "6 - category prompt add button text pos y" +msgstr "" + +msgid "left - category prompt add button align hor" +msgstr "" + +msgid "top - category prompt add button align ver" +msgstr "" + +msgid "180 - category prompt add button pos x" +msgstr "" + +msgid "330 - category prompt add button pos y" +msgstr "" + +msgid "left - category prompt delete button text align hor" +msgstr "" + +msgid "top - category prompt delete button text align ver" +msgstr "" + +msgid "10 - category prompt delete button text pos x" +msgstr "" + +msgid "6 - category prompt delete button text pos y" +msgstr "" + +msgid "left - category prompt delete button align hor" +msgstr "" + +msgid "top - category prompt delete button align ver" +msgstr "" + +msgid "330 - category prompt delete button pos y" +msgstr "" + +msgid "5 - category prompt delete button pos x" +msgstr "" + +msgid "left - category prompt edit button text align hor" +msgstr "" + +msgid "top - category prompt edit button text align ver" +msgstr "" + +msgid "10 - category prompt edit button text pos x" +msgstr "" + +msgid "6 - category prompt edit button text pos y" +msgstr "" + +msgid "left - category prompt edit button align hor" +msgstr "" + +msgid "top - category prompt edit button align ver" +msgstr "" + +msgid "180 - category prompt edit button pos x" +msgstr "" + +msgid "362 - category prompt edit button pos y" +msgstr "" + +msgid "bottom - category prompt save button align ver" +msgstr "" + +msgid "center - category prompt save button align hor" +msgstr "" + +msgid "-110 - category prompt save button pos x" +msgstr "" + +msgid "0 - category prompt save button pos y" +msgstr "" + +msgid "bottom - category prompt back button align ver" +msgstr "" + +msgid "center - category prompt back button align hor" +msgstr "" + +msgid "0 - category prompt back button pos y" +msgstr "" + +msgid "110 - category prompt back button pos x" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - check box browser prompt title text color" +msgstr "" + +msgid "center - check box browser prompt title text align hor" +msgstr "" + +msgid "top - check box browser prompt title text align ver" +msgstr "" + +msgid "0 - check box browser prompt title text pos x" +msgstr "" + +msgid "10 - check box browser prompt title text pos y" +msgstr "" + +msgid "center - check box browser prompt browser align hor" +msgstr "" + +msgid "top - check box browser prompt browser align ver" +msgstr "" + +msgid "0 - check box browser prompt browser pos x" +msgstr "" + +msgid "45 - check box browser prompt browser pos y" +msgstr "" + +msgid "bottom - check box browser prompt install button align ver" +msgstr "" + +msgid "center - check box browser prompt install button align hor" +msgstr "" + +msgid "-110 - check box browser prompt install button pos x" +msgstr "" + +msgid "0 - check box browser prompt install button pos y" +msgstr "" + +msgid "bottom - check box browser prompt back button align ver" +msgstr "" + +msgid "center - check box browser prompt back button align hor" +msgstr "" + +msgid "0 - check box browser prompt back button pos y" +msgstr "" + +msgid "110 - check box browser prompt back button pos x" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - prompt windows text color" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - game window name text color" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - game window size text color" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - game window playcount text color" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - game window details button text color" +msgstr "" + +msgid "r=30 g=30 b=240 a=255 - game window details button over text color" +msgstr "" + +msgid "r=0 g=0 b=0 a=255 - settings title text color" +msgstr "" + +msgid "center - category game prompt align hor" +msgstr "" + +msgid "middle - category game prompt align ver" +msgstr "" + +msgid "0 - category game prompt pos x" +msgstr "" + +msgid "0 - category game prompt pos y" +msgstr "" + +msgid "center - settings option browser align hor" +msgstr "" + +msgid "top - settings option browser align ver" +msgstr "" + +msgid "0 - settings option browser pos x" +msgstr "" + +msgid "90 - settings option browser pos y" +msgstr "" + +msgid "center - settings title text align hor" +msgstr "" + +msgid "top - settings title text align ver" +msgstr "" + +msgid "0 - settings title text pos x" +msgstr "" + +msgid "40 - settings title text pos y" +msgstr "" + +msgid "310 - settings title text max width" +msgstr "" + +msgid "1 - Enable tooltips: 0 for off and 1 for on" +msgstr "" diff --git a/USBLoaderGX/icon.png b/USBLoaderGX/icon.png new file mode 100644 index 0000000..951057c Binary files /dev/null and b/USBLoaderGX/icon.png differ diff --git a/USBLoaderGX/icon2.png b/USBLoaderGX/icon2.png new file mode 100644 index 0000000..81499ae Binary files /dev/null and b/USBLoaderGX/icon2.png differ diff --git a/USBLoaderGX/readMii.txt b/USBLoaderGX/readMii.txt new file mode 100644 index 0000000..8ca5db9 --- /dev/null +++ b/USBLoaderGX/readMii.txt @@ -0,0 +1,1075 @@ + + __,,__, ,__wywyywvyyyyywvywvyam,,_, _,,_ + _uWB&#MBM$Wg&MQ$#$K&RMKMA0$&xNH&&MN@2W&#MM&#$KQg + JN&B&MM#MQ$gM#Q$N#R&&#N$M$#�E$##V$WKG###B&$&NW#b + j8W0##&M$W&$###�##&$0MN#BX&5&#$xA$A$#$#&#z$MNQWK#L + 3#$$& N$&WK& XN#$&~~ ^VM#&#A~`^`"~^~"'K###2$M + SQN$# 9MB#@) $$$# ***, $&mR _,_ NU#$M + &0N## #M$$M# NA4 ****** *$g# *0$Q&H! ]$N$# + M\w&F ##&#@$ #W8- ~v"&N8&*#$# 0QB#&$& !#&$K + $QNNC E&M$0# g&&&_ "*$&QM #$MN$# + j$$0L $M@WWK #W&#M&k,,_ ~&$$ _,_ $NQN( + i&M4( N$K2## M#NNF$&####& 0#$ *0$Q&H! W#$( + j$B#N V&#AMS SRW $8$0M& 3M$ 0QB#&$& #N$I + jQ0&NL ""^ JB&ML '~^ jQ*A ` j##KF + K#$##& _#B#WNKM_ ,vB&#M _ _wp#&QAF + "&NAQAN&#$&MW#&###B#x$3@&$BA#WWWH$#KMM&K&NK###g&$# + *WN$&$$8QWNMMM#MM&«&A#&M$K&#WK@QM5#&*A$N&$&WM#@2 + "M*^&N##&$W8$2B#&MB&DWR0#$$0#W»&&M$#QQMN#&"" + \eeee6 F**A1 + jM0$e4 ?**G\! + imw{Q- x%%%m \%z%%e mxx _%*%@& -ve/v mmm\ wvm + V3Q%m& /#0^0E&~/&\ $&E/&%1e^"E 55t7JcVsm0-\ &^#l@&}&-" $7MAE&&%/ + $%x/z Wc&&t7-w&E4^ %VVM~1^\&$&&} e$&$$%$zQMxw w-v-#^ Q\W44 %-/%/\QS + et-SC e^00^ iF&E$- !%%$$%A*v 5^^4 EEZ/0 )%%0%4fimmEt" "$S8V +(WJ^%i m&MM#} /%\%%L 4Q\w WQ/Q\ &m«wS \v"v1 \74~1zM%&%/6s wEw// +&ssSs?s%wt&&-~~MM#& e1/'m% &5^jW &mw&\ SmVw^ S1&mw \^A5FE j7F*5, ~S3m% +j3Q"/&-&w&M%& ^^4$w^7QSQ@ t&&&%-"5w&E} e8"&&&&/%\W &5%1\%V*\0M &&7M +~?VW^$ ?&\81? ?mQ&&&- 00%%^~EE4E \&00 ^M43^ ^'"#5&$-^ ~wEE} + __ ,_ + __ggggggggggggggg& jggggg#p gMMMMMMM + &MMMMMMMMMMMMMMMMMMF "MMMMMMM& j#MMMMMMP + #MMMMMMMMMMMMMMMMMMMF #MMMMM&g#MMMMMMP + #MMMMMF "MMMMMMMMMMM#^ + #MMMMML pgppggggggp $MMMMMMMMF + $MMMMML 4#M#NRMMMMMF jMMMMMMMMMQ + $MMMMMF #MMMMF pMMMMMMMMMMMMp + 4MMMMMMNNN#MMMMMMMMMF jMMMMMMF MMMMMM&_ + MMMMMMMMMMMMMMMMMM& #MMMMM@~ ~MMMMMM& + """""""""""""""" """""" """"""^ + + +Congratulations! You are one of the proud Beta Testers for USB Loader GX. That's right. Beta tester. This means that you are using Beta software. This program is still under heavy development. Not everything works perfectly. If you are expecting it to, stop and look elsewhere. Some of the features covered here may be removed in your version of the application. And likewise, there may be features in your revision that are not covered here. + +By using a Beta revision, you are agreeing to not be an idiot. Most of the features should be self explanatory. The rest of them can be figured out by clicking around a trying stuff out. There is no button or combination of buttons that you can click that will brick your wii or make irreparable changes to your wii. So please try out all the features to see which options need to be enabled for your WII + TV + game combination. + +This was written 6/15/2009 regarding revision 529 +Last update on 10/1/09 regarding rev 772, updated/added a few images, updated cover path info, and added MIOS Patcher to download links. + + +Features + +* The GUI is completely based on the awesome libwiigui by Tantric +* Game information: reads game info from wiitdb.zip in your config folder like publisher, developer, year, rating, genre etc. +* Widescreen support: Without any special themes for widescreen +* Alternative dol loading: Supports special dol files needed to launch some games (e.g. Mortal Kombat) +* Loading from USB: Loads files (images, configs etc.) from SD or USB (needs a FAT32 partition on the drive to be primary and active). +* Global Settings and "per game" settings +* Parental control: Set levels for each game, set a password for install/remove/etc. +* View modes: simple List Mode, Game Grid and Game Carousel. +* Supports Themes: Create your own theme and use it with the loader +* Cover download: Download "normal" covers, 3D covers and disc images for all the games on your HDD (International Covers are downloaded based on your global language setting) +* Look and feel like the original Wii Menu: Use rumble feature, button sounds, background music, disc slot lights up etc. (you can also turn it off in the settings) +* Loads all the needed files from your SD/USB +* Language file support: use your native language for the loader. +* Custom sounds: for now only ogg custom sounds possible. +* Playstats: shows you how many times you played the game +* List sorting, Game Search, & Favorites: you can sort the list by playstats or names, search by name, or display only your favorites! +* Update function: update to the latest revision from inside the gui (requires internet connection). +* Homebrew & Title Launcher: Launch you favorite homebrew apps and channels from within the loader. +* Full Alternate Dol Support: Alternate dols can be loaded from SD/USB or from the game itself. Most altdols can be automatically chosen by the loader. + + +Useful links & Downloads + +Github +https://github.com/AsayuGit/USBLoaderGX + +Changelog +http://code.google.com/p/usbloader-gui/source/list + + +Game compatibility list +http://wiki.gbatemp.net/wiki/index.php?title=USB_Loader_v1.x_Game_Compatibility + +Devices compatibility list +http://wiki.gbatemp.net/wiki/index.php?title=USB_Devices_Compatibility_List + +List of WBFS managers +http://wiki.gbatemp.net/wiki/index.php?title=WBFS_Managers + +More questions? +http://forum.koureio.net/ + +cIOS installers +cIOS38r12: http://gbatemp.net/index.php?download=6093 +cIOS38r13: http://gbatemp.net/index.php?download=6133 +cIOS38r13b: http://gbatemp.net/index.php?download=6127 +cIOS38r14: http://gbatemp.net/index.php?download=6531 +Hermes cIOS222/223 rev3: http://www.4shared.com/file/125087683/2b7948f1/Hermes_cIOS_222_rev3_installer.html +Hermes cIOS222/223 rev4: http://www.4shared.com/file/129761844/53c80425/Hermes_cIOS_222_rev4_installer.html + +MIOS Patcher +WiiGator's cMIOS http://www.4shared.com/file/136843685/99990ffc/miospatcher.html + +Other +Wad manager 1.5: http://teknoconsolas.tv/wanin/WAD-Manager_v1.5.zip (mirror) +Forwarder dol for preloader: http://www.mediafire.com/download.php?nykt4zyndzq +Fat32Format: http://www.ridgecrop.demon.co.uk/download/fat32format.zip +HJSplit http://www.freebyte.net/download/hjsplit.zip (this joins 001, 002, ... files) + + + +Contents + + 1. [1] Prerequisites & setup + 1. [1a] Installation + 2. [1b] Channel & Forwarder + 3. [1c] [OPTIONAL]Autobooting and returning to USB loader GX + 4. [1d] Files & paths + 2. [2] Usage + 1. [2a] [OPTIONAL] Compiling the loader + 2. [2b] Adding games & changing GameID ***** + 3. [2c] Getting Covers & Wiitdb.zip ***** + 3. [3] Main menu + 1. [3a] Controls + 2. [3b] On the screen + 3. [3c] View + 4. [3d] Game Info + 5. [3e] Game Prompt + 4. [4] Exit Menu + 5. [5] Homebrew&Title Launcher ***** + 1. [5a] Homebrew Launcher + 2. [5b] Title Launcher + 3. [5c] (Un)Installing WADs over wifi + 6. [6] Settings + 1. [6a] Gui settings + 2. [6b] Game load + 3. [6c] Parental control + 4. [6d] Sound + 5. [6e] Custom paths ***** + 6. [6f] Update ***** + 7. [6g] Default settings ***** + 8. [6h] Credits + 7. [7] Game settings ***** + 1. [7a]Game load + 2. [7b]Ocarina + 3. [7c] Uninstall Menu + 4. [7d]Default settings + 8. [8]Cheating + 1. [8a] Using a Computer + 2. [8b] Using the USB loader + 9. [9]Themes + 10. [10]Special Games + 1. [10a]Wii Sports Resort + 2. [10b]Metroid Prime Trilogy + 11. [11]FAQ + +Everything in this Guide that is marked with ***** can not be used if the loader is locked! +Text in red is a little harder and for advanced users only! +Blue text is Important Info! + + +________________ +[1] Prerequisites & setup +[1a] Installation + +STEP 1 – Installing the HBC (Homebrew Channel) and a cIOS (custom Input/Output System «- ignore that). + +If you are COMPLETELY new to homebrew, this little guide will tell you how to install the homebrew channel on your wii. The guide can be used for every system menu (up to 4.1, so updating is recommended) and any serial (LU64+). Do not use it on a Korean wii! + +First, follow steps 1 and 2 of this guide: http://gbatemp.net/index.php?showtopic=155844 to get the HBC on your wii. The hackmii installer can also install bootmii for you if you need brick protection. Our next step is to get a cIOS installed that is needed for the loader. Try installing a cIOS with a cIOS installer (using IOS36). If this doesn't work (if you get an error while installing), you don't have a patched IOS (needed by the cIOS installer) and you have to use one of the two methods below. + + +Online method (Using wifi on the wii) +Get the Trucha bug restorer by wiipower and run it with the HBC. You will see a lot of white text on a black screen. This is how many installers/patchers look like. It has no nice banner and stuff to keep the filesize low. + + +1) Select IOS36 and press A. Even more text appears, read it if you want. Wait for the text at the bottom to appear and press 1. +2) Choose Downgrade IOS15. Then download from NUS (2 times). Follow instructions on the screen. +3) Now we can use the downgraded IOS15 to restore the Trucha in IOS36. Run TBR again. This time choose IOS15 and again press A then 1 when the text appears. +4) Go into the IOS36 menu. Use these configurations: 36 (this is in what IOS-slot the patched IOS36 will be placed.) YES YES NO (actually you can choose what you want for the last 2 options), then select Install patched IOS36 and press A. Choose Download from NUS once again and follow on screen instructions. +5) Now we have the patched IOS36, we can restore our IOS15 again. Load the TBR one last time. Choose IOS36,... .This time choose restore IOS15. Get the IOS from NUS and let the app finish everything. + +We are ready to install our cIOS. I will explain here how to get cIOS38r14 by waninkoko. You can also install another rev of this cIOS (don't go lower than r9) or a rev of IOS222/223 by hermes. All IOS have different uses and bugs. Its up to you to find out what these are. + +Get the installer here: http://gbatemp.net/index.php?download=6531 . Follow all the instructions at the link, but choose IOS36 instead of IOS249 (this is why we have patched IOS36). When you are asked to use wad install or online install, choose online install. You will then have the cIOS needed by the USB loader. + +Offline method (no wifi on the wii) +Wad files of IOS are not legal, so we can not give them to you. Here is how to get them anyway: + +Get the NUS downloader and Trucha bug restorer. + +First open NUS downloader and Click 'Generate certs' if it asks to. First check Pack-»Wad. Click Database and Go to IOS, IOS15, v257. Then click Nus Download. Repeat this proces for IOS15 v266 and IOS36 v3094. +Now go to the place where NUS downloader is and there will be 3 new folders. Copy the WAD of each folder to the SD card. + + +Now follow steps 1 – 5 from the Online guide, but instead of choosing “Download IOS from NUS”, choose “Load IOS from SD card”. + +We are ready to install our cIOS. I will explain here how to get cIOS38r14 by waninkoko. You can also install another rev of this cIOS (don't go lower than r9) or a rev of IOS222/223 by hermes. All IOS have different uses and bugs. Its up to you to find out what these are. + + +First we need one more file from the NUS: check Pack-»Wad. Get IOS38 v3610. Place the wad of the new folder at the root of the SD card. Download the cIOS installer: http://gbatemp.net/index.php?download=6531 . Follow the instructions at the link, but choose IOS36 instead of IOS249 (this is why we needed to patch IOS36). You have to choose wad installation. You will then have the cIOS needed by the USB loader. + +NOTES: +-You can have cIOS36/38 and cIOS222/223 installed at the same time. Every version has its own (dis)advantages. + + +-If your global cIOS is 249 and you set an individual game's cIOS to 222/223, it will not always work. On the other hand, if you set your global boot to 222 and set an individual boot to 249, it should work fine. + +-If you change your global boot cIOS you need to completely exit out of the loader and restart it in order for the change to take effect. If you do not do this you will get a black screen. It is also necessary to delete your GXgamesettings.cfg file from your config folder on your SD/USB to prevent any setting conflicts since anything in GXgamesettings.cfg overrides the GXglobal.cfg file. + +-Setting your global boot to 222 rev 3(installed as 37 merge 36) or 222 rev 4(installed as 38 merge 37) and setting your global 002fix to ANTI will result in 99% compatibility with no glitching/stuttering on IN REGION games. For OUT OF REGION games you need to also set the Video Mode to AUTOPATCH. The 1% non-compatibility is from the "please insert disc" games. However, those games are fully playable by simply inserting any dvd into your drive (I just stick a blank one in) OR by loading those specific games with cIOS 249 rev 12 or higher. + +-Make sure you always delete the 00000001 folder from the root of your SD/USB before doing any network installation of cIOS 222/223. + +STEP 2 – Preparing your USB device + +Optional +The USB loader can load images and other info of the same usb device as where the games are stored on. To be able to use this function, you will need to make two partitions on the USB device. The partition for the images should have enough with 2GB. You can also make more partitions for other purposes. Use GOOGLE to find out how to make partitions. (Or go here: http://gbatemp.net/index.php?showtopic=179085). +For linux: http://gwht.wikidot.com/gparted + +Required +The partitions have to be formatted to FAT. Mark the partition you want to use for WBFS as Active. + +If you make multiple partitions, the First partition must be the one for image,... and the second one for WBFS (for Wii games) + + +STEP 3 – Preparing the SD card + +You can also use the USB device for this if you made a second partition in Step 2. + +Using the easy installer + +The fastest way of installing the USB loader GX is to download the Easy installer. Run this tool and click next (be sure to have an internet connection).You will be asked what files to put on the SD card/ USB device (dependant on where you run homebrew from). Recommended is to download everything except following things: +-The languages that you won’t use (only one language can be checked), +-If you already have images for the loader, don’t check cleanup, as it will remove the images. + +Next, you will be asked where to install the loader to. Advised is to install it to SD:\apps\usbloader_gx or USB:\apps\usbloader_gx (replace SD/USB by the drive letter of the card/device). If you’re done, click install. + +Without the easy installer + +Sometimes its not possible to use the easy installer. You will have to put on the files manually. +1) Download the newest dol from http://usbloadergx.koureio.net/downloads/revisions. +2) Create a new folder on your SD card (or USB) in the apps folder, called usbloader_gx. Place the dol in this folder and rename it to boot.dol . + +STEP 4 – Running the loader + +When you first boot up the Loader (using the HBC or another method of booting homebrew), you will be asked to format a partition to WBFS. Choose your partition and press A. If your partition is formatted, you are ready to use all functions of this app! + +NOTE: You can also format a partition to WBFS by using a WBFS manager. + + +################################### + +[1b] Channel & Forwarder +If you don't like going to the HBC to load the loader every time, you have to install the channel or forwarder of this loader. +Both Channel and forwarder appear in the wii menu as a new channel. But there is a very important difference between them! The channel contains the app and can boot it without the SD card. The forwarder however simply loads the loader from SD:/apps/usbloader_gx/. There are (dis)advantages to both. Go here for more info: http://usbloadergx.koureio.net/downloads/forwarders + +To install the forwarder or channel, you need an application called Wad manager. Get it here: http://teknoconsolas.tv/wanin/WAD-Manager_v1.5.zip +Place it in its own folder in the apps folder of the SD card (or USB). + +Download forwarder: http://www.mediafire.com/?jdmiykainlm +Download channel (R649c): http://www.mediafire.com/download.php?ntuexwmycby +Create a new folder on the SD card (or USB) called wad. It has to be in the root of the SD card (so not in the apps folder). Place your wad here. + +Run the wad manager. Choose IOS249. Then choose SD or USB (depending on where you placed the wads). Select the wad to install and press A to install it. When its done, keep pressing B to go back to the HBC. Then go to the wii menu. You will see your new channel/forwarder on one of the pages. You can move it by holding A and B. + +Changing the location the forwarder loads the dol from: To do this, simply change the update path (see [6e]) + + +[1c] [Optional]Autobooting and returning to USB Loader GX + +It is possible to boot your wii directly into the USB loader GX. The only thing you need for this is a wii app called preloader. First download the newest rev of the loader or even better, the forwarder (dol format, see downloads at the top of the readmii). Place the dol you get in the root of your SD card (no need to rename it to boot.dol). In the preloader menu, choose install file and choose the dol to install. When its done, go to the main menu of preloader (B) and then choose 'settings'. You have to change 2 options here: Autoboot=file and Return to=preloader. Save the settings, then launch the Wii menu in the main menu. It will boot into the USB loader GX! + +################################### + +[1d] Files & paths + +There are other files that are not necessary to the core functionality of this loader, but are used for extra features. The dev. team has defined the following paths, most of which are configurable in the settings. + +Update Path - SD:/config/ +This is where the application will create files to save settings and statistics. All the files it makes start with GX to make them easy to find. +GxGlobal.cfg is the main settings and configuration for the loader. +GXGameSettings.cfg contains individual settings for games. +GXGameCount.cfg stores the game play count and favorites choices. A database of information about each game can be stored in this folder as well. Get you hands on wiitdb.zip and put it here. + +Covers Path - SD:/images/ +This is where box art is downloaded to and displayed from. All images must be sized in multiples of 4 or they won't show up. Create separate folders for 2D and 3D covers. When you direct each path to the proper folder the default displays are 3D for the List and Carousel views and 2D for the Grid view. +Official sizes: +2D covers = 160x224 +3D covers = 176x248 + +Disc Image Path - SD:/images/disc/ +This is where pictures of the actual game discs are downloaded to and displayed from. All images must be sized in multiples of 4 or they won't show up. +Official size: +Discart = 160x160 + +Background Music Path - SD:/config/backgroundmusic/ +This is the default folder for custom background music. + +Theme Path - SD:/theme/(SD:/wtheme for widescreen wii) +This is the default theme location. + +Cheatcodes Path - SD:/codes/ +This is the folder to put your gct cheat files. + +TXT Cheatcodes Path - SD:/txtcodes/ +Here is where you can place the txt files needed by the code manager. Files must have the full game ID (6 chars.) as name. The downloaded txt files (with the code manager) will be placed here. + +DOL Path - SD:/ +This is where replacement dols (used to fix certain broken games) go. + +Homebrew Apps Path - SD:/apps/ +This is where you can place the Homebrew apps for the Homebrew Loader. + + +________________ +[2] Usage + +Using this application is simple. Launch it in the same way that you did in the initial setup, pick a game (if you have any installed), and play the game. This is open source software. You are free to modify it, distribute it, and do anything you want with it. All we demand is that you do not claim our work as yours. We worked long and hard on this and let you use it for free. It would be a real bitch move if you put your name on it and said it was your own. +You are also free to distribute the software/source code as you like as long as this file (or a similar one approved by the dev team) companies it. If you don't follow these guidelines, you are a douche-bag. + +################################### + +[2a] [Optional] Compiling the loader + +THIS IS COMPLETELY OPTIONAL. IF YOU ARE NOT INTERESTED IN PROGRAMMING OR COMPILING, OR IF YOU DON'T MIND WAITING FOR SOMEONE ELSE TO COMPILE THE NEWEST REV, YOU CAN SKIP TO [2b]. + +This loader gets updated very frequently. The newest revision will not be available all the time to download. When that happens, you will have to compile the loader yourself. GBAtemp members emupaul and giantpune have made a guide that shows you how to compile the loader.The full guide can be found at http://gbatemp.net/index.php?showtopic=169078 + +1)Download a svn client. Reccomended is Tortoisesvn. If you want the loader to show the rev# in the settings, you also need sliksvn. +2)Download and install Devkitpro +3)Reboot your system +4)Create a new folder (can be anywhere) and name it USBGX (or any other name, as long as you know what it contains) +5)Right click your folder and select SVN Checkout (this option is added by Tortoisesvn) +6)Enter the url http://usbloader-gui.googlecode.com/svn/trunk/. Leave all other options as they are and click OK +7)Download http://usbloader-gui.googlecode.com/files/...-08-07-2009.zip and extract to the libogc folder +8)After it has downloaded the source, all folders will show a green OK mark. Open the file gui.pnproj +9)You are now in the programmers notepad. This utility is used to program wii apps. Press ALT + 1 (the 1 thats not on the Numpad) to compile the source. +10)Copy the boot.dol (or elf) to the SD card and run it. + +[OPTIONAL] Changing the source for the channel: You have to make a small change in the code to let the USB loader know its a channel. +1)Open Gui.pnproj, it wil open with the Programmers notepad. +2)Time to make a little change in the code (maybe your first time doing this :) ). You should see the file structure (If not, go to view»windows»projects and enable it, then place it somewhere). Open the prompts folder (if it isn't open already) by clicking the white arrow in front of it. Then open PromptWindows.h (double click) +3)It will appear in a new window. At the top of the file you should see #define NOTFULLCHANNEL +4)Put your cursor before the # at this line and type //. The line will become green and will look like: //#define NOTFULLCHANNEL. This line is now a comment. Comments are just extra information and are not compiled. +5)Compile the source by pressing ALT+1. Now you have the correct boot.dol, which you can inject in the channel. + +################################### + +[2b] Adding games & changing GameID ***** + +To add a game to your drive using this program, click the install button on the main screen and follow the on screen prompts. Games are automatically scrubbed (shrunk) and brickblocked (update partition removed) when adding them to the drive. + +Because of the way WBFS and the application work, you are only allowed to install 1 game for each game ID. If you do use another application to install 2 games with the same 6 character ID, only the first one on the drive will be loaded by our program. If the installation freezes (doesn't move for over 2 minutes) you can simply hold the power button on the Wii to turn it off. There is no danger of bricking your wii. The data that was written during the failed install is still present on the drive, but not marked as active so it will be treated as free space. It does not get added into the used space displayed on the screen and it will be overwritten next time you install a game. + +To install games (ISO or cISO) with your computer, you need a WBFS manager. Most popular are WBFS manager 3.0 and WBFS intelligent GUI v6. Using these programs should be self-explanatory. + + +***The following feature is for advanced users only! Do not use this feature unless you know exactly what you are doing!*** +As of revision 719, it is now possible to edit GameIDs via the loader which is useful with different games using the same GameID (ie; Guitar Hero mods). When viewing the GUI in list mode, simply click on the GameID displayed underneath the targeted game's cover (if GameID isn't displayed, see section [6a]) to bring up the ID change prompt. Keep in mind that this will create a new save file for the targeted game and will no longer load a previous save file unless the GameID is restored to it's original ID. + +################################### + +[2c] Getting Covers & Wiitdb.zip ***** + +This loader can show the boxart and discart for every game. The images have to be placed in the correct folder and must have the correct name and size (more info at [1a]). To download covers with this loader, you need to press 1 at the main menu. You can choose what covers you want to download (2D or 3D). Discart can also be downloaded. + +It is also possible to show the info for each game. You can show the game info by highlighting a game (don't press A, just point) and pressing 2. The data for the game info is stored in wiitdb.zip. There are two ways to get this file: + +-Update with the loader and select update all or update wiitdb, it will also be updated if you update the full channel. +-If you have no wifi, go to the game info screen of any game. Press 1 and you will see the text at the bottom change. Go to the file it shows and copy the URL. Then open the url with a web browser to download the wiitdb.zip. Once you got wiitdb.zip , place it in the titles.txt path (see Custom paths) + +NOTE: All images and wiitdb.zip are downloaded from the site www.wiitdb.com . + +________________ +[3] Main menu + +This is the main screen, the first one you see when you start the program. It looks a lot like the Wii system menu. (Default theme) + +################################### + +[3a] Controls + +User input for the main menu is accepted through WiiMote, Nunchuk, Gamecube controller, and Classic controller. While input is accepted from all these methods, the fastest and easiest method is with a WiiMote. + +Wiimote +A --- Main action Button +B --- Back/Cancel/Scroll (list view) +- Button --- Left (Grid/Carousel/game prompt/settings) +Home --- Open Exit menu ++ Button --- Right (Grid/Carousel/game prompt/settings) +1 --- Download covers +2 --- Show game info (select a game first) +D-Pad --- Choose +Pointer --- Choose + +Nunchuck +Control stick --- Choose + +GC Controller +Control stick --- Choose +D-Pad --- Choose +A --- Main Action button +B --- Back/Cancel/Scroll (list view) + +Classic controller +Left control stick --- Choose +D-Pad --- Choose +A --- Main action button +B --- Back/Cancel/Scroll (list view) +X --- Game info +Y --- Download covers +- Button --- Left (Grid/Carousel/game prompt/settings) +Home --- Open Exit menu ++ Button --- Right (Grid/Carousel/game prompt/settings) + +################################### + + +[3b] On the screen + +1.Install ***** -- (+) button at the left -- Press to add games to your HDD from the Wii's DVD drive. + + +2.Settings -- Button with gear on the left -- Use it to access all the settings and options. + + +3.Exit -- Button with 'wii' on the right -- Press this to view the exit menu. + + +4.Power -- Button with power logo at the right -- I bet you can figure out what it does. + + +5.Download ***** -- Listview: cover -- When you are in the list view, click a game box to download stuff. You can also use the 1 button in any display mode. + + +6.Reload -- SD card button -- Press it to reload your SD contents (images, themes,…). + + +7.Homebrew Loader -- Button right of the HDD info -- Run the Homebrew Loader + + +8.Sort bar -- Bar at the top -- contains 9 - 16 from left to right + + + 9.Favorites --- Press it to hide all games that are not marked as a favorite. + + 10. Game Search --- Use this button to only list games that start with a certain letter. + + 11.Abc --- Your games will be sorted alphabetically. + + 12.Playcount --- Sort games by the number of times you have launched them from this application. Games with the same count are sorted alphabetically. + + 13.List --- Press it to see games listed by name and any available box art for 1 game at a time. + + 14.Grid --- Use this button to see your games arranged in a grid. The number of rows available depends on how many games are on you drive. 39 games can be seen at the most. + + 15.Carousel --- Press this to see you games arranged in a rotating fan array. 7 games can be seen at a time. + + 16. Load from Disc --- Boot the current game disc that is inserted in the Wii disc drive. cMIOS is required in order to play Gamecube backups. + +17.Clock -- Above the HDD info -- This looks like a digital clock. Coincidently, it functions like a clock. + +18.HDD Info -- In the middle, at the bottom -- This shows some information about your connected HDD (only the WBFS partition). Free & total space in GB as well as the game count. GB is defined here as 1024MB. When you bought your drive, the manufacturer probably used 1000MB for GB so the size displayed here will be less than what your drive was advertised as. The game count will reflect the games you are choosing to display, not the actual amount of games on your drive. If you are hiding games with parental controls/favorites, they will not be added into this total. + +################################### + +[3c] View + +There are 3 different ways to view your games. + +List --- Games are listed by name (up to 9 at a time) box art for the selected game is displayed. This is currently the only screen you can initiate a download for artwork from. Also on this screen The B button has a slightly different use. If there are scrollbars present on your gamelist, holding B and moving the cursor scrolls the list. + +Grid --- Games are arranged in a grid (up to 320). The number of rows available depends on how many games are on you drive. By default, it is 3X14 (with the last column hidden)if there aren’t enough games to fill all 42 spots, it changes to 2x8 (2x7 shown on screen). Again, if there aren’t enough games to fill it up, the number of rows decreases. + +Carousel --- Games are arranged in a rotating fan array (up to 320). Up to 7 games can be seen at a time. + +################################### + +[3d] Game Info + +Pressing 2 (or X on CC input) brings a prompt with information about the selected game. This info is read from the wiitdb.zip file discussed earlier. Among the displayed information are the following: + +Accessories --- The supported accessories for the game are shown in the lower left. The max number of players is shown on the image of the WiiMote. Any required accessories are shown in light blue. + +Rating system --- The rating for the game is shown in the lower left of the screen. It is converted internally between PEGI,ESRB, and CERO (though not used for anything yet). + +Wifi --- The number of online players is displayed to the right of the accessories. Any other wifi features are listed above the accessories. + +Synopsis --- If a synopsis is present in the file, it can be viewed by pressing A on the game info screen. You need to set the game language to the language of synopsis you want to view! + +Wiitdb.zip will get updated when you update all or update the full channel. Only the info for the games and language you have will be downloaded. If you do not have the possibility to update with the loader because you have no Wifi, go to the game info screen and press 1 (Rev637 or higher needed). It will store a link in a file as shown at the bottom. Open the file and copy the link. Then open it with a web browser to download the file. Place the Wiitdb.zip in the titles.txt path. + +################################### + +[3e] Game Prompt + +This is the prompt that comes up when a game is selected (if the quickboot option is disabled). + +Play --- Click the spinning disc to launch this game. + +Rename ***** --- Click the title of the game in the top of the prompt to rename it directly on the WBFS file system. If you are using titles.txt or wiitdb.zip, this will have no (visible) effect. + +Back --- Closes this prompt. + +Favorite --- Click the star to add/remove this game from your favorites. + +Size --- The amount of space that the game occupies on the WBFS. + +Count --- The number of times you have launched this game using this application. + +Settings ***** --- Here is where you go to enter settings that will be used for this game only. + + +________________ +[4] Exit Menu + +This is the screen that appears when you press the home button on the WiiMote or the exit button in the main screen. + +Return to loader --- if you launched USB Loader GX from HBC, LoadMii, or similar chain loading application, you will see this button. Pressing it will take you back to the application you came from. + +Homebrew Channel --- Brings you to the homebrew channel + +Wii Menu --- Exits to the Wii System Menu. + +Batteries --- Status for all connected WiiMotes is displayed here. + +Close --- Closes this screen and returns you to where you were in the application before this screen was called. + + +________________ +[5] Homebrew&Title Launcher ***** +[5a] Homebrew Launcher + + +New since rev627 is the Homebrew Launcher. You can activate this function by clicking on the icon right of the HDD info at the main screen (the button looks like the Homebrew channel). Just like the HBC, all apps of the specified folder will be shown in groups of 4. The images of the apps are shown on the left, and the name to the right. When you click an app, the info in the meta.xml will be shown. + +Folders of homebrew must contain a .dol or .elf . Unlike the HBC they do not have to be renamed to boot.dol or boot.elf . +The folder may also contain an icon.png (size 128x48), meta.xml and other data that the app needs to run. + +################################### + +[5b] Title Launcher + +Since rev648 it is also possible to load channels. To access the title (channel) launcher, go to the Homebrew launcher. There you will see two buttons in the bottom right. The first (left) button leads to the title launcher. +If you want the correct names of the channels to display, you need a database.txt found here: http://pastebin.com/f6fb1533b. Place it in the config folder. +You are free to edit this file online, but do not add Homebrew channels. These have title IDs that can be different on other wiis. + +################################### + +[5c] (Un)Installing WADs over wifi + +FOR ADVANCED USERS ONLY! + +EASY METHOD + +Guide by GBAtemp member NeoRame + +1) Download the wiiload installer found here +2) Connect the wii to wifi. Go to the Homebrew channel and press Home. You will find your wiis IP here. +3) Run the Installer and choose next. Enter the wii IP and choose install. +4) Launch the USB loader GX and go to the Homebrew Launcher, then go to the Title (channel) launcher. +5) On your PC, double click a .wad .dol or .elf to send it to the Wii (You can also right click and choose Send to wii). If you send a wad, you will be asked to (un)install it or not. + +NOTE: If you can't get it to work, reboot your computer and try again. + +DIFFICULT METHOD (Use if the easy one doesn't work) + +Guide made by GBAtemp member Logan +What you will need: + + + * Your Wii's IP address (see below for details) + * WiiLoad + * This guide is for Windows only. I don't use Linux + + +1) Download WiiLoad from the above link and extract the contents. +2) Copy/Move wiiload.exe to C:\Windows\System32\ +3) Open Notepad and copy the following into it: + +Windows Registry Editor Version 5.00 + +[HKEY_CLASSES_ROOT\.WAD] +@="" + +[HKEY_CLASSES_ROOT\.WAD\shell] + +[HKEY_CLASSES_ROOT\.WAD\shell\Send to Wii!] + +[HKEY_CLASSES_ROOT\.WAD\shell\Send to Wii!\command] +@="c:\\windows\\system32\\wiiload.exe \"%1\"" +4) Save the file as "wiiload.reg" +5) Double click the file and accept entering the entries into the registry. +6) Boot up your Wii and load the USB loader GX. Go to the Homebrew Launcher and hover over the WiFi Wii icon. A tooltip will pop up showing your IP address. Make a note of it. +7) Set the environment variable by going to your computer's Control Panel -» System -» Advanced -» Environment Variables, then click "new" under either category. The variable name is WIILOAD and the value is tcp:yourIP, where yourIP is the Wii's IP/hostname. Click "OK" here and in System Properties. +8) Now go to the title (channel) browser on your wii. On your PC, right click on a .WAD file and you should now see a "Send to Wii!" option. Click on this and watch the magic work at the Wii end of business. +9) [Optional] Double click on a .WAD file and choose c:\windows\system32\wiiload.exe as the application to open it. Now double clicking .WAD files will send them to your Wii. +10) To uninstall, simply send the same .WAD file to the Wii. + +Use your noggin when dealing with WAD's. I won't be held accountable for any misuse! + + +________________ +[6] Settings + +This is where you customize the behavior of the program. + +################################### + +[6a] Gui settings + +These are the settings that affect the behavior and feel of the GUI. Your settings are saved when exiting back to the main screen, change custom paths, change views in the main screen, and a few other times. + +App language ***** --- If you have a language file to translate this program, you can select it here. You can change the path by clicking it at the top of the screen. The button in the lower right will restore the default (English). +NOTE: Newest revs will automatically load your language if it is found. + +Display --- In the list view, you can chose to display the selected game's region and ID here. + +Clock --- Choose how you want the clock displayed. + +Tooltips --- Enable tooltip help you with the various buttons and options. + +Flip-X --- This changes the behavior of left and right on the game prompt and Grid/Carrousel. If it feels un-natural, change this setting. + +Prompts/Buttons --- Select whether or not to apply the widescreen fix to prompt windows and certain buttons in the GUI. + +Keyboard --- Choose between different layouts for the on-screen keyboard used in the GUI. + +Discimage Download --- Select what discimages have to be downloaded +Only Original: Always get original discart +Only Customs: Always get custom discart +Original/Customs: Get original discart. Get custom discart if original is not available +Customs/Original: Get custom discart. Get original discart if cutom is not available + +Wiilight --- Change the behavior of the disc slot light. + +Rumble --- Turn rumble on/off. + +Auto init. network --- Turn this ON to automatically initialize the network at boot. If a new update is available, you will be asked if you want to download it. +IMPORTANT: Turning on this function may cause malfunctioning of the loader and games! + +Titles from XML --- Choose if you want to ignore the titles stored on the xml file (in wiitdb.zip) or titles.txt and use the ones stored on the WBFS. + +Screensaver --- Set how long it will take to activate the screensaver in case of inactivity. The screensaver switches off the Wiimote. + +################################### + +[6b] Game load + +Change settings that have to do with the way games are booted. These will be use as default if you don't set any specific settings for that game. + +Video mode --- Select the video mode to use for games. Most games work with disc default. If this doesn't work, try console default. Then if you still need to, try forcing your region. + +vidTV patch --- Patches the signal after the game has rendered it in the mode selected in video mode. If none of the video modes work, try this. + +Game language --- The language that is passed to the game when it is booted. If the language is supported by the game, it will be used in game. + +Patch country strings --- Use this for Japanese imports. + +Ocarina-- Turn on/off the ocarina cheat engine. You need gct files in the cheatcode path mentioned earlier. + +Boot/standard ***** --- Select the cIOS that is used to boot the program into. + +Quickboot --- Choose if you want to skip the game prompt when starting games. + +Error 002 fix --- With certain IOS, some games show an error that says "blablabla, 002, blablabla. Don't be a pirate." Turn this on to fix it. +Anti: Some cIOS have 002fix build-in. Unfortunately, this makes some games unplayable (the reason for this is that there are 2 types of 002 fix, and some games won't play with the one found in some cIOS). Activate the Anti002fx to play these games. Known games that need Anti002fix (they use 002fix on with some cIOS): Burger Island, Diabolik The Original Sin, Ghostbusters, Indiana Jones and the Staff of Kings, MySims Racing, Nutrition Matters, Solitaire And Mahjong, Takt of Magic + +################################### + +[6c] Parental control + +Settings for parents to control what content their kids see. Everything in this document with ***** beside it is hidden/unusable when the application is locked. + +Console --- Click here to lock/unlock advanced features. Requires password to unlock. + +Password ***** --- Click here to set a password. When locked it's shown as ******** + +Control level ***** --- Set the level of parental control here. Games will be excluded from the game list based on this and the settings you have for them in the game-specific settings. Also shown as ******** when the loader is locked. + +################################### + +[6d] Sound + +Settings related to audio are here. + +Background music --- You can chose custom BG music to be heard in the application here. Click the path at the top to change it. Format is OGG. Keep in mind that bigger songs will result in decreased memory available for other functions. It is possible to completely crash the loader with big files. Try to keep it «3MB to be safe. If you want to rock out to your music, use a media player. This is a game loader. + +Music volume --- Pick the volume for the BG music within this application, not in the games that are booted. + +SFX volume --- Pick the volume for the sound effects within this application, not in the games that are booted. + +################################### + +[6e] Custom paths ***** + +Below paths the program uses are customizable. Click a path to browse for its new destination. + +3D Cover Path --- For 3D boxart. When properly defined, 3D cover art will display in List and Carousel views by default. + +2D Cover Path --- For 2D boxart. When properly defined, 2D cover art will display in Grid view by default. + +Discimage path --- For Discart. + +Theme path --- For themes. + +XMLpath ---For wiitdb.zip + +Update path --- Used for updating the dol. If you are using our forwarder, it loads dols from this path. + +Cheatcodes path --- For gct & ocarina use. + +Txtcheatcodes path --- For txt files holding the codes for the code manager + +Dol path --- Contains replacement dols (Alternate dols) for certain broken games. + +Homebrew apps path --- Where you place your homebrew apps for the Homebrew Loader. + +################################### + +[6f] Update ***** + +Click to get updates online. Just because there is a newer revision than what you are using does not mean that it will be on the update server. Also, you get the choice to update dol or update all. The last option will update the dol, HBC icon.png and meta.xml + +It is also possible to update the full channel (This will also download wiitdb.zip). The channel needs a small change in the code before it can be updated. If you have a channel and you see the update all button, you can not update the channel. You have to get another one. + +################################### + +[6g] Default settings ***** + +Click here to restore default settings. You can also delete GXGlobal.cfg to do this if you get an error at boot. + +################################### + +[6h] Credits + +Look at the people that made this application possible. You get to rock out to some cool music, too. In the upper right corner you can see your rev# and the cIOS that your are currently running. + + +________________ +[7] Game settings ***** + + +Settings are available on a per-game basis from the prompt window. These settings have the same effect as the global settings, but are only used for the selected game. +NOTE: If quickboot is enabled, you cannot change the settings. So make sure you configure them before enabling quickboot. + +################################### + +[7a]Game load +After making changes, you must click the save button for them to take effect! + +Videomode --- see [6b] Game load +vidTV patch --- see [6b] Game load +Game language --- see [6b] Game load +Ocarina --- see [6b] Game load +Ios --- see [6b] Game load +Parental control --- see [6b] Game load +Error002 fix --- see [6b] Game load +Patch country strings --- see [6b] Game load + +Alternate dol --- This is for advanced users only. There are certain games that do not run because they reload IOS and this causes the USB to be dropped. +Select a dol: Use the next option to browse for an alt dol on the WBFS partition +Dol from SD/USB: Extract the proper dol from the ISO (using wiiscrubber) and name it with the 6 character game ID and put in the dolpath. + +Selected dol --- If you put Alternate dol on 'Select a dol', this function can be used to do so. (Even if the box is empty, you can click it) + +Save --- Writes the settings that are on the screen right now to the GXGameSettings file, behind the current game ID. + +################################### + +[7b]Ocarina + +Opens the cheat manager. For more info, see [8]Cheating + +################################### + +[7c] Uninstall Menu +If you click this button, you will see a new menu. You can uninstall everything here: the game, boxart, discart and TXTcheat file. You can also reset the playcounter here. + +################################### + +[7d]Default settings + +Restore all default settings for the game. (The default settings can be changed in [6b]Game load) + + +________________ +[8]Cheating + +With the build in application called Ocarina, it is possible to cheat by using the USB loader GX. To enable cheats, you will need a gct file with the gameID of the game in the correct path. (The cheatcodes path, see custom paths) + +There are two ways to create a gct file. For both, you will need a txt file that contains all the codes for the game. + +################################### + +[8a] Using a Computer + +All needed txt files can be found on http://geckocodes.org/. If you cannot find codes for your game, it means there are no codes available for that game. +To turn the txt files in gct files, you need the codemgr. It is included in the Ocarina download (check wiibrew.org). + +Open the txt file with the codemgr. You will see all the codes that are in the txt file. Sometimes the txt file has errors. In that case you need to open it manually with a txt editor. You can select all the cheats you want to enable. + +Some codes require that you fill in an amount of XX or other letters to make the code work. The values can usually be found in the comments. Select the letters you want to change and type the correct value over them. Then click ‘store settings’. + +If you filled everything in and enabled all cheats you want, click the ‘export to gct’ button. Choose the SD/USB you want to store the file to. It will create a file in the map codes. If you changed the path in the settings of the loader, you have to place the gct file in the right direction. + +################################### + +[8b] Using the USB loader + +Go to the Game settings. There, choose ocarina. If it doesn’t find a txt file with the gameID of the current game, you will be asked if you want to download it. You can also manually download the txt file, but don’t forget to rename it to the correct title ID (and place it in the txtcodes path, see custom paths). After you downloaded it, use the same Ocarina button to go to the code manager. Select all codes you want to enable, then click 'create' if you’re done. NO LETTERS CAN BE CHANGED USING THIS METHOD. TO MAKE THE CODES WORK THAT CONTAIN THEM, EDIT THE TXT FILE OR USE THE CODEMGR! It will bring you back to the gamesettings screen. + +################################### + +After you used on of above methods to create your gct file, enable ocarina in the game settings (game load), save and boot the game. + + +________________ +[9]Themes + +It is possible to theme this program. Many of the images can be replaced and moved. Every theme must include a GXTheme.cfg in the same folder as where you put the images. Here is a list of what you can put into the GXtheme.cfg : +#################### GXTheme.cfg ##################### +## Copy to a txt file and rename it to GXTheme.cfg. ## +## Don't touch lines starting with # ## +## Values between [] are defaults ## +###################################################### + +#### coordinates: x and y are coordinates in pixels, width and height are also in pixels #### + +## battery1_coords = x,y -- [245,400] -- For battery indicator 1 (exit menu) +battery1_coords = 245,400 + +## battery2_coords = x,y -- [335,400] -- For battery indicator 2 (exit menu) +battery2_coords = 335,400 + +## battery3_coords = x,y -- [245,425] -- For battery indicator 3 (exit menu) +battery3_coords = 245,425 + +## battery4_coords = x,y -- [335,425] -- For battery indicator 4 (exit menu) +battery4_coords = 335,425 + +## clock_coords = x,y -- [0,335] -- For the clock +clock_coords = 0,335 + +## covers_coords = x,y -- [26,58] -- For the game covers (list view) +covers_coords = 26,58 + +## gamecarousel_coords = x,y,width,height -- [0,-20,640,400] -- For the carousel (carousel view) +gamecarousel_coords = 0,-20,640,400 + +## gamecarousel_favorite_coords = x, y -- for the favoriteIcon in game-carousel-mode +## gamecarousel_search_coords = x, y -- for the searchIcon in game-carousel-mode +## gamecarousel_abc_coords = x, y -- for the abcIcon in game-carousel-mode +## gamecarousel_count_coords = x, y -- for the countIcon in game-carousel-mode +## gamecarousel_list_coords = x, y -- for the listIcon in game-carousel-mode +## gamecarousel_grid_coords = x, y -- for the gridIcon in game-carousel-mode +## gamecarousel_carousel_coords = x, y -- for the carouselIcon game-carousel-mode +## gamecarousel_dvd_coords = x, y -- for the dvdIcon game-carousel-mode + +## gamecount_coords = x,y -- [0,430] -- For the gamecount (below HDD info) +gamecount_coords = 0,430 + +## gamegrid_coords = x,y,width,height -- [0,20,640,400] -- For the gamegrid (grid view) +gamegrid_coords = 0,20,640,400 + +## gamegrid_favorite_coords = x, y -- for the favoriteIcon in game-grid-mode +## gamegrid_search_coords = x, y -- for the searchIcon in game-grid-mode +## gamegrid_abc_coords = x, y -- for the abcIcon in game-grid-mode +## gamegrid_count_coords = x, y -- for the countIcon in game-grid-mode +## gamegrid_list_coords = x, y -- for the listIcon in game-grid-mode +## gamegrid_grid_coords = x, y -- for the gridIcon in game-grid-mode +## gamegrid_carousel_coords = x, y -- for the carouselIcon in game-grid-mode +## gamegrid_dvd_coords = x, y -- for the dvdIcon in game-grid-mode + +## gamelist_coords = x,y,width,height -- [200,49,396,280] -- For the list of games (list view) +gamelist_coords = 200,49,396,280 + +## gamelist_favorite_coords = x, y -- for the favoriteIcon in game-list-mode +## gamelist_search_coords = x, y -- for the searchIcon in game-list-mode +## gamelist_abc_coords = x, y -- for the abcIcon in game-list-mode +## gamelist_count_coords = x, y -- for the countIcon in game-list-mode +## gamelist_list_coords = x, y -- for the listIcon in game-list-mode +## gamelist_grid_coords = x, y -- for the gridIcon in game-list-mode +## gamelist_carousel_coords = x, y -- for the carouselIcon in game-list-mode +## gamelist_dvd_coords = x, y -- for the dvdIcon in game-list-mode + +## hddinfo_coords = x,y -- [0,410] -- For the HDD info +hddinfo_coords = 0,410 + +## home_coords = x,y -- [485,367] -- For the exit menu button +home_coords = 485,367 + +## homebrew_coords = x,y - [425,400] -- For the Homebrew launcher button +homebrew_coords = 425,400 + +## id_coords = x,y -- [68,305] -- For the game ID (list view) +id_coords = 68,305 + +## install_coords = x,y -- [16,355] -- For the install button +install_coords = 16,355 + +## power_coords = x,y -- [576,355] -- For the power button +power_coords = 576,355 + +## region_coords = x,y -- [68,30] -- For the region (list view) +region_coords = 68,30 + +## sdcard_coords = x,y -- [150,390] -- For the Reload SD button +sdcard_coords = 150,390 + +## setting_coords = x,y -- [60,367] -- For the settings button +setting_coords = 60,367 + +#### show: 0 = don't show, 1 = show #### + +## show_battery = show -- [1] -- Show the battery indicators +show_battery = 1 + +## show_gamecount = show -- [1] -- Show the gamecount +show_gamecount = 1 + +## show_hddinfo = show -- [1] -- Show the hdd info +show_hddinfo = 1 + +## show_id = show -- [1] -- Show the game ID +show_id = 1 + +## show_region = show -- [1] -- Show the region +show_region = 1 + +## show_tooltip = show -- [1] -- Show tooltips +show_tooltip = 1 + +#### colors: red, green and blue go from 0 to 255 #### + +## clock_color = red,green,blue(,alpha) -- [138,138,138(,255)] -- Color of the clock +clock_color = 138,138,138(,255) + +## gametext_color = red,green,blue(,alpha) -- [0,0,0(,255)] -- Color of the gametext +gametext_color = 0,0,0(,255) + +## info_color = red,green,blue(,alpha) -- [55,190,237(,255)] -- Color of info (like HDD info) +info_color = 55,190,237(,255) + +## prompttext_color = red,green,blue(,alpha) -- [0,0,0(,255)] -- Color of text in prompts +prompttext_color = 0,0,0(,255) + +## settingstext_color = red,green,blue(,alpha) -- [0,0,0(,255)] -- Color of the text in the settings +settingstext_color = 0,0,0(,255) + +#### transparency: Alpha = from 0 (fully transparent) to 255 (Not transparent) + +## batteryUnused = Alpha -- [70] -- Transparancy of Battery indicators that are not used +batteryUnused = 70 + +## tooltipAlpha = Alpha -- [255] -- Transparency of tootltips +tooltipAlpha = 255 + +#### Allign: Allign = left/centre/right #### + +## clock_allign = Allign -- [centre] -- For the clock +clock_allign = centre + +## gamecount_allign = Allign -- [centre] -- Allign of the gamecount +gamecount_allign = centre + +## hddinfo_allign = Allign -- [centre] -- Align of the HDD info +hddinfo_allign = centre + +#### others #### + +## maxcharacters = x -- [36] -- Amount of characters shown before text starts scrolling left. (long text) +maxcharacters = 36 + +## pagesize = x -- [9] -- Amount of games in the list (list view) +pagesize = 9 + +## sortBarOffset = x -- [1] -- Amount of pixels the sortbar jump right when going to grid/carousel +sortBarOffset = 100 + + +________________ +[10]Special Games + +This section will explain on how to run some games with special boot methods. +The methods for Alt-dol from SD are explained here. You can also use Alt-dol from disc (use the same dols). If you have to rename the dol, replace the X by E (NTSC-U), P (PAL) or J (NTSC-J)! + + +[10a]Wii Sports Resort + +IMPORTANT: Wii sports resort requires the WII MOTION PLUS. If you do not have it, you can not run this game! +Booting WSR isn't too difficult. But as its different from usual booting methods, it is listed here. + +1) When you boot it for the first time, Alt dol loading must be enabled. +Alt dol info: Extract the player.dol and rename it to RZTX01.dol +Depending on your cIOS, 002fix or Anti002fix may be needed. +2) Watch the WM+ instruction video. After you watched it, the Wii will crash, so reboot. +3) From now on, load the game with Alt-Dol OFF + + +[10b]Metroid Prime Trilogy +Remove the disc before starting MPT! + +Select a DOL +1) First time boot the game without alt-dol (If this doesn't work, enable Dol from disc and use rs5fe_p.dol). Create a save file and exit the game. +2) From now, always use dol from Disc and choose the dol of the game you want to play: +rs5mp1_p.dol for Metroid Prime 1 +re5mp2_p.dol for Metroid Prime 2 +rs5mp3_p.dol for Metroid prime 3 +Then save and boot the game. +You need to do this EVERY time you boot the game + +Load From SD/USB +This is one of the most difficult games to boot from USB. First, you need to extract 3 alt-dols: +rs5mp1_p.dol for Metroid Prime 1 +re5mp2_p.dol for Metroid Prime 2 +rs5mp3_p.dol for Metroid prime 3 + +1) First time boot the game without alt-dol (If this doesn't work, extract rs5fe_p.dol, rename it to R3MX01.dol and boot the game with this alt-dol). Create a save file and exit the game. +2) Now the difficult part: All 3 alt dols have to be named R3MX01.dol . For this to be possible, you have to make a folder for each one. Every time you want to change game, you have to change the alt-dol path. The alt-dol that is used decides which game is play-able in the trilogy. + +Method to get MP3 working (NOTE: some versions of MPT can't boot MP3, evn with this method): +1) Install Hermes cIOS222 +2) In global game load, set Boot/standard to cIOS222 and enable 002fix +3) In specific game load, use cIOS222 +4) Run the game with the MP3 alt-dol +5) If the you get a black screen or an error message (Please Insert Metroid Prime 3 Disc), try inserting ANY DVD into the drive. Blank DVDs are acceptable. + + +________________ + +[11]FAQ + + +Q: Does this loader work on system menu X ? +A: Yes, it works on any system menu + + +Q: The Usb loader can’t find my HDD. What do I do now? +A: Be sure to have cIOSr9 or above (Or one of Hermes’ cIOS). If you use cIOSr12 or greater you have to try both USB ports! If this doesn’t work, check if your drive is compatible (use the devices compatibility wiki at the top of this readmii) + +Q: How can I use other usb devices (like Wii speak) in my games? +A: Install cIOSr12 or above. One port will be for the HDD and the other one for the device you want to use. + +Q:Do I have to rename all my games manually? +A:No. You can use wiitdb.zip to rename games automatically. More info in [2c] + +Q: Can I use the titles.txt to rename my games +A: No. Support for titles.txt has been dropped. Use wiitdb.zip + + +Q: I saw there is a newer rev available. Why can't update with the loader (it says no update available)? +A: The updates for the loader are on a different server. Not every rev will be available for download. Most revs will be available from http://usbloadergx.koureio.net/downloads/revisions. + + +Q: What does update all do? +A: It updates the dol (the loader itself), the icon.png and meta.xml for HBC, the language files and wiitdb.zip + +Q: Can I update the full channel? +A: Yes. If you have the channel version installed, there will be no update all function. If you do see this button, the channel is not correctly modified (see [2a]) so you can’t update it (also check the rev# in the credits, it should end with the letter c). In that case get another channel. + + +Q: Where can I see my rev# ? +A: Go to the Credits. The rev# will be at the top right corner. If it ends with c you are using the full channel. + + +Q: Can I use this loader in my own language? +A: This loader currently supports: Chinese (simple and trad.), Czech, Danish, Dutch, English, Finnish, French, German, Hungarian, Italian, Japanese, Korean, Norwegian, Polish, Portuguese, Russian, Spanish, Swedish, Thai and Turkish. +All languages are frequently updated by the GX language teams (I'm the Dutch translator). You can find us at http://gbatemp.net/index.php?showtopic=155252 + + +Q: I have a problem and the answer is not in this readmii. What do I do? +A: You can always ask questions at the GX forum: http://forum.koureio.net/ .You can find me (tj_cool) and the GX team there as well. \ No newline at end of file diff --git a/data/binary/app_booter.bin b/data/binary/app_booter.bin new file mode 100644 index 0000000..08d1806 Binary files /dev/null and b/data/binary/app_booter.bin differ diff --git a/data/binary/custom_banner.bnr b/data/binary/custom_banner.bnr new file mode 100644 index 0000000..7e94532 Binary files /dev/null and b/data/binary/custom_banner.bnr differ diff --git a/data/binary/stub.bin b/data/binary/stub.bin new file mode 100644 index 0000000..63a37a0 Binary files /dev/null and b/data/binary/stub.bin differ diff --git a/data/fonts/clock.ttf b/data/fonts/clock.ttf new file mode 100644 index 0000000..5a252b2 Binary files /dev/null and b/data/fonts/clock.ttf differ diff --git a/data/fonts/font.ttf b/data/fonts/font.ttf new file mode 100644 index 0000000..01ce581 Binary files /dev/null and b/data/fonts/font.ttf differ diff --git a/data/images/abcIcon.png b/data/images/abcIcon.png new file mode 100644 index 0000000..19b39e0 Binary files /dev/null and b/data/images/abcIcon.png differ diff --git a/data/images/add.png b/data/images/add.png new file mode 100644 index 0000000..2be63d7 Binary files /dev/null and b/data/images/add.png differ diff --git a/data/images/addressbar_textbox.png b/data/images/addressbar_textbox.png new file mode 100644 index 0000000..77007f5 Binary files /dev/null and b/data/images/addressbar_textbox.png differ diff --git a/data/images/arrangeBannerGrid.png b/data/images/arrangeBannerGrid.png new file mode 100644 index 0000000..720c8e0 Binary files /dev/null and b/data/images/arrangeBannerGrid.png differ diff --git a/data/images/arrangeBannerGrid_gray.png b/data/images/arrangeBannerGrid_gray.png new file mode 100644 index 0000000..d86b3c1 Binary files /dev/null and b/data/images/arrangeBannerGrid_gray.png differ diff --git a/data/images/arrangeCarousel.png b/data/images/arrangeCarousel.png new file mode 100644 index 0000000..b8162cf Binary files /dev/null and b/data/images/arrangeCarousel.png differ diff --git a/data/images/arrangeCarousel_gray.png b/data/images/arrangeCarousel_gray.png new file mode 100644 index 0000000..c7955d5 Binary files /dev/null and b/data/images/arrangeCarousel_gray.png differ diff --git a/data/images/arrangeGrid.png b/data/images/arrangeGrid.png new file mode 100644 index 0000000..1b1be84 Binary files /dev/null and b/data/images/arrangeGrid.png differ diff --git a/data/images/arrangeGrid_gray.png b/data/images/arrangeGrid_gray.png new file mode 100644 index 0000000..f8e066d Binary files /dev/null and b/data/images/arrangeGrid_gray.png differ diff --git a/data/images/arrangeList.png b/data/images/arrangeList.png new file mode 100644 index 0000000..9a11608 Binary files /dev/null and b/data/images/arrangeList.png differ diff --git a/data/images/arrangeList_gray.png b/data/images/arrangeList_gray.png new file mode 100644 index 0000000..59c6410 Binary files /dev/null and b/data/images/arrangeList_gray.png differ diff --git a/data/images/background.png b/data/images/background.png new file mode 100644 index 0000000..1a482c7 Binary files /dev/null and b/data/images/background.png differ diff --git a/data/images/balanceboard.png b/data/images/balanceboard.png new file mode 100644 index 0000000..d713380 Binary files /dev/null and b/data/images/balanceboard.png differ diff --git a/data/images/balanceboardR.png b/data/images/balanceboardR.png new file mode 100644 index 0000000..ee2de74 Binary files /dev/null and b/data/images/balanceboardR.png differ diff --git a/data/images/battery.png b/data/images/battery.png new file mode 100644 index 0000000..9a4c9af Binary files /dev/null and b/data/images/battery.png differ diff --git a/data/images/battery_bar.png b/data/images/battery_bar.png new file mode 100644 index 0000000..3aff741 Binary files /dev/null and b/data/images/battery_bar.png differ diff --git a/data/images/battery_bar_red.png b/data/images/battery_bar_red.png new file mode 100644 index 0000000..bc09b4c Binary files /dev/null and b/data/images/battery_bar_red.png differ diff --git a/data/images/battery_bar_white.png b/data/images/battery_bar_white.png new file mode 100644 index 0000000..528b340 Binary files /dev/null and b/data/images/battery_bar_white.png differ diff --git a/data/images/battery_red.png b/data/images/battery_red.png new file mode 100644 index 0000000..458b736 Binary files /dev/null and b/data/images/battery_red.png differ diff --git a/data/images/battery_white.png b/data/images/battery_white.png new file mode 100644 index 0000000..a2812c5 Binary files /dev/null and b/data/images/battery_white.png differ diff --git a/data/images/bg_browser.png b/data/images/bg_browser.png new file mode 100644 index 0000000..a2c03f3 Binary files /dev/null and b/data/images/bg_browser.png differ diff --git a/data/images/bg_browser_selection.png b/data/images/bg_browser_selection.png new file mode 100644 index 0000000..d9f4978 Binary files /dev/null and b/data/images/bg_browser_selection.png differ diff --git a/data/images/bg_options.png b/data/images/bg_options.png new file mode 100644 index 0000000..389cfa1 Binary files /dev/null and b/data/images/bg_options.png differ diff --git a/data/images/bg_options_entry.png b/data/images/bg_options_entry.png new file mode 100644 index 0000000..532b5e3 Binary files /dev/null and b/data/images/bg_options_entry.png differ diff --git a/data/images/bg_options_settings.png b/data/images/bg_options_settings.png new file mode 100644 index 0000000..49ca299 Binary files /dev/null and b/data/images/bg_options_settings.png differ diff --git a/data/images/boxBorder.png b/data/images/boxBorder.png new file mode 100644 index 0000000..9a4bc8a Binary files /dev/null and b/data/images/boxBorder.png differ diff --git a/data/images/browser.png b/data/images/browser.png new file mode 100644 index 0000000..f6400cd Binary files /dev/null and b/data/images/browser.png differ diff --git a/data/images/browser_over.png b/data/images/browser_over.png new file mode 100644 index 0000000..59b1547 Binary files /dev/null and b/data/images/browser_over.png differ diff --git a/data/images/button_dialogue_box.png b/data/images/button_dialogue_box.png new file mode 100644 index 0000000..23d2b2e Binary files /dev/null and b/data/images/button_dialogue_box.png differ diff --git a/data/images/button_install.png b/data/images/button_install.png new file mode 100644 index 0000000..6973733 Binary files /dev/null and b/data/images/button_install.png differ diff --git a/data/images/button_install_over.png b/data/images/button_install_over.png new file mode 100644 index 0000000..9ffc0f5 Binary files /dev/null and b/data/images/button_install_over.png differ diff --git a/data/images/category.png b/data/images/category.png new file mode 100644 index 0000000..17149fa Binary files /dev/null and b/data/images/category.png differ diff --git a/data/images/categoryPrompt.png b/data/images/categoryPrompt.png new file mode 100644 index 0000000..3425072 Binary files /dev/null and b/data/images/categoryPrompt.png differ diff --git a/data/images/category_gray.png b/data/images/category_gray.png new file mode 100644 index 0000000..74907fd Binary files /dev/null and b/data/images/category_gray.png differ diff --git a/data/images/cero_a.png b/data/images/cero_a.png new file mode 100644 index 0000000..31d989f Binary files /dev/null and b/data/images/cero_a.png differ diff --git a/data/images/cero_b.png b/data/images/cero_b.png new file mode 100644 index 0000000..3358e0a Binary files /dev/null and b/data/images/cero_b.png differ diff --git a/data/images/cero_c.png b/data/images/cero_c.png new file mode 100644 index 0000000..b024869 Binary files /dev/null and b/data/images/cero_c.png differ diff --git a/data/images/cero_d.png b/data/images/cero_d.png new file mode 100644 index 0000000..6eb1b4b Binary files /dev/null and b/data/images/cero_d.png differ diff --git a/data/images/cero_z.png b/data/images/cero_z.png new file mode 100644 index 0000000..6b5a48c Binary files /dev/null and b/data/images/cero_z.png differ diff --git a/data/images/channel_btn.png b/data/images/channel_btn.png new file mode 100644 index 0000000..dc46e47 Binary files /dev/null and b/data/images/channel_btn.png differ diff --git a/data/images/checkBoxSelection.png b/data/images/checkBoxSelection.png new file mode 100644 index 0000000..4b01949 Binary files /dev/null and b/data/images/checkBoxSelection.png differ diff --git a/data/images/classiccontroller.png b/data/images/classiccontroller.png new file mode 100644 index 0000000..92f81df Binary files /dev/null and b/data/images/classiccontroller.png differ diff --git a/data/images/classiccontrollerR.png b/data/images/classiccontrollerR.png new file mode 100644 index 0000000..e3d051d Binary files /dev/null and b/data/images/classiccontrollerR.png differ diff --git a/data/images/closebutton.png b/data/images/closebutton.png new file mode 100644 index 0000000..b2100d9 Binary files /dev/null and b/data/images/closebutton.png differ diff --git a/data/images/credits_bg.png b/data/images/credits_bg.png new file mode 100644 index 0000000..3ce92fd Binary files /dev/null and b/data/images/credits_bg.png differ diff --git a/data/images/credits_button.png b/data/images/credits_button.png new file mode 100644 index 0000000..510df76 Binary files /dev/null and b/data/images/credits_button.png differ diff --git a/data/images/credits_button_over.png b/data/images/credits_button_over.png new file mode 100644 index 0000000..92bb0b7 Binary files /dev/null and b/data/images/credits_button_over.png differ diff --git a/data/images/dancepad.png b/data/images/dancepad.png new file mode 100644 index 0000000..5519144 Binary files /dev/null and b/data/images/dancepad.png differ diff --git a/data/images/dancepadR.png b/data/images/dancepadR.png new file mode 100644 index 0000000..1b3ae1c Binary files /dev/null and b/data/images/dancepadR.png differ diff --git a/data/images/dialogue_box.png b/data/images/dialogue_box.png new file mode 100644 index 0000000..d16b96c Binary files /dev/null and b/data/images/dialogue_box.png differ diff --git a/data/images/dialogue_box_startgame.png b/data/images/dialogue_box_startgame.png new file mode 100644 index 0000000..bd68429 Binary files /dev/null and b/data/images/dialogue_box_startgame.png differ diff --git a/data/images/drums.png b/data/images/drums.png new file mode 100644 index 0000000..ee2e000 Binary files /dev/null and b/data/images/drums.png differ diff --git a/data/images/drumsR.png b/data/images/drumsR.png new file mode 100644 index 0000000..0183692 Binary files /dev/null and b/data/images/drumsR.png differ diff --git a/data/images/dvd.png b/data/images/dvd.png new file mode 100644 index 0000000..43d71b5 Binary files /dev/null and b/data/images/dvd.png differ diff --git a/data/images/dvd_gray.png b/data/images/dvd_gray.png new file mode 100644 index 0000000..84cdeb1 Binary files /dev/null and b/data/images/dvd_gray.png differ diff --git a/data/images/esrb_ao.png b/data/images/esrb_ao.png new file mode 100644 index 0000000..5004a5c Binary files /dev/null and b/data/images/esrb_ao.png differ diff --git a/data/images/esrb_e.png b/data/images/esrb_e.png new file mode 100644 index 0000000..a13af0c Binary files /dev/null and b/data/images/esrb_e.png differ diff --git a/data/images/esrb_ec.png b/data/images/esrb_ec.png new file mode 100644 index 0000000..3d15720 Binary files /dev/null and b/data/images/esrb_ec.png differ diff --git a/data/images/esrb_eten.png b/data/images/esrb_eten.png new file mode 100644 index 0000000..4defe77 Binary files /dev/null and b/data/images/esrb_eten.png differ diff --git a/data/images/esrb_m.png b/data/images/esrb_m.png new file mode 100644 index 0000000..a5d29da Binary files /dev/null and b/data/images/esrb_m.png differ diff --git a/data/images/esrb_t.png b/data/images/esrb_t.png new file mode 100644 index 0000000..b9549ba Binary files /dev/null and b/data/images/esrb_t.png differ diff --git a/data/images/exit_bottom.png b/data/images/exit_bottom.png new file mode 100644 index 0000000..5f95741 Binary files /dev/null and b/data/images/exit_bottom.png differ diff --git a/data/images/exit_bottom_over.png b/data/images/exit_bottom_over.png new file mode 100644 index 0000000..3899282 Binary files /dev/null and b/data/images/exit_bottom_over.png differ diff --git a/data/images/exit_button.png b/data/images/exit_button.png new file mode 100644 index 0000000..1c9fb09 Binary files /dev/null and b/data/images/exit_button.png differ diff --git a/data/images/exit_top.png b/data/images/exit_top.png new file mode 100644 index 0000000..759264f Binary files /dev/null and b/data/images/exit_top.png differ diff --git a/data/images/exit_top_over.png b/data/images/exit_top_over.png new file mode 100644 index 0000000..4f60dbc Binary files /dev/null and b/data/images/exit_top_over.png differ diff --git a/data/images/favIcon.png b/data/images/favIcon.png new file mode 100644 index 0000000..1b1314b Binary files /dev/null and b/data/images/favIcon.png differ diff --git a/data/images/favIcon_gray.png b/data/images/favIcon_gray.png new file mode 100644 index 0000000..cf28a89 Binary files /dev/null and b/data/images/favIcon_gray.png differ diff --git a/data/images/favorite.png b/data/images/favorite.png new file mode 100644 index 0000000..b8eeefe Binary files /dev/null and b/data/images/favorite.png differ diff --git a/data/images/gameinfo1.png b/data/images/gameinfo1.png new file mode 100644 index 0000000..7dbfea6 Binary files /dev/null and b/data/images/gameinfo1.png differ diff --git a/data/images/gameinfo1a.png b/data/images/gameinfo1a.png new file mode 100644 index 0000000..528824d Binary files /dev/null and b/data/images/gameinfo1a.png differ diff --git a/data/images/gameinfo2.png b/data/images/gameinfo2.png new file mode 100644 index 0000000..35ac092 Binary files /dev/null and b/data/images/gameinfo2.png differ diff --git a/data/images/gameinfo2a.png b/data/images/gameinfo2a.png new file mode 100644 index 0000000..3a81238 Binary files /dev/null and b/data/images/gameinfo2a.png differ diff --git a/data/images/gc_banner_bg.png b/data/images/gc_banner_bg.png new file mode 100644 index 0000000..9807893 Binary files /dev/null and b/data/images/gc_banner_bg.png differ diff --git a/data/images/gc_icon_bg.png b/data/images/gc_icon_bg.png new file mode 100644 index 0000000..d353bdc Binary files /dev/null and b/data/images/gc_icon_bg.png differ diff --git a/data/images/gcncontroller.png b/data/images/gcncontroller.png new file mode 100644 index 0000000..244bb56 Binary files /dev/null and b/data/images/gcncontroller.png differ diff --git a/data/images/gcncontrollerR.png b/data/images/gcncontrollerR.png new file mode 100644 index 0000000..b821371 Binary files /dev/null and b/data/images/gcncontrollerR.png differ diff --git a/data/images/guitar.png b/data/images/guitar.png new file mode 100644 index 0000000..cbb9a83 Binary files /dev/null and b/data/images/guitar.png differ diff --git a/data/images/guitarR.png b/data/images/guitarR.png new file mode 100644 index 0000000..7d763b5 Binary files /dev/null and b/data/images/guitarR.png differ diff --git a/data/images/gxlogo.png b/data/images/gxlogo.png new file mode 100644 index 0000000..dadd5cb Binary files /dev/null and b/data/images/gxlogo.png differ diff --git a/data/images/icon_folder.png b/data/images/icon_folder.png new file mode 100644 index 0000000..269b5ca Binary files /dev/null and b/data/images/icon_folder.png differ diff --git a/data/images/keyboard_backspace_over.png b/data/images/keyboard_backspace_over.png new file mode 100644 index 0000000..419a2e6 Binary files /dev/null and b/data/images/keyboard_backspace_over.png differ diff --git a/data/images/keyboard_clear_over.png b/data/images/keyboard_clear_over.png new file mode 100644 index 0000000..11fbb96 Binary files /dev/null and b/data/images/keyboard_clear_over.png differ diff --git a/data/images/keyboard_key.png b/data/images/keyboard_key.png new file mode 100644 index 0000000..50061ba Binary files /dev/null and b/data/images/keyboard_key.png differ diff --git a/data/images/keyboard_key_over.png b/data/images/keyboard_key_over.png new file mode 100644 index 0000000..15e352d Binary files /dev/null and b/data/images/keyboard_key_over.png differ diff --git a/data/images/keyboard_largekey_over.png b/data/images/keyboard_largekey_over.png new file mode 100644 index 0000000..bac1074 Binary files /dev/null and b/data/images/keyboard_largekey_over.png differ diff --git a/data/images/keyboard_mediumkey_over.png b/data/images/keyboard_mediumkey_over.png new file mode 100644 index 0000000..f2c821c Binary files /dev/null and b/data/images/keyboard_mediumkey_over.png differ diff --git a/data/images/keyboard_textbox.png b/data/images/keyboard_textbox.png new file mode 100644 index 0000000..caeef7e Binary files /dev/null and b/data/images/keyboard_textbox.png differ diff --git a/data/images/little_star.png b/data/images/little_star.png new file mode 100644 index 0000000..de0da22 Binary files /dev/null and b/data/images/little_star.png differ diff --git a/data/images/loader_mode.png b/data/images/loader_mode.png new file mode 100755 index 0000000..0d4c043 Binary files /dev/null and b/data/images/loader_mode.png differ diff --git a/data/images/lock.png b/data/images/lock.png new file mode 100644 index 0000000..fc61376 Binary files /dev/null and b/data/images/lock.png differ diff --git a/data/images/lock_gray.png b/data/images/lock_gray.png new file mode 100644 index 0000000..72db007 Binary files /dev/null and b/data/images/lock_gray.png differ diff --git a/data/images/menu_button.png b/data/images/menu_button.png new file mode 100644 index 0000000..008ae4a Binary files /dev/null and b/data/images/menu_button.png differ diff --git a/data/images/menu_button_over.png b/data/images/menu_button_over.png new file mode 100644 index 0000000..4f0780e Binary files /dev/null and b/data/images/menu_button_over.png differ diff --git a/data/images/microphone.png b/data/images/microphone.png new file mode 100644 index 0000000..d1e6b64 Binary files /dev/null and b/data/images/microphone.png differ diff --git a/data/images/microphoneR.png b/data/images/microphoneR.png new file mode 100644 index 0000000..892f833 Binary files /dev/null and b/data/images/microphoneR.png differ diff --git a/data/images/motionplus.png b/data/images/motionplus.png new file mode 100644 index 0000000..c3e3450 Binary files /dev/null and b/data/images/motionplus.png differ diff --git a/data/images/motionplusR.png b/data/images/motionplusR.png new file mode 100644 index 0000000..9857624 Binary files /dev/null and b/data/images/motionplusR.png differ diff --git a/data/images/new.png b/data/images/new.png new file mode 100644 index 0000000..167cce9 Binary files /dev/null and b/data/images/new.png differ diff --git a/data/images/nintendods.png b/data/images/nintendods.png new file mode 100644 index 0000000..c22cf42 Binary files /dev/null and b/data/images/nintendods.png differ diff --git a/data/images/nintendodsR.png b/data/images/nintendodsR.png new file mode 100644 index 0000000..0cad10c Binary files /dev/null and b/data/images/nintendodsR.png differ diff --git a/data/images/nocover.png b/data/images/nocover.png new file mode 100644 index 0000000..4be4143 Binary files /dev/null and b/data/images/nocover.png differ diff --git a/data/images/nocoverFlat.png b/data/images/nocoverFlat.png new file mode 100644 index 0000000..d44936a Binary files /dev/null and b/data/images/nocoverFlat.png differ diff --git a/data/images/nocoverFull.png b/data/images/nocoverFull.png new file mode 100644 index 0000000..a451115 Binary files /dev/null and b/data/images/nocoverFull.png differ diff --git a/data/images/nodisc.png b/data/images/nodisc.png new file mode 100644 index 0000000..6bb61a7 Binary files /dev/null and b/data/images/nodisc.png differ diff --git a/data/images/norating.png b/data/images/norating.png new file mode 100644 index 0000000..2b5248e Binary files /dev/null and b/data/images/norating.png differ diff --git a/data/images/not_favorite.png b/data/images/not_favorite.png new file mode 100644 index 0000000..c9bd9df Binary files /dev/null and b/data/images/not_favorite.png differ diff --git a/data/images/nunchuk.png b/data/images/nunchuk.png new file mode 100644 index 0000000..1187cd6 Binary files /dev/null and b/data/images/nunchuk.png differ diff --git a/data/images/nunchukR.png b/data/images/nunchukR.png new file mode 100644 index 0000000..8e07907 Binary files /dev/null and b/data/images/nunchukR.png differ diff --git a/data/images/one.png b/data/images/one.png new file mode 100644 index 0000000..55f0920 Binary files /dev/null and b/data/images/one.png differ diff --git a/data/images/oneButtonScroll.png b/data/images/oneButtonScroll.png new file mode 100644 index 0000000..fe89678 Binary files /dev/null and b/data/images/oneButtonScroll.png differ diff --git a/data/images/pageindicator.png b/data/images/pageindicator.png new file mode 100644 index 0000000..28b0f8e Binary files /dev/null and b/data/images/pageindicator.png differ diff --git a/data/images/pegi_12.png b/data/images/pegi_12.png new file mode 100644 index 0000000..5d19949 Binary files /dev/null and b/data/images/pegi_12.png differ diff --git a/data/images/pegi_16.png b/data/images/pegi_16.png new file mode 100644 index 0000000..039e476 Binary files /dev/null and b/data/images/pegi_16.png differ diff --git a/data/images/pegi_18.png b/data/images/pegi_18.png new file mode 100644 index 0000000..102102e Binary files /dev/null and b/data/images/pegi_18.png differ diff --git a/data/images/pegi_3.png b/data/images/pegi_3.png new file mode 100644 index 0000000..34c423f Binary files /dev/null and b/data/images/pegi_3.png differ diff --git a/data/images/pegi_7.png b/data/images/pegi_7.png new file mode 100644 index 0000000..b81e751 Binary files /dev/null and b/data/images/pegi_7.png differ diff --git a/data/images/playCountIcon.png b/data/images/playCountIcon.png new file mode 100644 index 0000000..14609fa Binary files /dev/null and b/data/images/playCountIcon.png differ diff --git a/data/images/player1_grab.png b/data/images/player1_grab.png new file mode 100644 index 0000000..d95c2b3 Binary files /dev/null and b/data/images/player1_grab.png differ diff --git a/data/images/player1_point.png b/data/images/player1_point.png new file mode 100644 index 0000000..c06c08c Binary files /dev/null and b/data/images/player1_point.png differ diff --git a/data/images/player2_grab.png b/data/images/player2_grab.png new file mode 100644 index 0000000..5f3f6ab Binary files /dev/null and b/data/images/player2_grab.png differ diff --git a/data/images/player2_point.png b/data/images/player2_point.png new file mode 100644 index 0000000..6e952d2 Binary files /dev/null and b/data/images/player2_point.png differ diff --git a/data/images/player3_grab.png b/data/images/player3_grab.png new file mode 100644 index 0000000..c0c3546 Binary files /dev/null and b/data/images/player3_grab.png differ diff --git a/data/images/player3_point.png b/data/images/player3_point.png new file mode 100644 index 0000000..704f84e Binary files /dev/null and b/data/images/player3_point.png differ diff --git a/data/images/player4_grab.png b/data/images/player4_grab.png new file mode 100644 index 0000000..7e9a814 Binary files /dev/null and b/data/images/player4_grab.png differ diff --git a/data/images/player4_point.png b/data/images/player4_point.png new file mode 100644 index 0000000..dd8f1ad Binary files /dev/null and b/data/images/player4_point.png differ diff --git a/data/images/playersSort.png b/data/images/playersSort.png new file mode 100644 index 0000000..b74b98a Binary files /dev/null and b/data/images/playersSort.png differ diff --git a/data/images/progressbar.png b/data/images/progressbar.png new file mode 100644 index 0000000..747f6a4 Binary files /dev/null and b/data/images/progressbar.png differ diff --git a/data/images/progressbar_empty.png b/data/images/progressbar_empty.png new file mode 100644 index 0000000..e72f0c4 Binary files /dev/null and b/data/images/progressbar_empty.png differ diff --git a/data/images/progressbar_outline.png b/data/images/progressbar_outline.png new file mode 100644 index 0000000..6b66545 Binary files /dev/null and b/data/images/progressbar_outline.png differ diff --git a/data/images/rankIcon.png b/data/images/rankIcon.png new file mode 100644 index 0000000..7616dd9 Binary files /dev/null and b/data/images/rankIcon.png differ diff --git a/data/images/remove.png b/data/images/remove.png new file mode 100644 index 0000000..be3605a Binary files /dev/null and b/data/images/remove.png differ diff --git a/data/images/rplayer1_point.png b/data/images/rplayer1_point.png new file mode 100644 index 0000000..eabd11b Binary files /dev/null and b/data/images/rplayer1_point.png differ diff --git a/data/images/rplayer2_point.png b/data/images/rplayer2_point.png new file mode 100644 index 0000000..f12a5c5 Binary files /dev/null and b/data/images/rplayer2_point.png differ diff --git a/data/images/rplayer3_point.png b/data/images/rplayer3_point.png new file mode 100644 index 0000000..d67c019 Binary files /dev/null and b/data/images/rplayer3_point.png differ diff --git a/data/images/rplayer4_point.png b/data/images/rplayer4_point.png new file mode 100644 index 0000000..d63ccd7 Binary files /dev/null and b/data/images/rplayer4_point.png differ diff --git a/data/images/scrollBarBottom.png b/data/images/scrollBarBottom.png new file mode 100644 index 0000000..426fdc2 Binary files /dev/null and b/data/images/scrollBarBottom.png differ diff --git a/data/images/scrollBarTile.png b/data/images/scrollBarTile.png new file mode 100644 index 0000000..d50b3b6 Binary files /dev/null and b/data/images/scrollBarTile.png differ diff --git a/data/images/scrollBarTop.png b/data/images/scrollBarTop.png new file mode 100644 index 0000000..60c3913 Binary files /dev/null and b/data/images/scrollBarTop.png differ diff --git a/data/images/scrollbar_arrowdown.png b/data/images/scrollbar_arrowdown.png new file mode 100644 index 0000000..e415212 Binary files /dev/null and b/data/images/scrollbar_arrowdown.png differ diff --git a/data/images/scrollbar_arrowup.png b/data/images/scrollbar_arrowup.png new file mode 100644 index 0000000..14f465a Binary files /dev/null and b/data/images/scrollbar_arrowup.png differ diff --git a/data/images/scrollbar_box.png b/data/images/scrollbar_box.png new file mode 100644 index 0000000..ada1580 Binary files /dev/null and b/data/images/scrollbar_box.png differ diff --git a/data/images/sdcard.png b/data/images/sdcard.png new file mode 100644 index 0000000..b3b247d Binary files /dev/null and b/data/images/sdcard.png differ diff --git a/data/images/sdcard_over.png b/data/images/sdcard_over.png new file mode 100644 index 0000000..636d3af Binary files /dev/null and b/data/images/sdcard_over.png differ diff --git a/data/images/searchIcon.png b/data/images/searchIcon.png new file mode 100644 index 0000000..2885af5 Binary files /dev/null and b/data/images/searchIcon.png differ diff --git a/data/images/searchIcon_gray.png b/data/images/searchIcon_gray.png new file mode 100644 index 0000000..6396ca6 Binary files /dev/null and b/data/images/searchIcon_gray.png differ diff --git a/data/images/settings_background.png b/data/images/settings_background.png new file mode 100644 index 0000000..02ed90d Binary files /dev/null and b/data/images/settings_background.png differ diff --git a/data/images/settings_button.png b/data/images/settings_button.png new file mode 100644 index 0000000..77ce4d3 Binary files /dev/null and b/data/images/settings_button.png differ diff --git a/data/images/settings_button_over.png b/data/images/settings_button_over.png new file mode 100644 index 0000000..0dba63d Binary files /dev/null and b/data/images/settings_button_over.png differ diff --git a/data/images/settings_title.png b/data/images/settings_title.png new file mode 100644 index 0000000..48de508 Binary files /dev/null and b/data/images/settings_title.png differ diff --git a/data/images/settings_title_over.png b/data/images/settings_title_over.png new file mode 100644 index 0000000..2111ad2 Binary files /dev/null and b/data/images/settings_title_over.png differ diff --git a/data/images/startgame_arrow_left.png b/data/images/startgame_arrow_left.png new file mode 100644 index 0000000..4ed6e29 Binary files /dev/null and b/data/images/startgame_arrow_left.png differ diff --git a/data/images/startgame_arrow_right.png b/data/images/startgame_arrow_right.png new file mode 100644 index 0000000..0ed3d0f Binary files /dev/null and b/data/images/startgame_arrow_right.png differ diff --git a/data/images/theme_box.png b/data/images/theme_box.png new file mode 100644 index 0000000..174b7b5 Binary files /dev/null and b/data/images/theme_box.png differ diff --git a/data/images/theme_dialogue_box.png b/data/images/theme_dialogue_box.png new file mode 100644 index 0000000..389cfa1 Binary files /dev/null and b/data/images/theme_dialogue_box.png differ diff --git a/data/images/tooltip_left.png b/data/images/tooltip_left.png new file mode 100644 index 0000000..b1114ee Binary files /dev/null and b/data/images/tooltip_left.png differ diff --git a/data/images/tooltip_right.png b/data/images/tooltip_right.png new file mode 100644 index 0000000..86bd7ed Binary files /dev/null and b/data/images/tooltip_right.png differ diff --git a/data/images/tooltip_tile.png b/data/images/tooltip_tile.png new file mode 100644 index 0000000..9b68e2f Binary files /dev/null and b/data/images/tooltip_tile.png differ diff --git a/data/images/unlock.png b/data/images/unlock.png new file mode 100644 index 0000000..241f1b3 Binary files /dev/null and b/data/images/unlock.png differ diff --git a/data/images/unlock_gray.png b/data/images/unlock_gray.png new file mode 100644 index 0000000..8f6c90e Binary files /dev/null and b/data/images/unlock_gray.png differ diff --git a/data/images/wbackground.png b/data/images/wbackground.png new file mode 100644 index 0000000..4035f47 Binary files /dev/null and b/data/images/wbackground.png differ diff --git a/data/images/wdialogue_box_startgame.png b/data/images/wdialogue_box_startgame.png new file mode 100644 index 0000000..033814d Binary files /dev/null and b/data/images/wdialogue_box_startgame.png differ diff --git a/data/images/wheel.png b/data/images/wheel.png new file mode 100644 index 0000000..e4e85fc Binary files /dev/null and b/data/images/wheel.png differ diff --git a/data/images/wheelR.png b/data/images/wheelR.png new file mode 100644 index 0000000..b777b12 Binary files /dev/null and b/data/images/wheelR.png differ diff --git a/data/images/wifi1.png b/data/images/wifi1.png new file mode 100644 index 0000000..8190f67 Binary files /dev/null and b/data/images/wifi1.png differ diff --git a/data/images/wifi10.png b/data/images/wifi10.png new file mode 100644 index 0000000..d198801 Binary files /dev/null and b/data/images/wifi10.png differ diff --git a/data/images/wifi12.png b/data/images/wifi12.png new file mode 100644 index 0000000..455f2e1 Binary files /dev/null and b/data/images/wifi12.png differ diff --git a/data/images/wifi16.png b/data/images/wifi16.png new file mode 100644 index 0000000..7f73c2c Binary files /dev/null and b/data/images/wifi16.png differ diff --git a/data/images/wifi2.png b/data/images/wifi2.png new file mode 100644 index 0000000..07dd889 Binary files /dev/null and b/data/images/wifi2.png differ diff --git a/data/images/wifi3.png b/data/images/wifi3.png new file mode 100644 index 0000000..67204d8 Binary files /dev/null and b/data/images/wifi3.png differ diff --git a/data/images/wifi32.png b/data/images/wifi32.png new file mode 100644 index 0000000..5fb2eba Binary files /dev/null and b/data/images/wifi32.png differ diff --git a/data/images/wifi4.png b/data/images/wifi4.png new file mode 100644 index 0000000..725219c Binary files /dev/null and b/data/images/wifi4.png differ diff --git a/data/images/wifi6.png b/data/images/wifi6.png new file mode 100644 index 0000000..2b71deb Binary files /dev/null and b/data/images/wifi6.png differ diff --git a/data/images/wifi8.png b/data/images/wifi8.png new file mode 100644 index 0000000..13502a1 Binary files /dev/null and b/data/images/wifi8.png differ diff --git a/data/images/wifi_btn.png b/data/images/wifi_btn.png new file mode 100644 index 0000000..2441108 Binary files /dev/null and b/data/images/wifi_btn.png differ diff --git a/data/images/wiimote.png b/data/images/wiimote.png new file mode 100644 index 0000000..a868c21 Binary files /dev/null and b/data/images/wiimote.png differ diff --git a/data/images/wiimote1.png b/data/images/wiimote1.png new file mode 100644 index 0000000..173ab5e Binary files /dev/null and b/data/images/wiimote1.png differ diff --git a/data/images/wiimote2.png b/data/images/wiimote2.png new file mode 100644 index 0000000..3a7462e Binary files /dev/null and b/data/images/wiimote2.png differ diff --git a/data/images/wiimote3.png b/data/images/wiimote3.png new file mode 100644 index 0000000..bea8055 Binary files /dev/null and b/data/images/wiimote3.png differ diff --git a/data/images/wiimote4.png b/data/images/wiimote4.png new file mode 100644 index 0000000..582cb50 Binary files /dev/null and b/data/images/wiimote4.png differ diff --git a/data/images/wiimote_poweroff.png b/data/images/wiimote_poweroff.png new file mode 100644 index 0000000..81f3446 Binary files /dev/null and b/data/images/wiimote_poweroff.png differ diff --git a/data/images/wiimote_poweroff_over.png b/data/images/wiimote_poweroff_over.png new file mode 100644 index 0000000..037dd7f Binary files /dev/null and b/data/images/wiimote_poweroff_over.png differ diff --git a/data/images/wiispeak.png b/data/images/wiispeak.png new file mode 100644 index 0000000..24a8e25 Binary files /dev/null and b/data/images/wiispeak.png differ diff --git a/data/images/wiispeakR.png b/data/images/wiispeakR.png new file mode 100644 index 0000000..272eb49 Binary files /dev/null and b/data/images/wiispeakR.png differ diff --git a/data/images/zapper.png b/data/images/zapper.png new file mode 100644 index 0000000..2a6ac6e Binary files /dev/null and b/data/images/zapper.png differ diff --git a/data/images/zapperR.png b/data/images/zapperR.png new file mode 100644 index 0000000..504f802 Binary files /dev/null and b/data/images/zapperR.png differ diff --git a/data/magic_patcher.o b/data/magic_patcher.o new file mode 100644 index 0000000..ad7af87 Binary files /dev/null and b/data/magic_patcher.o differ diff --git a/data/sounds/bg_music.ogg b/data/sounds/bg_music.ogg new file mode 100644 index 0000000..7b5715a Binary files /dev/null and b/data/sounds/bg_music.ogg differ diff --git a/data/sounds/button_click.wav b/data/sounds/button_click.wav new file mode 100644 index 0000000..b0578c5 Binary files /dev/null and b/data/sounds/button_click.wav differ diff --git a/data/sounds/button_click2.wav b/data/sounds/button_click2.wav new file mode 100644 index 0000000..011c0ad Binary files /dev/null and b/data/sounds/button_click2.wav differ diff --git a/data/sounds/button_over.wav b/data/sounds/button_over.wav new file mode 100644 index 0000000..8a06f4b Binary files /dev/null and b/data/sounds/button_over.wav differ diff --git a/data/sounds/credits_music.ogg b/data/sounds/credits_music.ogg new file mode 100644 index 0000000..20de7bc Binary files /dev/null and b/data/sounds/credits_music.ogg differ diff --git a/data/sounds/gc_banner.ogg b/data/sounds/gc_banner.ogg new file mode 100644 index 0000000..37e5ae0 Binary files /dev/null and b/data/sounds/gc_banner.ogg differ diff --git a/data/sounds/menuin.ogg b/data/sounds/menuin.ogg new file mode 100644 index 0000000..46b7b05 Binary files /dev/null and b/data/sounds/menuin.ogg differ diff --git a/data/sounds/menuout.ogg b/data/sounds/menuout.ogg new file mode 100644 index 0000000..760c040 Binary files /dev/null and b/data/sounds/menuout.ogg differ diff --git a/data/sounds/success.ogg b/data/sounds/success.ogg new file mode 100644 index 0000000..eb6390a Binary files /dev/null and b/data/sounds/success.ogg differ diff --git a/filelist.sh b/filelist.sh new file mode 100644 index 0000000..bb87f26 --- /dev/null +++ b/filelist.sh @@ -0,0 +1,64 @@ +#! /bin/bash +# +# Automatic resource file list generation +# Created by Dimok + +outFile="./source/themes/filelist.h" +count_old=$(cat $outFile 2>/dev/null | tr -d '\n\n' | sed 's/[^0-9]*\([0-9]*\).*/\1/') + +count=0 +for i in $(find ./data/images/ ./data/sounds/ ./data/fonts/ ./data/binary/ -maxdepth 1 -type f \( ! -printf "%f\n" \)) +do + files[count]=$i + count=$((count+1)) +done + +if [ "$count_old" != "$count" ] || [ ! -f $outFile ] +then + +echo "Generating filelist.h for $count files." >&2 +cat < $outFile +/**************************************************************************** + * USB Loader GX resource files. + * This file is generated automatically. + * Includes $count files. + * + * NOTE: + * Any manual modification of this file will be overwriten by the generation. + ****************************************************************************/ +#ifndef _FILELIST_H_ +#define _FILELIST_H_ + +#include + +EOF + +for i in ${files[@]} +do + filename=${i%.*} + extension=${i##*.} + echo 'extern const u8 '$filename'_'$extension'[];' >> $outFile + echo 'extern const u32 '$filename'_'$extension'_size;' >> $outFile + echo '' >> $outFile +done + +echo 'RecourceFile Resources::RecourceFiles[] =' >> $outFile +echo '{' >> $outFile + +for i in ${files[@]} +do + filename=${i%.*} + extension=${i##*.} + echo -e '\t{"'$i'", '$filename'_'$extension', '$filename'_'$extension'_size, NULL, 0},' >> $outFile +done + +echo -e '\t{"listBackground.png", NULL, 0, NULL, 0},\t// Optional' >> $outFile +echo -e '\t{"carouselBackground.png", NULL, 0, NULL, 0},\t// Optional' >> $outFile +echo -e '\t{"gridBackground.png", NULL, 0, NULL, 0},\t// Optional' >> $outFile +echo -e '\t{NULL, NULL, 0, NULL, 0}' >> $outFile +echo '};' >> $outFile + +echo '' >> $outFile +echo '#endif' >> $outFile + +fi diff --git a/gettext-bin/libexpat.dll b/gettext-bin/libexpat.dll new file mode 100644 index 0000000..13bc7ee Binary files /dev/null and b/gettext-bin/libexpat.dll differ diff --git a/gettext-bin/libgettextlib.dll b/gettext-bin/libgettextlib.dll new file mode 100644 index 0000000..6bc7525 Binary files /dev/null and b/gettext-bin/libgettextlib.dll differ diff --git a/gettext-bin/libgettextpo.dll b/gettext-bin/libgettextpo.dll new file mode 100644 index 0000000..9a9aa3f Binary files /dev/null and b/gettext-bin/libgettextpo.dll differ diff --git a/gettext-bin/libgettextsrc.dll b/gettext-bin/libgettextsrc.dll new file mode 100644 index 0000000..0d5a593 Binary files /dev/null and b/gettext-bin/libgettextsrc.dll differ diff --git a/gettext-bin/libiconv2.dll b/gettext-bin/libiconv2.dll new file mode 100644 index 0000000..fb1ffba Binary files /dev/null and b/gettext-bin/libiconv2.dll differ diff --git a/gettext-bin/libintl3.dll b/gettext-bin/libintl3.dll new file mode 100644 index 0000000..ec11e6b Binary files /dev/null and b/gettext-bin/libintl3.dll differ diff --git a/gettext-bin/msgmerge.exe b/gettext-bin/msgmerge.exe new file mode 100644 index 0000000..dc5a3ff Binary files /dev/null and b/gettext-bin/msgmerge.exe differ diff --git a/gettext-bin/xgettext.exe b/gettext-bin/xgettext.exe new file mode 100644 index 0000000..590a19b Binary files /dev/null and b/gettext-bin/xgettext.exe differ diff --git a/gui.pnproj b/gui.pnproj new file mode 100644 index 0000000..c577e3a --- /dev/null +++ b/gui.pnproj @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gui.pnps b/gui.pnps new file mode 100644 index 0000000..45a7f01 --- /dev/null +++ b/gui.pnps @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source/BoxCover/BoxCover.cpp b/source/BoxCover/BoxCover.cpp new file mode 100644 index 0000000..bef0b0f --- /dev/null +++ b/source/BoxCover/BoxCover.cpp @@ -0,0 +1,417 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "BoxCover.hpp" +#include "BoxMesh.hpp" +#include "settings/CSettings.h" +#include "themes/CTheme.h" +#include "menu.h" + +BoxCover::BoxCover(GuiImageData * img, bool flat) + : GuiImage(img), + boxBorder(Resources::GetFile("boxBorder.png"), Resources::GetFileSize("boxBorder.png")), + defaultBox(NULL) +{ + flatCover = flat; + Zoomable = false; + moveChan = -1; + moveStartPosX = 0; + moveStartPosY = 0; + movePosX = 0.0f; + movePosY = 0.0f; + RotX = 0.0f; + RotY = 0.0f; + RotZ = 0.0f; + PosX = 0.0f; + PosY = 0.0f; + PosZ = -27.f; + AnimRotate = 0.0f; + last_manual_move_frame = 0; + guVector camera = (guVector) {0.0F, 0.0F, 0.0F}; + guVector up = (guVector) {0.0F, 1.0F, 0.0F}; + guVector look = (guVector) {0.0F, 0.0F, -1.0F}; + boxColor = (GXColor) {233, 233, 233, 255}; + + guLookAt(view, &camera, &up, &look); + guPerspective(projection, 8, 640.f/480.f, 1.0f, 300.0F); + + if(flatCover || !image) + { + defaultBox = Resources::GetImageData("nocoverFull.png"); + GX_InitTexObj(&defaultBoxTex, defaultBox->GetImage(), defaultBox->GetWidth(), defaultBox->GetHeight(), defaultBox->GetTextureFormat(),GX_CLAMP, GX_CLAMP,GX_FALSE); + } + + if(!image) + { + GX_InitTexObj(&coverTex, defaultBox->GetImage(), defaultBox->GetWidth(), defaultBox->GetHeight(), defaultBox->GetTextureFormat(),GX_CLAMP, GX_CLAMP,GX_FALSE); + flatCover = false; + } + else + GX_InitTexObj(&coverTex, image, width,height, GX_TF_RGBA8,GX_CLAMP, GX_CLAMP,GX_FALSE); + + GX_InitTexObj(&boxBorderTex, boxBorder.GetImage(), boxBorder.GetWidth(), boxBorder.GetHeight(), boxBorder.GetTextureFormat(),GX_CLAMP, GX_CLAMP,GX_FALSE); +} + +BoxCover::~BoxCover() +{ + delete defaultBox; + + for(int i = 0; i < 4; ++i) + { + char name[50]; + snprintf(name, sizeof(name), "player%i_point.png", i+1); + pointer[i]->SetImage(name); + } +} + +//! Remove me later +void BoxCover::WiiPADControl(GuiTrigger *t) +{ + if((t->wpad.btns_d & WPAD_BUTTON_A) || (t->wpad.btns_h & WPAD_CLASSIC_BUTTON_A) || (t->pad.btns_h & PAD_BUTTON_A)) + { + if(t->wpad.ir.valid) + { + moveChan = t->chan; + moveStartPosX = t->wpad.ir.x; + moveStartPosY = t->wpad.ir.y; + PosX += movePosX; + PosY += movePosY; + movePosX = 0.0f; + movePosY = 0.0f; + + // GameCube and Classic Controller + s8 movX = fabs(t->pad.stickX) > 10.0f ? t->pad.stickX : t->WPAD_Stick(0, 0); + s8 movY = fabs(t->pad.stickY) > 10.0f ? t->pad.stickY : t->WPAD_Stick(0, 1); + + // WiiU Pro Classic Controller + // Todo : Proper stick calibration required to allow moving cover + + //! Drop stick moves of less than 10 because of sensitivity + if(fabs(movX) < 10.0f) movX = 0; + if(fabs(movY) < 10.0f) movY = 0; + if(movX < -PADCAL) + PosX += (movX + PADCAL) * Settings.PointerSpeed * fabs(PosZ)/3400.f; + if(movX > PADCAL) + PosX += (movX - PADCAL) * Settings.PointerSpeed * fabs(PosZ)/3400.f; + if(movY < -PADCAL) + PosY += (movY + PADCAL) * Settings.PointerSpeed * fabs(PosZ)/3400.f; + if(movY > PADCAL) + PosY += (movY - PADCAL) * Settings.PointerSpeed * fabs(PosZ)/3400.f; + + if(moveChan >= 0 && moveChan < 4) + { + char name[50]; + snprintf(name, sizeof(name), "player%i_grab.png", moveChan+1); + pointer[moveChan]->SetImage(name); + } + } + else + moveChan = -1; + } + else if(((t->wpad.btns_h & WPAD_BUTTON_A) || (t->wpad.btns_h & WPAD_CLASSIC_BUTTON_A) || (t->pad.btns_h & PAD_BUTTON_A)) && moveChan == t->chan && t->wpad.ir.valid && !effects) + { + movePosX = (t->wpad.ir.x-moveStartPosX) * fabs(PosZ)/3400.f; + movePosY = (moveStartPosY-t->wpad.ir.y) * fabs(PosZ)/3400.f; + last_manual_move_frame = frameCount; + } + else if(!(t->wpad.btns_h & WPAD_BUTTON_A) && !(t->wpad.btns_h & WPAD_CLASSIC_BUTTON_A) && !(t->pad.btns_h & PAD_BUTTON_A) && moveChan == t->chan) + { + if(moveChan >= 0 && moveChan < 4) + { + char name[50]; + snprintf(name, sizeof(name), "player%i_point.png", moveChan+1); + pointer[moveChan]->SetImage(name); + } + } + + if((t->wpad.btns_h & WPAD_BUTTON_UP) || (t->pad.substickY > PADCAL) ) + { + RotX -= 2.0f; + last_manual_move_frame = frameCount; + } + if((t->wpad.btns_h & WPAD_BUTTON_DOWN) || (t->pad.substickY < -PADCAL) ) + { + RotX += 2.0f; + last_manual_move_frame = frameCount; + } + if((t->wpad.btns_h & WPAD_BUTTON_LEFT) || (t->pad.substickX < -PADCAL) ) + { + RotY -= 2.0f; + last_manual_move_frame = frameCount; + } + if((t->wpad.btns_h & WPAD_BUTTON_RIGHT) || (t->pad.substickX > PADCAL) ) + { + RotY += 2.0f; + last_manual_move_frame = frameCount; + } + if((t->wpad.btns_d & WPAD_BUTTON_2) || (t->pad.btns_d & PAD_BUTTON_X) || (t->wpad.btns_d & WPAD_CLASSIC_BUTTON_X) ) + { + if(RotY < 180.0f) + SetEffect(EFFECT_BOX_ROTATE_X, 10, 180); + else + SetEffect(EFFECT_BOX_ROTATE_X, -10, -180); + last_manual_move_frame = frameCount; + } + if((t->wpad.btns_h & WPAD_BUTTON_PLUS) || (t->pad.btns_h & PAD_TRIGGER_R) || (t->wpad.btns_h & WPAD_CLASSIC_BUTTON_FULL_R) ) + { + if(PosZ < -2.8f) + PosZ += 0.4f*fabs(PosZ)/19.f; + } + if((t->wpad.btns_h & WPAD_BUTTON_MINUS) || (t->pad.btns_h & PAD_TRIGGER_L) || (t->wpad.btns_h & WPAD_CLASSIC_BUTTON_FULL_L) ) + { + if(PosZ > -43.0f) + PosZ -= 0.4f*fabs(PosZ)/19.f; + } +} + +void BoxCover::Update(GuiTrigger * t) +{ + s8 movY = t->WPAD_Stick((t->wpad.exp.type == WPAD_EXP_CLASSIC), 0); + s8 movX = t->WPAD_Stick((t->wpad.exp.type == WPAD_EXP_CLASSIC), 1); + //! Drop stick moves of less than 10 because of sensitivity + if(fabs(movY) < 10.0f) movY = 0; + if(fabs(movX) < 10.0f) movX = 0; + + if(movY != 0 || movX != 0) + last_manual_move_frame = frameCount; + + RotY += (f32) movY / 50.0f; + RotX -= (f32) movX / 50.0f; + + if(Zoomable) + WiiPADControl(t); + + //! Stop movement for about 5 sec after manual move + if(frameCount-last_manual_move_frame < 250) + return; + + Animation = sinf(DegToRad(AnimRotate))*2.0f; + Animation2 = cosf(DegToRad(AnimRotate))*5.0f; + AnimRotate += 0.1f; + if(AnimRotate > 360.0f) + AnimRotate = 0.0f; +} + +void BoxCover::Draw() +{ + u8 BoxAlpha = (int) (alpha+alphaDyn) & 0xFF; + + GX_LoadProjectionMtx(projection, GX_PERSPECTIVE); + + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_SetVtxDesc(GX_VA_POS, GX_INDEX8); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_INDEX8); + + //! don't draw inside of the box + GX_SetCullMode(GX_CULL_FRONT); + + Mtx modelView; + Mtx modelView2; + Mtx modelView3; + + guVector cubeAxis = {0,0,1}; + guVector cubeAxis2 = {0,1,0}; + guVector cubeAxis3 = {1,0,0}; + guMtxIdentity(modelView); + guMtxRotAxisDeg(modelView3, &cubeAxis3, RotX-Animation2); + guMtxRotAxisDeg(modelView2, &cubeAxis2, RotY+Animation2+xoffsetDyn/2.0f); + guMtxRotAxisDeg(modelView, &cubeAxis, RotZ-Animation); + guMtxConcat(modelView3, modelView2, modelView2); + guMtxConcat(modelView2, modelView, modelView); + if(Settings.widescreen) + guMtxScaleApply(modelView, modelView, Settings.WSFactor, 1.0f, 1.0f); + guMtxTransApply(modelView, modelView, PosX+xoffsetDyn/680.0f+movePosX, PosY+yoffsetDyn/680.0f+movePosY, PosZ); + guMtxConcat(view,modelView,modelView); + + GX_LoadPosMtxImm(modelView, GX_PNMTX0); + + //! Border quads + GX_LoadTexObj(&boxBorderTex, GX_TEXMAP0); + GX_InvalidateTexAll(); + + GX_SetArray(GX_VA_POS, (void *) &g_boxMeshQ[0].pos, sizeof(g_boxMeshQ[0])); + GX_SetArray(GX_VA_TEX0, (void *) &g_boxMeshQ[0].texCoord, sizeof(g_boxMeshQ[0])); + + GX_Begin(GX_QUADS, GX_VTXFMT0, g_boxMeshQSize); + for (u32 j = 0; j < g_boxMeshQSize; ++j) + { + GX_Position1x8(j); + GX_Color4u8(boxColor.r, boxColor.g, boxColor.b, BoxAlpha); + GX_TexCoord1x8(j); + } + GX_End(); + + //! Border triangles + GX_SetArray(GX_VA_POS, (void *) &g_boxMeshT[0].pos, sizeof(g_boxMeshT[0])); + GX_SetArray(GX_VA_TEX0, (void *) &g_boxMeshT[0].texCoord, sizeof(g_boxMeshT[0])); + + GX_Begin(GX_TRIANGLES, GX_VTXFMT0, g_boxMeshTSize); + for (u32 j = 0; j < g_boxMeshTSize; ++j) + { + GX_Position1x8(j); + GX_Color4u8(boxColor.r, boxColor.g, boxColor.b, BoxAlpha); + GX_TexCoord1x8(j); + } + GX_End(); + + //! Back Cover (Might be flat) + GX_LoadTexObj(flatCover ? &defaultBoxTex : &coverTex, GX_TEXMAP0); + GX_InvalidateTexAll(); + + GX_SetArray(GX_VA_POS, (void *) &g_boxBackCoverMesh[0].pos, sizeof(g_boxBackCoverMesh[0])); + GX_SetArray(GX_VA_TEX0, (void *) &g_boxBackCoverMesh[0].texCoord, sizeof(g_boxBackCoverMesh[0])); + + GX_Begin(GX_QUADS, GX_VTXFMT0, g_boxBackCoverMeshSize); + for (u32 j = 0; j < g_boxBackCoverMeshSize; ++j) + { + GX_Position1x8(j); + if(flatCover) + GX_Color4u8(boxColor.r, boxColor.g, boxColor.b, BoxAlpha); + else + GX_Color4u8(0xff, 0xff, 0xff, BoxAlpha); + GX_TexCoord1x8(j); + } + GX_End(); + + if(flatCover) + { + //! Front Flat Cover + GX_LoadTexObj(&coverTex, GX_TEXMAP0); + GX_InvalidateTexAll(); + + GX_SetArray(GX_VA_POS, (void *) &g_flatCoverMesh[0].pos, sizeof(g_flatCoverMesh[0])); + GX_SetArray(GX_VA_TEX0, (void *) &g_flatCoverMesh[0].texCoord, sizeof(g_flatCoverMesh[0])); + + GX_Begin(GX_QUADS, GX_VTXFMT0, g_flatCoverMeshSize); + for (u32 j = 0; j < g_flatCoverMeshSize; ++j) + { + GX_Position1x8(j); + GX_Color4u8(0xff, 0xff, 0xff, 0xff); + GX_TexCoord1x8(j); + } + GX_End(); + } + else + { + //! Front Cover + GX_SetArray(GX_VA_POS, (void *) &g_boxCoverMesh[0].pos, sizeof(g_boxCoverMesh[0])); + GX_SetArray(GX_VA_TEX0, (void *) &g_boxCoverMesh[0].texCoord, sizeof(g_boxCoverMesh[0])); + + GX_Begin(GX_QUADS, GX_VTXFMT0, g_boxCoverMeshSize); + for (u32 j = 0; j < g_boxCoverMeshSize; ++j) + { + GX_Position1x8(j); + GX_Color4u8(0xff, 0xff, 0xff, BoxAlpha); + GX_TexCoord1x8(j); + } + GX_End(); + } + + //! stop cull + GX_SetCullMode(GX_CULL_NONE); + + UpdateEffects(); +} + +void BoxCover::SetEffect(int eff, int amount, int target) +{ + GuiImage::SetEffect(eff, amount, target); +} + +void BoxCover::UpdateEffects() +{ + GuiImage::UpdateEffects(); + + if(effects & EFFECT_BOX_FLY_CENTRE) + { + if(PosX > 0.1f) + PosX -= effectAmount/1200.f; + if(PosY > 0.1f) + PosY -= effectAmount/1200.f; + if(PosX < -0.1f) + PosX += effectAmount/1200.f; + if(PosY < -0.1f) + PosY += effectAmount/1200.f; + + movePosX = 0.0f; + movePosY = 0.0f; + PosZ += 0.4f; + RotY += effectAmount/4.9f; + + if(fabs(PosX) < 0.1f && fabs(PosY) < 0.1f) + { + PosX = 0.0f; + PosY = 0.0f; + effects = 0; + effectAmount = 0; + } + } + else if(effects & EFFECT_BOX_FLY_BACK) + { + if(PosX > PosXOrig+0.1f) + PosX -= effectAmount/1200.f; + if(PosY > PosYOrig+0.1f) + PosY -= effectAmount/1200.f; + if(PosX < PosXOrig-0.1f) + PosX += effectAmount/1200.f; + if(PosY < PosYOrig-0.1f) + PosY += effectAmount/1200.f; + + PosZ -= 0.4f; + RotY -= effectAmount/4.9f; + + if(movePosX > 0.1f) + movePosX -= 0.1f; + else if(movePosX < 0.1f) + movePosX += 0.1f; + if(movePosY > 0.1f) + movePosY -= 0.1f; + else if(movePosY < 0.1f) + movePosY += 0.1f; + + if(fabs(PosXOrig-PosX) < 0.1f && fabs(PosYOrig-PosY) < 0.1f) + { + movePosX = 0.0f; + movePosY = 0.0f; + PosX = PosXOrig; + PosY = PosYOrig; + PosZ = PosZOrig; + effects = 0; + effectAmount = 0; + } + } + else if(effects & EFFECT_BOX_ROTATE_X) + { + RotY += effectAmount; + effectTarget -= effectAmount; + + if(fabs(effectTarget) < fabs(effectAmount)) + { + effects = 0; + effectAmount = 0; + effectTarget = 0; + } + } +} diff --git a/source/BoxCover/BoxCover.hpp b/source/BoxCover/BoxCover.hpp new file mode 100644 index 0000000..c8ef567 --- /dev/null +++ b/source/BoxCover/BoxCover.hpp @@ -0,0 +1,82 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef BOX_COVER_HPP_ +#define BOX_COVER_HPP_ + +#include "GUI/gui.h" + +#define EFFECT_BOX_FLY_CENTRE 0x2000000 +#define EFFECT_BOX_FLY_BACK 0x4000000 +#define EFFECT_BOX_ROTATE_X 0x8000000 + +class BoxCover : public GuiImage +{ + public: + BoxCover(GuiImageData * img, bool flat = false); + virtual ~BoxCover(); + //! Colors: + //! Gray Box (Default): r:233 g:233 b:233 + //! Red Box (NSMB): r:198 g:34 b:4 + void SetBoxColor(GXColor c) { LOCK(this); boxColor = c; }; + void SetPosition(f32 x, f32 y, f32 z) { LOCK(this); PosXOrig = PosX = x; PosYOrig = PosY = y; PosZOrig = PosZ = z; }; + void SetEffect(int eff, int amount, int target = 0); + void SetImage(GuiImageData *img); //forbid this call + void SetZoomable(bool z) { LOCK(this); Zoomable = z; }; + void Draw(); + void Update(GuiTrigger * t); + void UpdateEffects(); + private: + void WiiPADControl(GuiTrigger *t); + + f32 RotX; + f32 RotY; + f32 RotZ; + f32 PosX; + f32 PosY; + f32 PosZ; + f32 PosXOrig; + f32 PosYOrig; + f32 PosZOrig; + f32 AnimRotate; + f32 Animation; + f32 Animation2; + u32 last_manual_move_frame; + int moveStartPosX; + int moveStartPosY; + f32 movePosX; + f32 movePosY; + int moveChan; + bool flatCover; + bool Zoomable; + Mtx44 projection; + GuiImageData boxBorder; + GuiImageData *defaultBox; + Mtx view; + GXTexObj coverTex; + GXTexObj boxBorderTex; + GXTexObj defaultBoxTex; + GXColor boxColor; +}; + +#endif diff --git a/source/BoxCover/BoxMesh.cpp b/source/BoxCover/BoxMesh.cpp new file mode 100644 index 0000000..a8b11f8 --- /dev/null +++ b/source/BoxCover/BoxMesh.cpp @@ -0,0 +1,156 @@ +#include +#include "BoxMesh.hpp" + +// Quick and dirty hardcoded DVD box mesh + +static const guVector g_coverBL = { -0.65f, -0.915f, 0.f }; +static const guVector g_coverTR = { 0.65f, 0.915f, 0.f }; +static const float g_boxCoverY = 0.05f; +static const float g_boxBorderWidth = 0.022f; +static const guVector g_frontCoverBL = { g_coverBL.x, g_coverBL.y + g_boxCoverY, g_coverBL.z }; +static const guVector g_frontCoverTR = { g_coverTR.x, g_coverTR.y + g_boxCoverY, g_coverTR.z }; +static const guVector g_backCoverBL = { g_frontCoverBL.x, g_frontCoverBL.y, g_frontCoverBL.z - 0.16f }; +static const guVector g_backCoverTR = { g_frontCoverTR.x, g_frontCoverTR.y, g_frontCoverTR.z - 0.16f }; +const float g_boxCoverYCenter = (g_frontCoverTR.y - g_frontCoverBL.y) * 0.5f; +const float g_coverYCenter = (g_coverTR.y - g_coverBL.y) * 0.5f; + +#define w(x) ((float)x / 64.0f) +#define h(y) ((float)y / 256.0f) + + +const SMeshVert g_boxMeshQ[] ATTRIBUTE_ALIGN(32) = { // Quads + // Bordure du bas devant + { { g_frontCoverBL.x, g_frontCoverBL.y, g_frontCoverBL.z }, CTexCoord(w(0), h(256)) }, + { { g_frontCoverBL.x, g_frontCoverBL.y - g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(224)) }, + { { g_frontCoverTR.x, g_frontCoverBL.y - g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(224)) }, + { { g_frontCoverTR.x, g_frontCoverBL.y, g_frontCoverBL.z }, CTexCoord(w(0), h(224)) }, + + // Bordure du haut devant + { { g_frontCoverBL.x, g_frontCoverTR.y + g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(1)) }, + { { g_frontCoverBL.x, g_frontCoverTR.y, g_frontCoverBL.z }, CTexCoord(w(0), h(1)) }, + { { g_frontCoverTR.x, g_frontCoverTR.y, g_frontCoverBL.z }, CTexCoord(w(0), h(32)) }, + { { g_frontCoverTR.x, g_frontCoverTR.y + g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(32)) }, + + // Bordure du bas derrière + { { g_backCoverBL.x, g_backCoverBL.y - g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(256)) }, + { { g_backCoverBL.x, g_backCoverBL.y, g_backCoverBL.z }, CTexCoord(w(64), h(224)) }, + { { g_backCoverTR.x, g_backCoverBL.y, g_backCoverBL.z }, CTexCoord(w(64), h(224)) }, + { { g_backCoverTR.x, g_backCoverBL.y - g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(224)) }, + + // Bordure du haut derrière + { { g_backCoverBL.x, g_backCoverTR.y, g_backCoverBL.z }, CTexCoord(w(64), h(1)) }, + { { g_backCoverBL.x, g_backCoverTR.y + g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(1)) }, + { { g_backCoverTR.x, g_backCoverTR.y + g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(32)) }, + { { g_backCoverTR.x, g_backCoverTR.y, g_backCoverBL.z }, CTexCoord(w(64), h(32)) }, + + // Bordure de droite devant + { { g_frontCoverTR.x, g_frontCoverBL.y, g_frontCoverBL.z }, CTexCoord(w(0), h(256)) }, + { { g_frontCoverTR.x + g_boxBorderWidth, g_frontCoverBL.y, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(256)) }, + { { g_frontCoverTR.x + g_boxBorderWidth, g_frontCoverTR.y, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(0)) }, + { { g_frontCoverTR.x, g_frontCoverTR.y, g_frontCoverBL.z }, CTexCoord(w(0), h(0)) }, + + // Bordure de droite derrière + { { g_backCoverTR.x + g_boxBorderWidth, g_backCoverBL.y, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(256)) }, + { { g_backCoverTR.x, g_backCoverBL.y, g_backCoverBL.z }, CTexCoord(w(64), h(256)) }, + { { g_backCoverTR.x, g_backCoverTR.y, g_backCoverBL.z }, CTexCoord(w(64), h(0)) }, + { { g_backCoverTR.x + g_boxBorderWidth, g_backCoverTR.y, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(0)) }, + + // Face du haut + { { g_frontCoverBL.x, g_frontCoverTR.y + g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(1)) }, + { { g_frontCoverTR.x, g_frontCoverTR.y + g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(32)) }, + { { g_backCoverTR.x, g_backCoverTR.y + g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(32)) }, + { { g_backCoverBL.x, g_backCoverTR.y + g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(1)) }, + + // Angle face du haut / face de droite + { { g_frontCoverTR.x, g_frontCoverTR.y + g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(32)) }, + { { g_frontCoverTR.x + g_boxBorderWidth, g_frontCoverTR.y, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(0)) }, + { { g_backCoverTR.x + g_boxBorderWidth, g_backCoverTR.y, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(0)) }, + { { g_backCoverTR.x, g_backCoverTR.y + g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(32)) }, + + // Face de droite + { { g_frontCoverTR.x + g_boxBorderWidth, g_frontCoverTR.y, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(0)) }, + { { g_frontCoverTR.x + g_boxBorderWidth, g_frontCoverBL.y, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(256)) }, + { { g_backCoverTR.x + g_boxBorderWidth, g_backCoverBL.y, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(256)) }, + { { g_backCoverTR.x + g_boxBorderWidth, g_backCoverTR.y, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(0)) }, + + // Angle face de droite / face du bas + { { g_frontCoverTR.x + g_boxBorderWidth, g_frontCoverBL.y, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(256)) }, + { { g_frontCoverTR.x, g_frontCoverBL.y - g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(224)) }, + { { g_backCoverTR.x, g_backCoverBL.y - g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(224)) }, + { { g_backCoverTR.x + g_boxBorderWidth, g_backCoverBL.y, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(256)) }, + + // Face du bas + { { g_frontCoverTR.x, g_frontCoverBL.y - g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(224)) }, + { { g_frontCoverBL.x, g_frontCoverBL.y - g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(224)) }, + { { g_backCoverBL.x, g_backCoverBL.y - g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(256)) }, + { { g_backCoverTR.x, g_backCoverBL.y - g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(224)) }, + + // Face de gauche en haut + { { g_frontCoverBL.x, g_frontCoverTR.y, g_frontCoverBL.z }, CTexCoord(w(1), h(1)) }, + { { g_frontCoverBL.x, g_frontCoverTR.y + g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(1), h(1)) }, + { { g_backCoverBL.x, g_backCoverTR.y + g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(1), h(1)) }, + { { g_backCoverBL.x, g_backCoverTR.y, g_backCoverBL.z}, CTexCoord(w(1), h(1)) }, + + // Face de gauche en bas + { { g_frontCoverBL.x, g_frontCoverBL.y - g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(1), h(1)) }, + { { g_frontCoverBL.x, g_frontCoverBL.y, g_frontCoverBL.z }, CTexCoord(w(1), h(1)) }, + { { g_backCoverBL.x, g_backCoverBL.y, g_backCoverBL.z }, CTexCoord(w(1), h(1)) }, + { { g_backCoverBL.x, g_backCoverBL.y - g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(1), h(1)) }, +}; + +const SMeshVert g_boxMeshT[] ATTRIBUTE_ALIGN(32) = { // Triangles + // Haut devant + { { g_frontCoverTR.x, g_frontCoverTR.y, g_frontCoverBL.z }, CTexCoord(w(0), h(16)) }, + { { g_frontCoverTR.x + g_boxBorderWidth, g_frontCoverTR.y, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(0)) }, + { { g_frontCoverTR.x, g_frontCoverTR.y + g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(32)) }, + + // Haut derrière + { { g_backCoverTR.x, g_backCoverTR.y, g_backCoverBL.z }, CTexCoord(w(64), h(16)) }, + { { g_backCoverTR.x, g_backCoverTR.y + g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(32)) }, + { { g_backCoverTR.x + g_boxBorderWidth, g_backCoverTR.y, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(0)) }, + + // Bas devant + { { g_frontCoverTR.x, g_frontCoverBL.y, g_frontCoverBL.z }, CTexCoord(w(0), h(240)) }, + { { g_frontCoverTR.x, g_frontCoverBL.y - g_boxBorderWidth, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(224)) }, + { { g_frontCoverTR.x + g_boxBorderWidth, g_frontCoverBL.y, g_frontCoverBL.z - g_boxBorderWidth }, CTexCoord(w(10), h(256)) }, + + // Bas derrière + { { g_backCoverTR.x, g_backCoverBL.y, g_backCoverBL.z }, CTexCoord(w(64), h(240)) }, + { { g_backCoverTR.x + g_boxBorderWidth, g_backCoverBL.y, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(256)) }, + { { g_backCoverTR.x, g_backCoverBL.y - g_boxBorderWidth, g_backCoverBL.z + g_boxBorderWidth }, CTexCoord(w(54), h(224)) } +}; + +#undef h +#undef w + +const SMeshVert g_flatCoverMesh[] ATTRIBUTE_ALIGN(32) = { + { { g_frontCoverBL.x, g_frontCoverBL.y, g_frontCoverBL.z }, CTexCoord(0.f, 1.f) }, + { { g_frontCoverTR.x, g_frontCoverBL.y, g_frontCoverBL.z }, CTexCoord(1.f, 1.f) }, + { { g_frontCoverTR.x, g_frontCoverTR.y, g_frontCoverBL.z }, CTexCoord(1.f, 0.f) }, + { { g_frontCoverBL.x, g_frontCoverTR.y, g_frontCoverBL.z }, CTexCoord(0.f, 0.f) }, +}; + +const SMeshVert g_boxBackCoverMesh[] ATTRIBUTE_ALIGN(32) = { + { { g_backCoverTR.x, g_backCoverBL.y, g_backCoverBL.z }, CTexCoord(0.f, 1.f) }, + { { g_backCoverBL.x, g_backCoverBL.y, g_backCoverBL.z }, CTexCoord(1.3f / 2.76f, 1.f) }, + { { g_backCoverBL.x, g_backCoverTR.y, g_backCoverBL.z }, CTexCoord(1.3f / 2.76f, 0.f) }, + { { g_backCoverTR.x, g_backCoverTR.y, g_backCoverBL.z }, CTexCoord(0.f, 0.f) }, + + { { g_frontCoverBL.x, g_frontCoverBL.y, g_frontCoverBL.z }, CTexCoord(1.46f / 2.76f, 1.f) }, + { { g_frontCoverBL.x, g_frontCoverTR.y, g_frontCoverBL.z }, CTexCoord(1.46f / 2.76f, 0.f) }, + { { g_backCoverBL.x, g_backCoverTR.y, g_backCoverBL.z }, CTexCoord(1.3f / 2.76f, 0.f) }, + { { g_backCoverBL.x, g_backCoverBL.y, g_backCoverBL.z }, CTexCoord(1.3f / 2.76f, 1.f) }, +}; + +const SMeshVert g_boxCoverMesh[] ATTRIBUTE_ALIGN(32) = { + { { g_frontCoverBL.x, g_frontCoverBL.y, g_frontCoverBL.z }, CTexCoord(1.46f / 2.76f, 1.f) }, + { { g_frontCoverTR.x, g_frontCoverBL.y, g_frontCoverBL.z }, CTexCoord(1.f, 1.f) }, + { { g_frontCoverTR.x, g_frontCoverTR.y, g_frontCoverBL.z }, CTexCoord(1.f, 0.f) }, + { { g_frontCoverBL.x, g_frontCoverTR.y, g_frontCoverBL.z }, CTexCoord(1.46f / 2.76f, 0.f) } +}; + +const u32 g_flatCoverMeshSize = sizeof g_flatCoverMesh / sizeof g_flatCoverMesh[0]; +const u32 g_boxMeshQSize = sizeof g_boxMeshQ / sizeof g_boxMeshQ[0]; +const u32 g_boxMeshTSize = sizeof g_boxMeshT / sizeof g_boxMeshT[0]; +const u32 g_boxCoverMeshSize = sizeof g_boxCoverMesh / sizeof g_boxCoverMesh[0]; +const u32 g_boxBackCoverMeshSize = sizeof g_boxBackCoverMesh / sizeof g_boxBackCoverMesh[0]; diff --git a/source/BoxCover/BoxMesh.hpp b/source/BoxCover/BoxMesh.hpp new file mode 100644 index 0000000..a56cbc5 --- /dev/null +++ b/source/BoxCover/BoxMesh.hpp @@ -0,0 +1,45 @@ +#ifndef BOXMESH_HPP_ +#define BOXMESH_HPP_ + +//Box mesh from hibern + +// Quick and dirty hardcoded DVD box mesh +// Should be replaced by a true mesh loader +// Lacks normals + +class CTexCoord +{ +public: + float x; + float y; +public: + CTexCoord(void) { x = 0.f; y = 0.f; } + CTexCoord(float px, float py) { x = px; y = py; } +}; + +struct SMeshVert +{ + guVector pos; + CTexCoord texCoord; +}; + +// Flat cover +extern const SMeshVert g_flatCoverMesh[]; +extern const u32 g_flatCoverMeshSize; + +// Box +extern const SMeshVert g_boxMeshQ[]; // Quads +extern const u32 g_boxMeshQSize; +extern const SMeshVert g_boxMeshT[]; // Triangles +extern const u32 g_boxMeshTSize; +// Box cover +extern const SMeshVert g_boxBackCoverMesh[]; +extern const u32 g_boxBackCoverMeshSize; +extern const SMeshVert g_boxCoverMesh[]; +extern const u32 g_boxCoverMeshSize; +// +extern const float g_boxCoverYCenter; +extern const float g_coverYCenter; + + +#endif diff --git a/source/Channels/channels.cpp b/source/Channels/channels.cpp new file mode 100755 index 0000000..db5a338 --- /dev/null +++ b/source/Channels/channels.cpp @@ -0,0 +1,754 @@ +/*************************************************************************** + * Copyright (C) 2010 by dude + * Copyright (C) 2011 by Miigotu + * Copyright (C) 2011 by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include +#include "FileOperations/fileops.h" +#include "Controls/DeviceHandler.hpp" +#include "settings/CSettings.h" +#include "settings/GameTitles.h" +#include "patches/gamepatches.h" +#include "wad/nandtitle.h" +#include "memory/memory.h" +#include "utils/lz77.h" +#include "gecko.h" + +#include "channels.h" + +typedef struct _dolheader{ + u32 section_pos[18]; + u32 section_start[18]; + u32 section_size[18]; + u32 bss_start; + u32 bss_size; + u32 entry_point; + u32 padding[7]; +} __attribute__((packed)) dolheader; + +Channels *Channels::instance = NULL; + +void Channels::GetEmuChannelList() +{ + EmuChannels.clear(); + + char filepath[1024]; + int language = CONF_GetLanguage(); + + snprintf(filepath, sizeof(filepath), "%s/title/00010001", Settings.NandEmuChanPath); + ParseTitleDir(filepath, language); + + snprintf(filepath, sizeof(filepath), "%s/title/00010004", Settings.NandEmuChanPath); + ParseTitleDir(filepath, language); + + snprintf(filepath, sizeof(filepath), "%s/title/00010002", Settings.NandEmuChanPath); + ParseTitleDir(filepath, language); +} + +void Channels::GetChannelList() +{ + NandChannels.clear(); + + // Get count of titles of the good titles + InternalGetNandChannelList(0x00010001); + InternalGetNandChannelList(0x00010004); + InternalGetNandChannelList(0x00010002); +} + +void Channels::InternalGetNandChannelList(u32 type) +{ + // Get count of system titles + u32 num_titles = NandTitles.SetType(type); + + for (u32 i = 0; i < num_titles; i++) + { + u64 tid = NandTitles.Next(); + if (!tid) + break; + + //these can't be booted anyways + if (TITLE_LOWER( tid ) == 0x48414741 || TITLE_LOWER( tid ) == 0x48414141 || TITLE_LOWER( tid ) == 0x48414641) + continue; + + //these aren't installed on the nand + if (!NandTitles.Exists(tid)) + continue; + + char id[5]; + NandTitles.AsciiTID(tid, id); + + // Force old and new format to be "JODI" which is known by GameTDB + if(tid == 0x000100014c554c5aLL || tid == 0x00010001AF1BF516LL || tid == 0x0001000148415858LL) + strcpy(id, "JODI"); + + const char *name = GameTitles.GetTitle(id); + std::string TitleName; + + if(!name || *name == '\0') + { + name = NandTitles.NameOf(tid); + // Set title for caching + if(name) + GameTitles.SetGameTitle(id, name); + } + + int s = NandChannels.size(); + NandChannels.resize(s + 1); + memset(&NandChannels[s], 0, sizeof(struct discHdr)); + memcpy(NandChannels[s].id, id, 4); + NandChannels[s].tid = tid; + NandChannels[s].type = TYPE_GAME_NANDCHAN; + strncpy(NandChannels[s].title, name ? name : "", sizeof(NandChannels[s].title)-1); + } +} + +vector & Channels::GetNandHeaders(void) +{ + if(NandChannels.empty()) + this->GetChannelList(); + + return NandChannels; +} + +vector & Channels::GetEmuHeaders(void) +{ + if(EmuChannels.empty()) + this->GetEmuChannelList(); + + return EmuChannels; +} + +u8 * Channels::GetDol(const u64 &title, u8 *tmdBuffer) +{ + static const u8 dolsign[6] = {0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; + static u8 dolhead[32] ATTRIBUTE_ALIGN(32); + u8 *buffer = NULL; + u32 filesize = 0; + u32 bootcontent = 0xDEADBEAF; + u32 high = TITLE_UPPER(title); + u32 low = TITLE_LOWER(title); + + char *filepath = (char *) memalign(32, ISFS_MAXPATH); + if(!filepath) + return NULL; + + _tmd * tmd_file = (_tmd *) SIGNATURE_PAYLOAD((u32 *)tmdBuffer); + + if(!Settings.UseChanLauncher) + { + for(u32 i = 0; i < tmd_file->num_contents; ++i) + { + if(tmd_file->contents[i].index == tmd_file->boot_index) + continue; // Skip loader + + snprintf(filepath, ISFS_MAXPATH, "/title/%08x/%08x/content/%08x.app", (unsigned int)high, (unsigned int)low, (unsigned int)tmd_file->contents[i].cid); + + s32 fd = ISFS_Open(filepath, ISFS_OPEN_READ); + if(fd < 0) + continue; + + s32 ret = ISFS_Read(fd, dolhead, 32); + ISFS_Close(fd); + + if(ret != 32) + continue; + + if(memcmp(dolhead, dolsign, sizeof(dolsign)) == 0) + { + bootcontent = tmd_file->contents[i].cid; + break; + } + } + } + + //! Fall back to boot content if dol is not found + if(bootcontent == 0xDEADBEAF) + { + bootcontent = tmd_file->contents[tmd_file->boot_index].cid; + if(!Settings.UseChanLauncher) gprintf("Main dol not found -> "); + gprintf("Loading boot content index\n"); + } + + snprintf(filepath, ISFS_MAXPATH, "/title/%08x/%08x/content/%08x.app", (unsigned int)high, (unsigned int)low, (unsigned int)bootcontent); + gprintf("Loading Channel DOL: %s\n", filepath); + + if (NandTitle::LoadFileFromNand(filepath, &buffer, &filesize) < 0) + { + gprintf("Failed loading DOL file\n"); + free(filepath); + return NULL; + } + + free(filepath); + + if (isLZ77compressed(buffer)) + { + u8 *decompressed = NULL; + u32 size = 0; + if (decompressLZ77content(buffer, filesize, &decompressed, &size) < 0) + { + gprintf("Decompression failed\n"); + free(buffer); + return NULL; + } + free(buffer); + buffer = decompressed; + filesize = size; + } + + // move dol to mem2 + u8 *outBuf = (u8 *) MEM2_alloc(filesize); + if(!outBuf) + return buffer; + + memcpy(outBuf, buffer, filesize); + free(buffer); + + return outBuf; +} + +u8 Channels::GetRequestedIOS(const u64 &title) +{ + u8 IOS = 0; + + u32 tmdSize = 0; + u8 *titleTMD = GetTMD(title, &tmdSize, ""); + if (!titleTMD) + return 0; + + if(tmdSize > 0x18B) + IOS = titleTMD[0x18B]; + + free(titleTMD); + + return IOS; +} + +u8 *Channels::GetTMD(const u64 &tid, u32 *size, const char *prefix) +{ + char *filepath = (char *) memalign(32, ISFS_MAXPATH); + if(!filepath) + return NULL; + + if(!prefix) + prefix = ""; + + snprintf(filepath, ISFS_MAXPATH, "%s/title/%08x/%08x/content/title.tmd", prefix, (unsigned int)TITLE_UPPER(tid), (unsigned int)TITLE_LOWER(tid)); + + u8 *tmdBuffer = NULL; + u32 tmdSize = 0; + + int ret; + + if(*prefix != '\0') + ret = LoadFileToMem(filepath, &tmdBuffer, &tmdSize); + else + ret = NandTitle::LoadFileFromNand(filepath, &tmdBuffer, &tmdSize); + + free(filepath); + + if (ret < 0) + { + gprintf("Reading TMD...Failed!\n"); + if(tmdBuffer) + free(tmdBuffer); + return NULL; + } + + if(size) + *size = tmdSize; + + return tmdBuffer; +} + +u32 Channels::LoadChannel(const u64 &chantitle) +{ + ISFS_Initialize(); + + u32 ios = 0; + u32 tmdSize = 0; + u8 *tmdBuffer = GetTMD(chantitle, &tmdSize, ""); + if(!tmdBuffer) + { + ISFS_Deinitialize(); + return 0; + } + + u8 *chanDOL = GetDol(chantitle, tmdBuffer); + if(!chanDOL) + { + ISFS_Deinitialize(); + free(tmdBuffer); + return 0; + } + + if(tmdSize > 0x18B) + ios = tmdBuffer[0x18B]; + + Identify(chantitle, tmdBuffer, tmdSize); + + free(tmdBuffer); + + dolheader *dolfile = (dolheader *)chanDOL; + + if(dolfile->bss_start) + { + dolfile->bss_start |= 0x80000000; + + if(dolfile->bss_start < 0x81800000) + { + // For homebrews...not all have it clean. + if(dolfile->bss_start + dolfile->bss_size >= 0x81800000) + dolfile->bss_size = 0x81800000 - dolfile->bss_start; + + memset((void *)dolfile->bss_start, 0, dolfile->bss_size); + DCFlushRange((void *)dolfile->bss_start, dolfile->bss_size); + ICInvalidateRange((void *)dolfile->bss_start, dolfile->bss_size); + } + } + + int i; + for(i = 0; i < 18; i++) + { + if (!dolfile->section_size[i]) continue; + if (dolfile->section_pos[i] < sizeof(dolheader)) continue; + if(!(dolfile->section_start[i] & 0x80000000)) + dolfile->section_start[i] |= 0x80000000; + + u8 *dolChunkOffset = (u8 *)dolfile->section_start[i]; + u32 dolChunkSize = dolfile->section_size[i]; + + memmove (dolChunkOffset, chanDOL + dolfile->section_pos[i], dolChunkSize); + DCFlushRange(dolChunkOffset, dolChunkSize); + ICInvalidateRange(dolChunkOffset, dolChunkSize); + + RegisterDOL(dolChunkOffset, dolChunkSize); + } + + u32 chanEntryPoint = dolfile->entry_point; + + free(dolfile); + + // Preparations + memset((void *)Disc_ID, 0, 6); + *Disc_ID = TITLE_LOWER(chantitle); // Game ID + *Arena_H = 0; // Arena High, the apploader does this too + *BI2 = 0x817FE000; // BI2, the apploader does this too + *Bus_Speed = 0x0E7BE2C0; // bus speed + *CPU_Speed = 0x2B73A840; // cpu speed + *GameID_Address = 0x81000000; // Game id address, while there's all 0s at 0x81000000 when using the apploader... + memcpy((void *)Online_Check, (void *)Disc_ID, 4);// online check + + memset((void *)0x817FE000, 0, 0x2000); // Clearing BI2 + DCFlushRange((void*)0x817FE000, 0x2000); + + // IOS Version Check + *(vu32*)0x80003140 = ((ios << 16)) | 0xFFFF; + *(vu32*)0x80003188 = ((ios << 16)) | 0xFFFF; + + ISFS_Deinitialize(); + + return chanEntryPoint; +} + +static bool Identify_GenerateTik(signed_blob **outbuf, u32 *outlen) +{ + signed_blob *buffer = (signed_blob *)memalign(32, STD_SIGNED_TIK_SIZE); + if (!buffer) return false; + memset(buffer, 0, STD_SIGNED_TIK_SIZE); + + sig_rsa2048 *signature = (sig_rsa2048 *)buffer; + signature->type = ES_SIG_RSA2048; + + tik *tik_data = (tik *)SIGNATURE_PAYLOAD(buffer); + strcpy(tik_data->issuer, "Root-CA00000001-XS00000003"); + memset(tik_data->cidx_mask, 0xFF, 32); + + *outbuf = buffer; + *outlen = STD_SIGNED_TIK_SIZE; + + return true; +} + +bool Channels::Identify(const u64 &titleid, u8 *tmdBuffer, u32 tmdSize) +{ + char *filepath = (char *) memalign(32, ISFS_MAXPATH); + if(!filepath) + return false; + + u32 tikSize; + signed_blob *tikBuffer = NULL; + + if(!Identify_GenerateTik(&tikBuffer,&tikSize)) + { + free(filepath); + gprintf("Generating fake ticket...Failed!"); + return false; + } + + strlcpy(filepath, "/sys/cert.sys", ISFS_MAXPATH); + u8 *certBuffer = NULL; + u32 certSize = 0; + if (NandTitle::LoadFileFromNand(filepath, &certBuffer, &certSize) < 0) + { + gprintf("Reading certs...Failed!\n"); + free(tikBuffer); + free(filepath); + return false; + } + s32 ret = ES_Identify((signed_blob*)certBuffer, certSize, (signed_blob*)tmdBuffer, tmdSize, tikBuffer, tikSize, NULL); + if (ret < 0) + { + switch(ret) + { + case ES_EINVAL: + gprintf("Error! ES_Identify (ret = %d;) Data invalid!\n", ret); + break; + case ES_EALIGN: + gprintf("Error! ES_Identify (ret = %d;) Data not aligned!\n", ret); + break; + case ES_ENOTINIT: + gprintf("Error! ES_Identify (ret = %d;) ES not initialized!\n", ret); + break; + case ES_ENOMEM: + gprintf("Error! ES_Identify (ret = %d;) No memory!\n", ret); + break; + default: + gprintf("Error! ES_Identify (ret = %d)\n", ret); + break; + } + } + + free(tikBuffer); + free(filepath); + free(certBuffer); + + return ret < 0 ? false : true; +} + +bool Channels::emuExists(char *tmdpath) +{ + u8 *buffer = NULL; + u32 size = 0; + + if(LoadFileToMem(tmdpath, &buffer, &size) < 0) + return false; + + signed_blob *s_tmd = (signed_blob *) buffer; + + u32 i; + tmd *titleTmd = (tmd *) SIGNATURE_PAYLOAD(s_tmd); + + for (i = 0; i < titleTmd->num_contents; i++) + if (!titleTmd->contents[i].index) + break; + + if(i == titleTmd->num_contents) + { + free(buffer); + return false; + } + + u32 cid = titleTmd->contents[i].cid; + + free(buffer); + + char *ptr = strrchr(tmdpath, '/'); + if(!ptr) + return false; + + //! tmdpath has length of 1024 + snprintf(ptr+1, 1024-(ptr+1-tmdpath), "%08x.app", (unsigned int)cid); + + FILE *f = fopen(tmdpath, "rb"); + if(!f) + return false; + + fclose(f); + + return true; +} + +bool Channels::ParseTitleDir(char *path, int language) +{ + if(!path) + return false; + + const char *tidPtr = strrchr(path, '/'); + if(!tidPtr) + return false; + else + tidPtr++; + + struct dirent *dirent = NULL; + DIR *dir = opendir(path); + if(!dir) + return false; + + char *pathEndPtr = path + strlen(path); + + u32 tidHigh = strtoul(tidPtr, NULL, 16); + struct stat st; + + while ((dirent = readdir(dir)) != 0) + { + if(!dirent->d_name) + continue; + + //these can't be booted anyways + if(*dirent->d_name == '.' || strcmp(dirent->d_name, "48414141") == 0 || strcmp(dirent->d_name, "48414641") == 0) + { + continue; + } + + snprintf(pathEndPtr, 1024-(pathEndPtr-path), "/%s/content/title.tmd", dirent->d_name); + + if(stat(path, &st) != 0) + continue; + + // check if content in tmd exists + if(!emuExists(path)) + continue; + + u32 tidLow = strtoul(dirent->d_name, NULL, 16); + char id[5]; + memset(id, 0, sizeof(id)); + memcpy(id, &tidLow, 4); + + u64 tid = ((u64)tidHigh << 32) | ((u64) tidLow); + + // Force old and new format to be "JODI" which is known by GameTDB + if(tid == 0x000100014c554c5aLL || tid == 0x00010001AF1BF516LL || tid == 0x0001000148415858LL) + strcpy(id, "JODI"); + + std::string TitleName; + + const char *title = GameTitles.GetTitle(id); + if(title && *title != '\0') + { + TitleName = title; + } + else if(GetEmuChanTitle(path, language, TitleName)) + { + GameTitles.SetGameTitle(id, TitleName.c_str()); + } + else + { + TitleName = id; + } + + int s = EmuChannels.size(); + EmuChannels.resize(s + 1); + memset(&EmuChannels[s], 0, sizeof(struct discHdr)); + memcpy(EmuChannels[s].id, id, 4); + EmuChannels[s].tid = tid; + EmuChannels[s].type = TYPE_GAME_EMUNANDCHAN; + strncpy(EmuChannels[s].title, TitleName.c_str(), sizeof(EmuChannels[s].title)-1); + } + + closedir(dir); + + return true; +} + +bool Channels::GetEmuChanTitle(char *tmdpath, int language, std::string &Title) +{ + u8 *buffer = NULL; + u32 size = 0; + + if(LoadFileToMem(tmdpath, &buffer, &size) < 0) + return false; + + signed_blob *s_tmd = (signed_blob *) buffer; + + u32 i; + tmd *titleTmd = (tmd *) SIGNATURE_PAYLOAD(s_tmd); + + for (i = 0; i < titleTmd->num_contents; i++) + if (!titleTmd->contents[i].index) + break; + + if(i == titleTmd->num_contents) + { + free(buffer); + return false; + } + + u32 cid = titleTmd->contents[i].cid; + + free(buffer); + + char *ptr = strrchr(tmdpath, '/'); + if(!ptr) + return false; + + //! tmdpath has length of 1024 + snprintf(ptr+1, 1024-(ptr+1-tmdpath), "%08x.app", (unsigned int)cid); + + FILE *f = fopen(tmdpath, "rb"); + if(!f) + return false; + + if(fseek(f, IMET_OFFSET, SEEK_SET) != 0) + { + fclose(f); + return false; + } + + IMET *imet = (IMET*) malloc(sizeof(IMET)); + if(!imet) + { + fclose(f); + return false; + } + + if(fread(imet, 1, sizeof(IMET), f) != sizeof(IMET)) + { + free(imet); + fclose(f); + return false; + } + + fclose(f); + + if (imet->sig != IMET_SIGNATURE) + { + free(imet); + return false; + } + + // names not available + if (imet->name_japanese[language * IMET_MAX_NAME_LEN] == 0) + { + if(imet->name_english[0] != 0) + language = CONF_LANG_ENGLISH; + else + { + free(imet); + return false; + } + } + + wchar_t wName[IMET_MAX_NAME_LEN]; + + // retrieve channel name in system language or on english + for (int i = 0; i < IMET_MAX_NAME_LEN; i++) + wName[i] = imet->name_japanese[i + (language * IMET_MAX_NAME_LEN)]; + + wString wsname(wName); + Title = wsname.toUTF8(); + + free(imet); + + return true; +} + +u8 *Channels::GetOpeningBnr(const u64 &title, u32 * outsize, const char *pathPrefix) +{ + u8 *banner = NULL; + u32 high = TITLE_UPPER(title); + u32 low = TITLE_LOWER(title); + + char *filepath = (char *) memalign(32, ISFS_MAXPATH + strlen(pathPrefix)); + if(!filepath) + return NULL; + + do + { + snprintf(filepath, ISFS_MAXPATH, "%s/title/%08x/%08x/content/title.tmd", pathPrefix, (unsigned int)high, (unsigned int)low); + + u8 *buffer = NULL; + u32 filesize = 0; + + int ret = 0; + + if(pathPrefix && *pathPrefix != 0) + ret = LoadFileToMem(filepath, &buffer, &filesize); + else + ret = NandTitle::LoadFileFromNand(filepath, &buffer, &filesize); + + if (ret < 0) + break; + + _tmd * tmd_file = (_tmd *) SIGNATURE_PAYLOAD((u32 *)buffer); + bool found = false; + u32 bootcontent = 0; + for(u32 i = 0; i < tmd_file->num_contents; ++i) + { + if(tmd_file->contents[i].index == 0) + { + bootcontent = tmd_file->contents[i].cid; + found = true; + break; + } + } + + free(buffer); + buffer = NULL; + filesize = 0; + + if(!found) + break; + + snprintf(filepath, ISFS_MAXPATH, "%s/title/%08x/%08x/content/%08x.app", pathPrefix, (unsigned int)high, (unsigned int)low, (unsigned int)bootcontent); + + if(pathPrefix && *pathPrefix != 0) + ret = LoadFileToMem(filepath, &buffer, &filesize); + else + ret = NandTitle::LoadFileFromNand(filepath, &buffer, &filesize); + + if (ret < 0) + break; + + IMET *imet = (IMET *) (buffer + IMET_OFFSET); + if(imet->sig != 'IMET') + { + free(buffer); + break; + } + + // move IMET_OFFSET bytes back + filesize -= IMET_OFFSET; + + banner = (u8 *) memalign(32, filesize); + if(!banner) + { + free(buffer); + break; + } + + memcpy(banner, buffer + IMET_OFFSET, filesize); + + free(buffer); + + if(outsize) + *outsize = filesize; + } + while(0); + + free(filepath); + + return banner; +} diff --git a/source/Channels/channels.h b/source/Channels/channels.h new file mode 100755 index 0000000..2d88486 --- /dev/null +++ b/source/Channels/channels.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2010 by dude + * Copyright (C) 2011 by Miigotu + * Copyright (C) 2011 by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _CHANNELS_H_ +#define _CHANNELS_H_ + +#include +#include +#include +#include "usbloader/disc.h" + +using namespace std; + +class Channels +{ +public: + static Channels *Instance(void) { if(!instance) instance = new Channels(); return instance; } + static void DestroyInstance(void) { if(instance) delete instance; instance = NULL; } + + static u32 LoadChannel(const u64 &chantitle); + static u8 GetRequestedIOS(const u64 &title); + static u8 *GetTMD(const u64 &tid, u32 *size, const char *prefix); + static u8 *GetDol(const u64 &title, u8 *tmdBuffer); + static u8 *GetOpeningBnr(const u64 &title, u32 *outsize, const char *pathPrefix); + + void GetChannelList(); + void GetEmuChannelList(); + vector & GetNandHeaders(void); + vector & GetEmuHeaders(void); +private: + static Channels *instance; + + static bool Identify(const u64 &titleid, u8 *tmdBuffer, u32 tmdSize); + bool emuExists(char *tmdpath); + + void InternalGetNandChannelList(u32 type); + bool ParseTitleDir(char *path, int language); + bool GetEmuChanTitle(char *tmdpath, int language, std::string &Title); + + vector NandChannels; + vector EmuChannels; +}; + +#endif diff --git a/source/Controls/DeviceHandler.cpp b/source/Controls/DeviceHandler.cpp new file mode 100644 index 0000000..df8285d --- /dev/null +++ b/source/Controls/DeviceHandler.cpp @@ -0,0 +1,403 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include "settings/CSettings.h" +#include "usbloader/usbstorage2.h" +#include "DeviceHandler.hpp" +#include "usbloader/wbfs.h" +#include "system/IosLoader.h" + +DeviceHandler * DeviceHandler::instance = NULL; + +DeviceHandler::~DeviceHandler() +{ + UnMountAll(); +} + +DeviceHandler * DeviceHandler::Instance() +{ + if (instance == NULL) + { + instance = new DeviceHandler(); + } + return instance; +} + +void DeviceHandler::DestroyInstance() +{ + if(instance) + { + delete instance; + } + instance = NULL; +} + +bool DeviceHandler::MountAll() +{ + bool result = false; + + for(u32 i = SD; i < MAXDEVICES; i++) + { + if(Mount(i)) + result = true; + } + + return result; +} + +void DeviceHandler::UnMountAll() +{ + for(u32 i = SD; i < MAXDEVICES; i++) + UnMount(i); + + if(sd) + delete sd; + if(usb0) + delete usb0; + if(usb1) + delete usb1; + + sd = NULL; + usb0 = NULL; + usb1 = NULL; +} + +bool DeviceHandler::Mount(int dev) +{ + if(dev == SD) + return MountSD(); + + else if(dev >= USB1 && dev <= USB8) + return MountUSB(dev-USB1); + + return false; +} + +bool DeviceHandler::IsInserted(int dev) +{ + if(dev == SD) + return SD_Inserted() && sd->IsMounted(0); + + else if(dev >= USB1 && dev <= USB8) + { + int portPart = PartitionToPortPartition(dev-USB1); + PartitionHandle *usb = instance->GetUSBHandleFromPartition(dev-USB1); + if(usb) + return usb->IsMounted(portPart); + } + + return false; +} + +void DeviceHandler::UnMount(int dev) +{ + if(dev == SD) + UnMountSD(); + + else if(dev >= USB1 && dev <= USB8) + UnMountUSB(dev-USB1); +} + +bool DeviceHandler::MountSD() +{ + if(!sd) + sd = new PartitionHandle(&__io_wiisd); + + if(sd->GetPartitionCount() < 1) + { + delete sd; + sd = NULL; + return false; + } + + //! Mount only one SD Partition + return sd->Mount(0, DeviceName[SD], true); +} + +static inline bool USBSpinUp() +{ + bool started0 = false; + bool started1 = false; + int retries = 400; + + const DISC_INTERFACE * handle0 = NULL; + const DISC_INTERFACE * handle1 = NULL; + if(Settings.USBPort == 0 || Settings.USBPort == 2) + handle0 = DeviceHandler::GetUSB0Interface(); + if(Settings.USBPort == 1 || Settings.USBPort == 2) + handle1 = DeviceHandler::GetUSB1Interface(); + + // wait 20 sec for the USB to spin up...stupid slow ass HDD + do + { + if(handle0) + started0 = (handle0->startup() && handle0->isInserted()); + + if(handle1) + started1 = (handle1->startup() && handle1->isInserted()); + + if( (!handle0 || started0) + && (!handle1 || started1)) { + break; + } + usleep(50000); + } + while(--retries > 0); + + return (started0 || started1); +} + +bool DeviceHandler::MountUSB(int pos) +{ + if(!usb0 && !usb1) + return false; + + if(pos >= GetUSBPartitionCount()) + return false; + + int portPart = PartitionToPortPartition(pos); + + if(PartitionToUSBPort(pos) == 0 && usb0) + return usb0->Mount(portPart, DeviceName[USB1+pos]); + else if(usb1) + return usb1->Mount(portPart, DeviceName[USB1+pos]); + + return false; +} + +bool DeviceHandler::MountAllUSB(bool spinup) +{ + if(spinup && !USBSpinUp()) + return false; + + if(!usb0 && (Settings.USBPort == 0 || Settings.USBPort == 2)) + usb0 = new PartitionHandle(GetUSB0Interface()); + if(!usb1 && (Settings.USBPort == 1 || Settings.USBPort == 2) && IOS_GetVersion() >= 200) + usb1 = new PartitionHandle(GetUSB1Interface()); + + if(usb0 && usb0->GetPartitionCount() < 1) + { + delete usb0; + usb0 = NULL; + } + if(usb1 && usb1->GetPartitionCount() < 1) + { + delete usb1; + usb1 = NULL; + } + + bool result = false; + int partCount = GetUSBPartitionCount(); + + for(int i = 0; i < partCount; i++) + { + if(MountUSB(i)) + result = true; + } + + return result; +} + +bool DeviceHandler::MountUSBPort1(bool spinup) +{ + if(spinup && !USBSpinUp()) + return false; + + if(!usb1 && (Settings.USBPort == 1 || Settings.USBPort == 2) && IOS_GetVersion() >= 200) + usb1 = new PartitionHandle(GetUSB1Interface()); + + if(usb1 && usb1->GetPartitionCount() < 1) + { + delete usb1; + usb1 = NULL; + return false; + } + + bool result = false; + int partCount = GetUSBPartitionCount(); + int partCount0 = 0; + if(usb0) + partCount0 = usb0->GetPartitionCount(); + + for(int i = partCount0; i < partCount; i++) + { + if(MountUSB(i)) + result = true; + } + + return result; +} + +void DeviceHandler::UnMountUSB(int pos) +{ + if(pos >= GetUSBPartitionCount()) + return; + + int portPart = PartitionToPortPartition(pos); + + if(PartitionToUSBPort(pos) == 0 && usb0) + return usb0->UnMount(portPart); + else if(usb1) + return usb1->UnMount(portPart); +} + +void DeviceHandler::UnMountAllUSB() +{ + int partCount = GetUSBPartitionCount(); + + for(int i = 0; i < partCount; i++) + UnMountUSB(i); + + delete usb0; + usb0 = NULL; + delete usb1; + usb1 = NULL; +} + +int DeviceHandler::PathToDriveType(const char * path) +{ + if(!path) + return -1; + + for(int i = SD; i < MAXDEVICES; i++) + { + if(strncasecmp(path, DeviceName[i], strlen(DeviceName[i])) == 0) + return i; + } + + return -1; +} + +const char * DeviceHandler::GetFSName(int dev) +{ + if(dev == SD && DeviceHandler::instance->sd) + { + return DeviceHandler::instance->sd->GetFSName(0); + } + else if(dev >= USB1 && dev <= USB8) + { + int partCount0 = 0; + int partCount1 = 0; + if(DeviceHandler::instance->usb0) + partCount0 += DeviceHandler::instance->usb0->GetPartitionCount(); + if(DeviceHandler::instance->usb1) + partCount1 += DeviceHandler::instance->usb1->GetPartitionCount(); + + if(dev-USB1 < partCount0 && DeviceHandler::instance->usb0) + return DeviceHandler::instance->usb0->GetFSName(dev-USB1); + else if(DeviceHandler::instance->usb1) + return DeviceHandler::instance->usb1->GetFSName(dev-USB1-partCount0); + } + + return ""; +} + +const char * DeviceHandler::GetDevicePrefix(const char * path) +{ + if(PathToDriveType(path) == -1) + return ""; + return DeviceName[PathToDriveType(path)]; +} + +int DeviceHandler::GetFilesystemType(int dev) +{ + if(!instance) + return -1; + + const char *FSName = GetFSName(dev); + if(!FSName) return -1; + + if(strncmp(FSName, "WBFS", 4) == 0) + return PART_FS_WBFS; + else if(strncmp(FSName, "FAT", 3) == 0) + return PART_FS_FAT; + else if(strncmp(FSName, "NTFS", 4) == 0) + return PART_FS_NTFS; + else if(strncmp(FSName, "LINUX", 4) == 0) + return PART_FS_EXT; + + return -1; +} + + +u16 DeviceHandler::GetUSBPartitionCount() +{ + if(!instance) + return 0; + + u16 partCount0 = 0; + u16 partCount1 = 0; + if(instance->usb0) + partCount0 = instance->usb0->GetPartitionCount(); + if(instance->usb1) + partCount1 = instance->usb1->GetPartitionCount(); + + return partCount0+partCount1; +} + +int DeviceHandler::PartitionToUSBPort(int part) +{ + if(!DeviceHandler::instance) + return 0; + + u16 partCount0 = 0; + if(DeviceHandler::instance->usb0) + partCount0 = instance->usb0->GetPartitionCount(); + + if(!instance->usb0 || part >= partCount0) + return 1; + else + return 0; +} + +int DeviceHandler::PartitionToPortPartition(int part) +{ + if(!DeviceHandler::instance) + return 0; + + u16 partCount0 = 0; + if(instance->usb0) + partCount0 = instance->usb0->GetPartitionCount(); + + if(!instance->usb0 || part >= partCount0) + return part-partCount0; + else + return part; +} + +PartitionHandle *DeviceHandler::GetUSBHandleFromPartition(int part) const +{ + if(PartitionToUSBPort(part) == 0) + return usb0; + else + return usb1; +} diff --git a/source/Controls/DeviceHandler.hpp b/source/Controls/DeviceHandler.hpp new file mode 100644 index 0000000..5b4261c --- /dev/null +++ b/source/Controls/DeviceHandler.hpp @@ -0,0 +1,115 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef DEVICE_HANDLER_HPP_ +#define DEVICE_HANDLER_HPP_ + +#include "PartitionHandle.h" +#include "usbloader/usbstorage2.h" + +/** + * libogc device names. + */ +enum +{ + SD = 0, + USB1, + USB2, + USB3, + USB4, + USB5, + USB6, + USB7, + USB8, + MAXDEVICES +}; + +/** + * libogc device names. + */ +const char DeviceName[MAXDEVICES][8] = +{ + "sd", + "usb1", + "usb2", + "usb3", + "usb4", + "usb5", + "usb6", + "usb7", + "usb8", +}; + +class DeviceHandler +{ + public: + static DeviceHandler * Instance(); + static void DestroyInstance(); + + bool MountAll(); + void UnMountAll(); + bool Mount(int dev); + bool IsInserted(int dev); + void UnMount(int dev); + + //! Individual Mounts/UnMounts... + bool MountSD(); + bool MountAllUSB(bool spinUp = true); + bool MountUSBPort1(bool spinUp = true); + bool SD_Inserted() { if(sd) return sd->IsInserted(); return false; } + bool USB0_Inserted() { if(usb0) return usb0->IsInserted(); return false; } + bool USB1_Inserted() { if(usb1) return usb1->IsInserted(); return false; } + void UnMountSD() { if(sd) delete sd; sd = NULL; } + void UnMountUSB(int pos); + void UnMountAllUSB(); + PartitionHandle * GetSDHandle() const { return sd; } + PartitionHandle * GetUSB0Handle() const { return usb0; } + PartitionHandle * GetUSB1Handle() const { return usb1; } + PartitionHandle * GetUSBHandleFromPartition(int part) const; + static const DISC_INTERFACE *GetUSB0Interface() { return (IOS_GetVersion() >= 200) ? &__io_usbstorage2_port0 : &__io_usbstorage; } + static const DISC_INTERFACE *GetUSB1Interface() { return (IOS_GetVersion() >= 200) ? &__io_usbstorage2_port1 : NULL; } + static int GetFilesystemType(int dev); + static const char * GetFSName(int dev); + static int PathToDriveType(const char * path); + static const char * PathToFSName(const char * path) { return GetFSName(PathToDriveType(path)); } + static const char * GetDevicePrefix(const char * path); + static int PartitionToUSBPort(int part); + static u16 GetUSBPartitionCount(); + static int PartitionToPortPartition(int part); + private: + DeviceHandler() : sd(0), gca(0), gcb(0), usb0(0), usb1(0) { } + ~DeviceHandler(); + bool MountUSB(int part); + + static DeviceHandler *instance; + + PartitionHandle * sd; + PartitionHandle * gca; + PartitionHandle * gcb; + PartitionHandle * usb0; + PartitionHandle * usb1; +}; + +#endif diff --git a/source/Controls/PartitionHandle.cpp b/source/Controls/PartitionHandle.cpp new file mode 100644 index 0000000..917584d --- /dev/null +++ b/source/Controls/PartitionHandle.cpp @@ -0,0 +1,438 @@ + /**************************************************************************** + * Copyright (C) 2013 by Cyan + * Copyright (C) 2010 by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include "libs/libwbfs/libwbfs.h" +#include "utils/uncompress.h" +#include "PartitionHandle.h" + +//! libfat stuff +extern "C" +{ + sec_t FindFirstValidPartition(const DISC_INTERFACE* disc); +} + +#define PARTITION_TYPE_DOS33_EXTENDED 0x05 /* DOS 3.3+ extended partition */ +#define PARTITION_TYPE_WIN95_EXTENDED 0x0F /* Windows 95 extended partition */ + +#define CACHE 32 +#define SECTORS 64 + +static inline const char * PartFromType(int type) +{ + switch (type) + { + case 0x00: return "Unused"; + case 0x01: return "FAT12"; + case 0x04: return "FAT16"; + case 0x05: return "Extended"; + case 0x06: return "FAT16"; + case 0x07: return "NTFS"; + case 0x0b: return "FAT32"; + case 0x0c: return "FAT32"; + case 0x0e: return "FAT16"; + case 0x0f: return "Extended"; + case 0x82: return "LxSWP"; + case 0x83: return "LINUX"; + case 0x8e: return "LxLVM"; + case 0xa8: return "OSX"; + case 0xab: return "OSXBT"; + case 0xaf: return "OSXHF"; + case 0xbf: return "WBFS"; + case 0xe8: return "LUKS"; + default: return "Unknown"; + } +} + +PartitionHandle::PartitionHandle(const DISC_INTERFACE *discio) + : interface(discio) +{ + // Sanity check + if (!interface) + return; + + // Start the device and check that it is inserted + if (!interface->startup()) + return; + + if (!interface->isInserted()) + return; + + FindPartitions(); +} + +PartitionHandle::~PartitionHandle() +{ + UnMountAll(); + + //shutdown device + interface->shutdown(); +} + +bool PartitionHandle::IsMounted(int pos) +{ + if(pos < 0 || pos >= (int) MountNameList.size()) + return false; + + if(MountNameList[pos].size() == 0) + return false; + + return true; +} + +bool PartitionHandle::Mount(int pos, const char * name, bool forceFAT) +{ + if(!valid(pos)) + return false; + + if(!name) + return false; + + UnMount(pos); + + if(pos >= (int) MountNameList.size()) + MountNameList.resize(pos+1); + + MountNameList[pos] = name; + + //! Some stupid partition manager think they don't need to edit the freaken MBR. + //! So we need to check the first 64 sectors and see if some partition is there. + //! libfat does that by default so let's use it. + //! We do that only on sd not on usb. + if(forceFAT && (!GetFSName(pos) || strcmp(GetFSName(pos), "Unknown") == 0)) + { + if (fatMount(MountNameList[pos].c_str(), interface, 0, CACHE, SECTORS)) + { + sec_t FAT_startSector = FindFirstValidPartition(interface); + AddPartition("FAT", FAT_startSector, 0xdeadbeaf, true, 0x0c, 0, TABLE_TYPE_UNKNOWN); + return true; + } + } + + if(strncmp(GetFSName(pos), "FAT", 3) == 0 || strcmp(GetFSName(pos), "GUID-Entry") == 0) + { + if (fatMount(MountNameList[pos].c_str(), interface, GetLBAStart(pos), CACHE, SECTORS)) + { + if(strcmp(GetFSName(pos), "GUID-Entry") == 0) + PartitionList[pos].FSName = "FAT"; + return true; + } + } + + if(strncmp(GetFSName(pos), "NTFS", 4) == 0 || strcmp(GetFSName(pos), "GUID-Entry") == 0) + { + if(ntfsMount(MountNameList[pos].c_str(), interface, GetLBAStart(pos), CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) + { + PartitionList[pos].FSName = "NTFS"; + return true; + } + } + + if(strncmp(GetFSName(pos), "LINUX", 5) == 0 || strcmp(GetFSName(pos), "GUID-Entry") == 0) + { + if(ext2Mount(MountNameList[pos].c_str(), interface, GetLBAStart(pos), CACHE, SECTORS, EXT2_FLAG_DEFAULT)) + { + PartitionList[pos].FSName = "LINUX"; + return true; + } + } + + MountNameList[pos].clear(); + + return false; +} + +void PartitionHandle::UnMount(int pos) +{ + if(!interface) + return; + + if(pos >= (int) MountNameList.size()) + return; + + if(MountNameList[pos].size() == 0) + return; + + char DeviceSyn[20]; + snprintf(DeviceSyn, sizeof(DeviceSyn), "%s:", MountNameList[pos].c_str()); + + //closing all open Files write back the cache + fatUnmount(DeviceSyn); + //closing all open Files write back the cache + ntfsUnmount(DeviceSyn, true); + //closing all open Files write back the cache + ext2Unmount(DeviceSyn); + //Remove name from list + MountNameList[pos].clear(); +} + +u32 PartitionHandle::GetPartitionClusterSize(u32 lba_start) +{ + char *buffer = (char *) malloc(MAX_BYTES_PER_SECTOR); + if(!buffer) return 0; + + if (!interface->readSectors(lba_start, 1, buffer)) + { + free(buffer); + return 0; + } + + u32 cluster_size = 0; + + // Only for FAT partitions + if(*((u16 *) (buffer + 0x1FE)) == 0x55AA) + { + if((memcmp(buffer + 0x36, "FAT", 3) == 0 || memcmp(buffer + 0x52, "FAT", 3) == 0)) + { + u16 sector_sz = *((u8*) (buffer + 0x0C)) << 8 | *((u8*) (buffer + 0x0B)); + u8 sector_per_cluster = *((u8*) (buffer + 0x0D)); + cluster_size = sector_sz * sector_per_cluster; + } + } + + free(buffer); + return cluster_size; +} + +bool PartitionHandle::IsExisting(u64 lba) +{ + for(u32 i = 0; i < PartitionList.size(); ++i) + { + if(PartitionList[i].LBA_Start == lba) + return true; + } + + return false; +} + +int PartitionHandle::FindPartitions() +{ + MASTER_BOOT_RECORD *mbr = (MASTER_BOOT_RECORD *) malloc(MAX_BYTES_PER_SECTOR); + if(!mbr) return -1; + + // Read the first sector on the device + if (!interface->readSectors(0, 1, mbr)) + { + free(mbr); + return -1; + } + + // If this is not the device's master boot record + if (mbr->signature != MBR_SIGNATURE && mbr->signature != MBR_SIGNATURE_MOD) + { + // Check if the device has only one WBFS partition without a table. + wbfs_head_t *head = (wbfs_head_t *) mbr; + if (head->magic == wbfs_htonl(WBFS_MAGIC)) + { + AddPartition("WBFS", 0, 0xdeadbeaf, true, 0xBF, 0, TABLE_TYPE_UNKNOWN); + free(mbr); + return 0; + } + + free(mbr); + return -1; + } + + for (int i = 0; i < 4; i++) + { + PARTITION_RECORD * partition = (PARTITION_RECORD *) &mbr->partitions[i]; + + if(partition->type == PARTITION_TYPE_GPT) + { + int ret = CheckGPT(i); + if(ret == 0) // if it's a GPT we don't need to go on looking through the mbr anymore + return ret; + } + + if(partition->type == PARTITION_TYPE_DOS33_EXTENDED || partition->type == PARTITION_TYPE_WIN95_EXTENDED) + { + CheckEBR(i, le32(partition->lba_start)); + continue; + } + + if(le32(partition->block_count) > 0 && !IsExisting(le32(partition->lba_start))) + { + AddPartition(PartFromType(partition->type), le32(partition->lba_start), + le32(partition->block_count), (partition->status == PARTITION_BOOTABLE), + partition->type, i, MBR); + } + } + + free(mbr); + + return 0; +} + +void PartitionHandle::CheckEBR(u8 PartNum, sec_t ebr_lba) +{ + EXTENDED_BOOT_RECORD *ebr = (EXTENDED_BOOT_RECORD *) malloc(MAX_BYTES_PER_SECTOR); + if(!ebr) return; + sec_t next_erb_lba = 0; + + do + { + // Read and validate the extended boot record + if (!interface->readSectors(ebr_lba + next_erb_lba, 1, ebr)) + { + free(ebr); + return; + } + + if (ebr->signature != EBR_SIGNATURE) + { + free(ebr); + return; + } + + if(le32(ebr->partition.block_count) > 0 && !IsExisting(ebr_lba + next_erb_lba + le32(ebr->partition.lba_start))) + { + AddPartition(PartFromType(ebr->partition.type), ebr_lba + next_erb_lba + le32(ebr->partition.lba_start), + le32(ebr->partition.block_count), (ebr->partition.status == PARTITION_BOOTABLE), + ebr->partition.type, PartNum, EBR); + } + // Get the start sector of the current partition + // and the next extended boot record in the chain + next_erb_lba = le32(ebr->next_ebr.lba_start); + } + while(next_erb_lba > 0); + + free(ebr); +} + +static const u8 TYPE_UNUSED[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +static const u8 TYPE_BIOS[16] = { 0x48,0x61,0x68,0x21,0x49,0x64,0x6F,0x6E,0x74,0x4E,0x65,0x65,0x64,0x45,0x46,0x49 }; +static const u8 TYPE_LINUX_MS_BASIC_DATA[16] = { 0xA2,0xA0,0xD0,0xEB,0xE5,0xB9,0x33,0x44,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7 }; + +int PartitionHandle::CheckGPT(u8 PartNum) +{ + GPT_HEADER *gpt_header = (GPT_HEADER *) malloc(MAX_BYTES_PER_SECTOR); + if(!gpt_header) return -1; + + // Read and validate the extended boot record + if (!interface->readSectors(1, 1, gpt_header)) + { + free(gpt_header); + return -1; + } + + if(strncmp(gpt_header->magic, "EFI PART", 8) != 0) + { + free(gpt_header); + return -1; + } + + gpt_header->part_table_lba = le64(gpt_header->part_table_lba); + gpt_header->part_entries = le32(gpt_header->part_entries); + gpt_header->part_entry_size = le32(gpt_header->part_entry_size); + gpt_header->part_entry_checksum = le32(gpt_header->part_entry_checksum); + + u8 * sector_buf = new u8[MAX_BYTES_PER_SECTOR]; + + u64 next_lba = gpt_header->part_table_lba; + + for(u32 i = 0; i < gpt_header->part_entries; ++i) + { + if (!interface->readSectors(next_lba, 1, sector_buf)) + break; + + for(u32 n = 0; n < BYTES_PER_SECTOR/gpt_header->part_entry_size; ++n, ++i) + { + GUID_PART_ENTRY * part_entry = (GUID_PART_ENTRY *) (sector_buf+gpt_header->part_entry_size*n); + + if(memcmp(part_entry->part_type_guid, TYPE_UNUSED, 16) == 0) + continue; + + if(IsExisting(le64(part_entry->part_first_lba))) + continue; + + bool bootable = (memcmp(part_entry->part_type_guid, TYPE_BIOS, 16) == 0); + + AddPartition("GUID-Entry", le64(part_entry->part_first_lba), le64(part_entry->part_last_lba), bootable, PARTITION_TYPE_GPT, i, GPT); + } + + next_lba++; + } + + delete [] sector_buf; + free(gpt_header); + + return 0; +} + +void PartitionHandle::AddPartition(const char * name, u64 lba_start, u64 sec_count, bool bootable, u8 part_type, u8 part_num, u8 part_TableType) +{ + char *buffer = (char *) malloc(MAX_BYTES_PER_SECTOR); + + if (!interface->readSectors(lba_start, 1, buffer)) + { + free(buffer); + return; + } + + wbfs_head_t *head = (wbfs_head_t *) buffer; + + if (head->magic == wbfs_htonl(WBFS_MAGIC)) + { + name = "WBFS"; + part_type = 0xBF; //Override partition type on WBFS + //! correct sector size in physical sectors (512 bytes per sector) + sec_count = (u64) head->n_hd_sec * (u64) (1 << head->hd_sec_sz_s) / (u64) BYTES_PER_SECTOR; + + } + else if(*((u16 *) (buffer + 0x1FE)) == 0x55AA) + { + //! Partition type can be missleading the correct partition format. Stupid lazy ass Partition Editors. + if((memcmp(buffer + 0x36, "FAT", 3) == 0 || memcmp(buffer + 0x52, "FAT", 3) == 0) && + strncmp(PartFromType(part_type), "FAT", 3) != 0) + { + name = "FAT32"; + part_type = 0x0c; + } + if (memcmp(buffer + 0x03, "NTFS", 4) == 0) + { + name = "NTFS"; + part_type = 0x07; + } + } + + PartitionFS PartitionEntrie; + PartitionEntrie.FSName = name; + PartitionEntrie.LBA_Start = lba_start; + PartitionEntrie.SecCount = sec_count; + PartitionEntrie.Bootable = bootable; + PartitionEntrie.PartitionType = part_type; + PartitionEntrie.PartitionNum = part_num; + PartitionEntrie.PartitionTableType = part_TableType; + + PartitionList.push_back(PartitionEntrie); + + free(buffer); +} diff --git a/source/Controls/PartitionHandle.h b/source/Controls/PartitionHandle.h new file mode 100644 index 0000000..ac6e617 --- /dev/null +++ b/source/Controls/PartitionHandle.h @@ -0,0 +1,176 @@ + /**************************************************************************** + * Copyright (C) 2013 by Cyan + * Copyright (C) 2010 by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef PARTITION_HANDLE_H +#define PARTITION_HANDLE_H + +#include +#include +#include + +#define MAX_PARTITIONS 32 /* Maximum number of partitions that can be found */ +#define MAX_MOUNTS 10 /* Maximum number of mounts available at one time */ +#define MAX_SYMLINK_DEPTH 10 /* Maximum search depth when resolving symbolic links */ + +#define MBR_SIGNATURE 0x55AA +#define EBR_SIGNATURE MBR_SIGNATURE + +#define MBR_SIGNATURE_MOD 0x55AB /* modified MBR_SIGNATURE to prevent the format message on WiiU */ + +#define PARTITION_BOOTABLE 0x80 /* Bootable (active) */ +#define PARTITION_NONBOOTABLE 0x00 /* Non-bootable */ +#define PARTITION_TYPE_GPT 0xEE /* Indicates that a GPT header is available */ + +#define GUID_SYSTEM_PARTITION 0x0000000000000001LL /* System partition (disk partitioning utilities must reserve the partition as is) */ +#define GUID_READ_ONLY_PARTITION 0x0800000000000000LL /* Read-only partition */ +#define GUID_HIDDEN_PARTITION 0x2000000000000000LL /* Hidden partition */ +#define GUID_NO_AUTOMOUNT_PARTITION 0x4000000000000000LL /* Do not automount (e.g., do not assign drive letter) */ + +#define BYTES_PER_SECTOR 512 /* Default in libogc */ +#define MAX_BYTES_PER_SECTOR 4096 /* Max bytes per sector */ + +typedef struct _PARTITION_RECORD { + u8 status; /* Partition status; see above */ + u8 chs_start[3]; /* Cylinder-head-sector address to first block of partition */ + u8 type; /* Partition type; see above */ + u8 chs_end[3]; /* Cylinder-head-sector address to last block of partition */ + u32 lba_start; /* Local block address to first sector of partition */ + u32 block_count; /* Number of blocks in partition */ +} __attribute__((__packed__)) PARTITION_RECORD; + + +typedef struct _MASTER_BOOT_RECORD { + u8 code_area[446]; /* Code area; normally empty */ + PARTITION_RECORD partitions[4]; /* 4 primary partitions */ + u16 signature; /* MBR signature; 0xAA55 */ +} __attribute__((__packed__)) MASTER_BOOT_RECORD; + +typedef struct _EXTENDED_BOOT_RECORD { + u8 code_area[446]; /* Code area; normally empty */ + PARTITION_RECORD partition; /* Primary partition */ + PARTITION_RECORD next_ebr; /* Next extended boot record in the chain */ + u8 reserved[32]; /* Normally empty */ + u16 signature; /* EBR signature; 0xAA55 */ +} __attribute__((__packed__)) EXTENDED_BOOT_RECORD; + +typedef struct _GPT_HEADER +{ + char magic[8]; /* "EFI PART" */ + u32 revision; /* For version 1.0 */ + u32 header_size; /* Header size in bytes */ + u32 checksum; /* CRC32 of header (0 to header size), with this field zeroed during calculation */ + u32 reserved; /* must be 0 */ + u64 header_lba; /* Current LBA (location of this header copy) */ + u64 backup_lba; /* Backup LBA (location of the other header copy) */ + u64 first_part_lba; /* First usable LBA for partitions (primary partition table last LBA + 1) */ + u64 last_part_lba; /* Last usable LBA (secondary partition table first LBA - 1) */ + u8 disk_guid[16]; /* Disk GUID (also referred as UUID on UNIXes) */ + u64 part_table_lba; /* Partition entries starting LBA (always 2 in primary copy) */ + u32 part_entries; /* Number of partition entries */ + u32 part_entry_size; /* Size of a partition entry (usually 128) */ + u32 part_entry_checksum; /* CRC32 of partition array */ + u8 zeros[420]; +} __attribute__((__packed__)) GPT_HEADER; + +typedef struct _GUID_PART_ENTRY +{ + u8 part_type_guid[16]; /* Partition type GUID */ + u8 uniq_part_guid[16]; /* Unique partition GUID */ + u64 part_first_lba; /* First LBA (little-endian) */ + u64 part_last_lba; /* Last LBA (inclusive, usually odd) */ + u64 attribute_flags; /* GUID Attribute flags (e.g. bit 60 denotes read-only) */ + char partition_name[72]; /* Partition name (36 UTF-16LE code units) */ +} __attribute__((__packed__)) GUID_PART_ENTRY; + +typedef struct _PartitionFS +{ + const char * FSName; + u64 LBA_Start; + u64 SecCount; + bool Bootable; + u8 PartitionType; + u8 PartitionNum; + u8 PartitionTableType; +} __attribute__((__packed__)) PartitionFS; + +enum { MBR, EBR, GPT, TABLE_TYPE_UNKNOWN }; + +class PartitionHandle +{ + public: + //! Constructor reads the MBR and all EBRs and lists up the Partitions + PartitionHandle(const DISC_INTERFACE *discio); + //! Destructor unmounts drives + ~PartitionHandle(); + //! Is Drive inserted + bool IsInserted() { if(!interface) return false; else return interface->isInserted(); }; + //! Is the partition Mounted + bool IsMounted(int pos); + //! Mount a specific Partition + bool Mount(int pos, const char * name, bool forceFAT = false); + //! UnMount a specific Partition + void UnMount(int pos); + //! UnMount all Partition + void UnMountAll() { for(u32 i = 0; i < PartitionList.size(); ++i) UnMount(i); }; + //! Get the Mountname + const char * MountName(int pos) { if(pos < 0 || pos >= (int) MountNameList.size() || !MountNameList[pos].size()) return ""; else return MountNameList[pos].c_str(); }; + //! Get the Name of the FileSystem e.g. "FAT32" + const char * GetFSName(int pos) { if(valid(pos)) return PartitionList[pos].FSName; else return ""; }; + //! Get the LBA where the partition is located + u32 GetLBAStart(int pos) { if(valid(pos)) return PartitionList[pos].LBA_Start; else return 0; }; + //! Get the partition size in sectors of this partition + u32 GetSecCount(int pos) { if(valid(pos)) return PartitionList[pos].SecCount; else return 0; }; + //! Get the cluster size of the FAT partition in bytes + u32 GetPartitionClusterSize(u32 lba_start); + //! Check if the partition is Active or NonBootable + bool IsActive(int pos) { if(valid(pos)) return PartitionList[pos].Bootable; else return false; }; + //! Get the partition type + int GetPartitionType(int pos) { if(valid(pos)) return PartitionList[pos].PartitionType; else return -1; }; + //! Get the entrie number in MBR of this partition + int GetPartitionNum(int pos) { if(valid(pos)) return PartitionList[pos].PartitionNum; else return -1; }; + //! Get the Partition Table type of this partition + int GetPartitionTableType(int pos) { if(valid(pos)) return PartitionList[pos].PartitionTableType; else return -1; }; + //! Get the count of found partitions + int GetPartitionCount() const { return PartitionList.size(); }; + //! Get the partition size in bytes + u64 GetSize(int pos) { if(valid(pos)) return (u64) PartitionList[pos].SecCount*BYTES_PER_SECTOR; else return 0; }; + //! Get the whole partition record struct + PartitionFS * GetPartitionRecord(int pos) { if(valid(pos)) return &PartitionList[pos]; else return NULL; }; + //! Get the disc interface of this handle + const DISC_INTERFACE * GetDiscInterface() { return interface; }; + protected: + bool valid(int pos) { return (pos >= 0 && pos < (int) PartitionList.size()); } + void AddPartition(const char * name, u64 lba_start, u64 sec_count, bool bootable, u8 part_type, u8 part_num, u8 part_TableType); + bool IsExisting(u64 lba); + int FindPartitions(); + void CheckEBR(u8 PartNum, sec_t ebr_lba); + int CheckGPT(u8 PartNum); + + const DISC_INTERFACE *interface; + std::vector PartitionList; + std::vector MountNameList; +}; + +#endif diff --git a/source/Controls/WiiPointer.cpp b/source/Controls/WiiPointer.cpp new file mode 100755 index 0000000..525fb18 --- /dev/null +++ b/source/Controls/WiiPointer.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** + * Copyright (C) 2011 Dimok + * + * 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 "WiiPointer.h" +#include "settings/CSettings.h" +#include "themes/Resources.h" +#include "utils/tools.h" +#include "video.h" +#include "input.h" + +extern bool isWiiVC; // in sys.cpp + +Mtx44 WiiPointer::projection; + +WiiPointer::WiiPointer(const char *pntrImg) + : posX(screenwidth/2), posY(screenheight/2), + angle(0.0f), lastActivity(301) +{ + pointerImg = Resources::GetImageData(pntrImg); + + //! create projection matrix + guOrtho(projection, Settings.AdjustOverscanY, screenheight - 1 - Settings.AdjustOverscanY, + Settings.AdjustOverscanX, screenwidth - 1 - Settings.AdjustOverscanX, 0, 10000); +} + +WiiPointer::~WiiPointer() +{ + delete pointerImg; +} + +void WiiPointer::SetImage(const char *pntrImg) +{ + GuiImageData * newPointer = Resources::GetImageData(pntrImg); + if(!newPointer) + return; + + // let's save us the work with mutex here + GuiImageData * temp2 = pointerImg; + pointerImg = newPointer; + delete temp2; +} + +void WiiPointer::Draw(GuiTrigger *t) +{ + if(t && pointerImg) + { + if(t->wpad.ir.valid) + { + lastActivity = 0; + posX = t->wpad.ir.x; + posY = t->wpad.ir.y; + angle = t->wpad.ir.angle; + } + else + { + angle = 0.0f; + + // dynamic deadzone value required for WiiU gamepad when using Virtual Console Wii channels. Fixes diagonal sticks. + // dirty fix. could be in input.h ? + u8 deadzone = isWiiVC ? 20 : PADCAL; + + // GC PAD + // x-axis + if(t->pad.stickX < -deadzone) + { + posX += (t->pad.stickX + deadzone) * Settings.PointerSpeed; + lastActivity = 0; + } + else if(t->pad.stickX > deadzone) + { + posX += (t->pad.stickX - deadzone) * Settings.PointerSpeed; + lastActivity = 0; + } + // y-axis + if(t->pad.stickY < -deadzone) + { + posY -= (t->pad.stickY + deadzone) * Settings.PointerSpeed; + lastActivity = 0; + } + else if(t->pad.stickY > deadzone) + { + posY -= (t->pad.stickY - deadzone) * Settings.PointerSpeed; + lastActivity = 0; + } + + int wpadX = t->WPAD_Stick(0, 0); + int wpadY = t->WPAD_Stick(0, 1); + + // Wii Extensions + // x-axis + if(wpadX < -PADCAL) + { + posX += (wpadX + PADCAL) * Settings.PointerSpeed; + lastActivity = 0; + } + else if(wpadX > PADCAL) + { + posX += (wpadX - PADCAL) * Settings.PointerSpeed; + lastActivity = 0; + } + // y-axis + if(wpadY < -PADCAL) + { + posY -= (wpadY + PADCAL) * Settings.PointerSpeed; + lastActivity = 0; + } + else if(wpadY > PADCAL) + { + posY -= (wpadY - PADCAL) * Settings.PointerSpeed; + lastActivity = 0; + } + + if(t->pad.btns_h || t->wpad.btns_h) + lastActivity = 0; + + posX = LIMIT(posX, -50.0f, screenwidth+50.0f); + posY = LIMIT(posY, -50.0f, screenheight+50.0f); + + if(lastActivity < 180) { // (3s on 60Hz and 3.6s on 50Hz) + t->wpad.ir.valid = 1; + t->wpad.ir.x = posX; + t->wpad.ir.y = posY; + } + } + + if(t->wpad.ir.valid) + { + GXTexObj texObj; + GX_InitTexObj(&texObj, pointerImg->GetImage(), pointerImg->GetWidth(), pointerImg->GetHeight(), GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); + GX_LoadTexObj(&texObj, GX_TEXMAP0); + + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_InvalidateTexAll(); + + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + Mtx mv; + guMtxIdentity(mv); + guMtxRotDeg (mv, 'z', angle); + guMtxTransApply(mv, mv, posX, posY, 9900.f); + guMtxConcat(FSModelView2D, mv, mv); + + GX_LoadProjectionMtx(projection, GX_ORTHOGRAPHIC); + GX_LoadPosMtxImm(mv, GX_PNMTX0); + + // pointer is pointing to center of the texture + f32 width = 0.5f * pointerImg->GetWidth(); + f32 height = 0.5f * pointerImg->GetHeight(); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position3f32(-width, -height, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); + GX_TexCoord2f32(0, 0); + + GX_Position3f32(width, -height, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); + GX_TexCoord2f32(1, 0); + + GX_Position3f32(width, height, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); + GX_TexCoord2f32(1, 1); + + GX_Position3f32(-width, height, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); + GX_TexCoord2f32(0, 1); + + GX_End(); + } + } + + ++lastActivity; +} diff --git a/source/Controls/WiiPointer.h b/source/Controls/WiiPointer.h new file mode 100755 index 0000000..6382fbf --- /dev/null +++ b/source/Controls/WiiPointer.h @@ -0,0 +1,39 @@ +/**************************************************************************** + * Copyright (C) 2011 Dimok + * + * 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 WIIPOINTER_H_ +#define WIIPOINTER_H_ + +#include "GUI/gui.h" +#include "utils/timer.h" + +class WiiPointer +{ +public: + WiiPointer(const char *pntrImg); + virtual ~WiiPointer(); + void SetImage(const char *pntrImg); + void SetPosition(float x, float y, float a) {posX = x; posY = y; angle = a;} + void Draw(GuiTrigger *t); + u32 getLastActivCounter(void) { return lastActivity; } +private: + float posX, posY, angle; + u32 lastActivity; + GuiImageData * pointerImg; + static Mtx44 projection; +}; + +#endif /* WIIPOINTER_H_ */ diff --git a/source/FileOperations/DirList.cpp b/source/FileOperations/DirList.cpp new file mode 100644 index 0000000..2b6bdbb --- /dev/null +++ b/source/FileOperations/DirList.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * DirList Class + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#define MAXPATHLEN 1024 + +#include "utils/StringTools.h" +#include "DirList.h" + +DirList::DirList(const char * path, const char *filter, u32 flags) +{ + this->LoadPath(path, filter, flags); + this->SortList(); +} + +DirList::~DirList() +{ + ClearList(); +} + +bool DirList::LoadPath(const char * folder, const char *filter, u32 flags) +{ + if(!folder) return false; + + std::string folderpath(folder); + + return LoadPath(folderpath, filter, flags); +} + +bool DirList::LoadPath(std::string &folderpath, const char *filter, u32 flags) +{ + if(folderpath.size() < 3) + return false; + + struct dirent *dirent = NULL; + DIR *dir = NULL; + + if(folderpath[folderpath.size()-1] == '/') + folderpath.erase(folderpath.size()-1); + + bool isRoot = (folderpath.find('/') == std::string::npos); + if(isRoot) + folderpath += '/'; + + dir = opendir(folderpath.c_str()); + if (dir == NULL) + return false; + + char * filename = new (std::nothrow) char[MAXPATHLEN]; + struct stat *st = new (std::nothrow) struct stat; + if(!filename || !st) + { + delete [] filename; + delete st; + closedir(dir); + return false; + } + + while ((dirent = readdir(dir)) != 0) + { + if(!dirent->d_name) + continue; + + snprintf(filename, MAXPATHLEN, "%s/%s", folderpath.c_str(), dirent->d_name); + + if(stat(filename, st) != 0) + continue; + + snprintf(filename, MAXPATHLEN, dirent->d_name); + + if(st->st_mode & S_IFDIR) + { + if(strcmp(filename,".") == 0 || strcmp(filename,"..") == 0) + continue; + + if(flags & CheckSubfolders) + { + int length = folderpath.size(); + if(!isRoot) folderpath += '/'; + folderpath += filename; + LoadPath(folderpath, filter, flags); + folderpath.erase(length); + } + + if(!(flags & Dirs)) + continue; + } + else + { + if(!(flags & Files)) + continue; + } + + if(filter) + { + char * fileext = strrchr(filename, '.'); + if(!fileext) + continue; + + if(strtokcmp(fileext, filter, ",") == 0) + AddEntrie(folderpath.c_str(), filename, st->st_size, (st->st_mode & S_IFDIR) ? true : false); + } + else + { + AddEntrie(folderpath.c_str(), filename, st->st_size, (st->st_mode & S_IFDIR) ? true : false); + } + } + closedir(dir); + delete [] filename; + delete st; + + return true; +} + +void DirList::AddEntrie(const char * folderpath, const char * filename, u64 filesize, bool isDir) +{ + if(!folderpath || !filename) + return; + + int pos = FileInfo.size(); + + FileInfo.resize(pos+1); + + FileInfo[pos].FilePath = new (std::nothrow) char[strlen(folderpath)+strlen(filename)+2]; + if(FileInfo[pos].FilePath) + sprintf(FileInfo[pos].FilePath, "%s/%s", folderpath, filename); + FileInfo[pos].FileSize = filesize; + FileInfo[pos].isDir = isDir; +} + +void DirList::ClearList() +{ + for(u32 i = 0; i < FileInfo.size(); ++i) + { + if(FileInfo[i].FilePath) + delete [] FileInfo[i].FilePath; + } + + FileInfo.clear(); + std::vector().swap(FileInfo); +} + +const char * DirList::GetFilename(int ind) +{ + if (!valid(ind)) + return NULL; + + return FullpathToFilename(FileInfo[ind].FilePath); +} + +static bool SortCallback(const FileInfos & f1, const FileInfos & f2) +{ + if(f1.isDir && !(f2.isDir)) return true; + if(!(f1.isDir) && f2.isDir) return false; + + if(f1.FilePath && !f2.FilePath) return true; + if(!f1.FilePath) return false; + + if(strcasecmp(f1.FilePath, f2.FilePath) > 0) + return false; + + return true; +} + +void DirList::SortList() +{ + if(FileInfo.size() > 1) + std::sort(FileInfo.begin(), FileInfo.end(), SortCallback); +} + +void DirList::SortList(bool (*SortFunc)(const FileInfos &a, const FileInfos &b)) +{ + if(FileInfo.size() > 1) + std::sort(FileInfo.begin(), FileInfo.end(), SortFunc); +} + +int DirList::GetFileIndex(const char *filename) +{ + if(!filename) + return -1; + + for (u32 i = 0; i < FileInfo.size(); ++i) + { + if (strcasecmp(GetFilename(i), filename) == 0) + return i; + } + + return -1; +} diff --git a/source/FileOperations/DirList.h b/source/FileOperations/DirList.h new file mode 100644 index 0000000..caece41 --- /dev/null +++ b/source/FileOperations/DirList.h @@ -0,0 +1,97 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * DirList Class + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef ___DIRLIST_H_ +#define ___DIRLIST_H_ + +#include +#include +#include + +typedef struct +{ + char * FilePath; + u64 FileSize; + bool isDir; +} FileInfos; + +class DirList +{ + public: + //!Constructor + DirList() {} + //!Overload + //!\param path Path from where to load the filelist of all files + //!\param filter A fileext that needs to be filtered + //!\param flags search/filter flags from the enum + DirList(const char * path, const char *filter = NULL, u32 flags = Files | Dirs); + //!Destructor + ~DirList(); + //! Load all the files from a directory + bool LoadPath(const char * path, const char *filter = NULL, u32 flags = Files | Dirs); + bool LoadPath(std::string &path, const char *filter = NULL, u32 flags = Files | Dirs); + //! Get a filename of the list + //!\param list index + const char * GetFilename(int index); + //! Get the a filepath of the list + //!\param list index + const char * GetFilepath(int index) { if(!valid(index)) return NULL; return FileInfo[index].FilePath; } + //! Get the a filesize of the list + //!\param list index + u64 GetFilesize(int index) { if(!valid(index)) return 0; return FileInfo[index].FileSize; } + //! Is index a dir or a file + //!\param list index + bool IsDir(int index) { if(!valid(index)) return 0; return FileInfo[index].isDir; } + //! Erase an entry of the list + //!\param list index + void RemoveEntrie(int index) { if(!valid(index)) return; FileInfo.erase(FileInfo.begin()+index); } + //! Get the filecount of the whole list + int GetFilecount() { return FileInfo.size(); } + //! Sort list by filepath + void SortList(); + //! Custom sort command for custom sort functions definitions + void SortList(bool (*SortFunc)(const FileInfos &a, const FileInfos &b)); + //! Get the index of the specified filename + int GetFileIndex(const char *filename); + //! Enum for search/filter flags + enum + { + Files = 0x01, + Dirs = 0x02, + CheckSubfolders = 0x08 + }; + protected: + //!Add a list entrie + void AddEntrie(const char * folderpath, const char * filename, u64 filesize, bool isDir); + //! Clear the list + void ClearList(); + //! Check if valid pos is requested + inline bool valid(int pos) { return (pos >= 0 && pos < (int) FileInfo.size()); } + + std::vector FileInfo; +}; + +#endif diff --git a/source/FileOperations/File.cpp b/source/FileOperations/File.cpp new file mode 100644 index 0000000..75659b8 --- /dev/null +++ b/source/FileOperations/File.cpp @@ -0,0 +1,142 @@ +#include +#include "File.hpp" + +CFile::CFile() +{ + file_fd = NULL; + mem_file = NULL; + filesize = 0; + Pos = 0; +} + +CFile::CFile(const char * filepath, const char * mode) +{ + file_fd = NULL; + open(filepath, mode); +} + +CFile::CFile(const u8 * mem, int size) +{ + file_fd = NULL; + open(mem, size); +} + +CFile::~CFile() +{ + close(); +} + +int CFile::open(const char * filepath, const char * mode) +{ + close(); + + file_fd = fopen(filepath, mode); + if(!file_fd) + return -1; + + fseek(file_fd, 0, SEEK_END); + filesize = ftell(file_fd); + rewind(); + + return 0; +} + +int CFile::open(const u8 * mem, int size) +{ + close(); + + mem_file = mem; + filesize = size; + + return 0; +} + +void CFile::close() +{ + if(file_fd) + fclose(file_fd); + + file_fd = NULL; + mem_file = NULL; + filesize = 0; + Pos = 0; +} + +int CFile::read(u8 * ptr, size_t size) +{ + if(file_fd) + { + int ret = fread(ptr, 1, size, file_fd); + if(ret > 0) + Pos += ret; + return ret; + } + + int readsize = size; + + if(readsize > (long int) filesize-Pos) + readsize = filesize-Pos; + + if(readsize <= 0) + return readsize; + + if(mem_file != NULL) + { + memcpy(ptr, mem_file+Pos, readsize); + Pos += readsize; + return readsize; + } + + return -1; +} + +int CFile::write(const u8 * ptr, size_t size) +{ + if(file_fd) + { + int ret = fwrite(ptr, 1, size, file_fd); + if(ret > 0) + Pos += ret; + return ret; + } + + return -1; +} + +int CFile::seek(long int offset, int origin) +{ + int ret = 0; + + if(origin == SEEK_SET) + { + Pos = offset; + } + else if(origin == SEEK_CUR) + { + Pos += offset; + } + else if(origin == SEEK_END) + { + Pos = filesize+offset; + } + if(Pos < 0) + { + Pos = 0; + return -1; + } + + if(file_fd) + ret = fseek(file_fd, Pos, SEEK_SET); + + if(mem_file != NULL) + { + if(Pos > (long int) filesize) + { + Pos = filesize; + return -1; + } + } + + return ret; +} + diff --git a/source/FileOperations/File.hpp b/source/FileOperations/File.hpp new file mode 100644 index 0000000..053d34c --- /dev/null +++ b/source/FileOperations/File.hpp @@ -0,0 +1,30 @@ +#ifndef FILE_HPP_ +#define FILE_HPP_ + +#include +#include + +class CFile +{ + public: + CFile(); + CFile(const char * filepath, const char * mode); + CFile(const u8 * memory, int memsize); + ~CFile(); + int open(const char * filepath, const char * mode); + int open(const u8 * memory, int memsize); + void close(); + int read(u8 * ptr, size_t size); + int write(const u8 * ptr, size_t size); + int seek(long int offset, int origin); + long int tell() { return Pos; }; + long int size() { return filesize; }; + void rewind() { seek(0, SEEK_SET); }; + protected: + FILE * file_fd; + const u8 * mem_file; + u64 filesize; + long int Pos; +}; + +#endif diff --git a/source/FileOperations/fileops.cpp b/source/FileOperations/fileops.cpp new file mode 100644 index 0000000..4e23f9f --- /dev/null +++ b/source/FileOperations/fileops.cpp @@ -0,0 +1,603 @@ + /*************************************************************************** + * Copyright (C) 2009 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * fileops.cpp + * File operations for the WiiXplorer + * Handling all the needed file operations + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "prompts/ProgressWindow.h" +#include "language/gettext.h" +#include "DirList.h" +#include "fileops.h" +#include "gecko.h" + +#define BLOCKSIZE 70*1024 //70KB +#define VectorResize(List) if(List.capacity()-List.size() == 0) List.reserve(List.size()+100) + + +static bool actioncanceled = false; + +/**************************************************************************** + * CheckFile + * + * Check if file is existing + ***************************************************************************/ +extern "C" bool CheckFile(const char * filepath) +{ + if(!filepath) + return false; + + struct stat filestat; + + char dirnoslash[strlen(filepath)+2]; + snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath); + + while(dirnoslash[strlen(dirnoslash)-1] == '/') + dirnoslash[strlen(dirnoslash)-1] = '\0'; + + char * notRoot = strrchr(dirnoslash, '/'); + if(!notRoot) + { + strcat(dirnoslash, "/"); + } + + if (stat(dirnoslash, &filestat) == 0) + return true; + + return false; +} + +/**************************************************************************** + * FileSize + * + * Get filesize in bytes. u64 for files bigger than 4GB + ***************************************************************************/ +extern "C" u64 FileSize(const char * filepath) +{ + struct stat filestat; + + if (stat(filepath, &filestat) != 0) + return 0; + + return filestat.st_size; +} + +/**************************************************************************** + * LoadFileToMem + * + * Load up the file into a block of memory + ***************************************************************************/ +extern "C" int LoadFileToMem(const char *filepath, u8 **inbuffer, u32 *size) +{ + int ret = -1; + u64 filesize = FileSize(filepath); + char * filename = strrchr(filepath, '/'); + if(filename) + filename++; + + *inbuffer = NULL; + *size = 0; + + FILE *file = fopen(filepath, "rb"); + + if (file == NULL) + return -1; + + u8 *buffer = (u8 *) malloc(filesize); + if (buffer == NULL) + { + fclose(file); + return -2; + } + + u64 done = 0; + u32 blocksize = BLOCKSIZE; + + do + { + if(actioncanceled) + { + free(buffer); + fclose(file); + return PROGRESS_CANCELED; + } + + if(blocksize > filesize-done) + blocksize = filesize-done; + + ret = fread(buffer+done, 1, blocksize, file); + if(ret < 0) + { + free(buffer); + fclose(file); + return -3; + } + else if(ret == 0) + { + //we are done + break; + } + + done += ret; + + } + while(done < filesize); + + fclose(file); + + if (done != filesize) + { + free(buffer); + return -3; + } + + *inbuffer = buffer; + *size = filesize; + + return 1; +} + +/**************************************************************************** + * LoadFileToMemWithProgress + * + * Load up the file into a block of memory, while showing a progress dialog + ***************************************************************************/ +extern "C" int LoadFileToMemWithProgress(const char *progressText, const char *filepath, u8 **inbuffer, u32 *size) +{ + + int ret = LoadFileToMem(filepath, inbuffer, size); + + return ret; +} + +/**************************************************************************** + * CreateSubfolder + * + * Create recursive all subfolders to the given path + ***************************************************************************/ +extern "C" bool CreateSubfolder(const char * fullpath) +{ + if(!fullpath) + return false; + + bool result = false; + + char dirnoslash[strlen(fullpath)+1]; + strcpy(dirnoslash, fullpath); + + int pos = strlen(dirnoslash)-1; + while(dirnoslash[pos] == '/') + { + dirnoslash[pos] = '\0'; + pos--; + } + + if(CheckFile(dirnoslash)) + { + return true; + } + else + { + char parentpath[strlen(dirnoslash)+2]; + strcpy(parentpath, dirnoslash); + char * ptr = strrchr(parentpath, '/'); + + if(!ptr) + { + //!Device root directory (must be with '/') + strcat(parentpath, "/"); + struct stat filestat; + if (stat(parentpath, &filestat) == 0) + return true; + + return false; + } + + ptr++; + ptr[0] = '\0'; + + result = CreateSubfolder(parentpath); + } + + if(!result) + return false; + + if (mkdir(dirnoslash, 0777) == -1) + { + return false; + } + + return true; +} + +/**************************************************************************** + * CompareDevices + * + * Compare if its the devices are equal + ***************************************************************************/ +static bool CompareDevices(const char *src, const char *dest) +{ + if(!src || !dest) + return false; + + char *device1 = strchr(src, ':'); + char *device2 = strchr(dest, ':'); + + if(!device1 || !device2) + return false; + + int position1 = device1-src+1; + int position2 = device2-dest+1; + + char temp1[50]; + char temp2[50]; + + snprintf(temp1, position1, "%s", src); + snprintf(temp2, position2, "%s", dest); + + if(strcasecmp(temp1, temp2) == 0) + return true; + + return false; +} + +/**************************************************************************** + * CopyFile + * + * Copy the file from source filepath to destination filepath + ***************************************************************************/ +extern "C" int CopyFile(const char * src, const char * dest) +{ + int read = 1; + int wrote = 1; + + char * filename = strrchr(src, '/'); + if(filename) + filename++; + else + return -1; + + u64 sizesrc = FileSize(src); + + FILE * source = fopen(src, "rb"); + + if(!source) + return -2; + + u32 blksize = BLOCKSIZE; + + u8 * buffer = (u8 *) malloc(blksize); + + if(buffer == NULL){ + //no memory + fclose(source); + return -1; + } + + FILE * destination = fopen(dest, "wb"); + + if(destination == NULL) + { + free(buffer); + fclose(source); + return -3; + } + + u64 done = 0; + + do + { + if(ProgressCanceled()) + { + fclose(source); + fclose(destination); + free(buffer); + RemoveFile((char *) dest); + return PROGRESS_CANCELED; + } + + ShowProgress(done, sizesrc); + + if(blksize > sizesrc - done) + blksize = sizesrc - done; + + //Display progress + read = fread(buffer, 1, blksize, source); + if(read < 0) + { + fclose(source); + fclose(destination); + free(buffer); + RemoveFile((char *) dest); + return -3; + } + + wrote = fwrite(buffer, 1, read, destination); + if(wrote < 0) + { + fclose(source); + fclose(destination); + free(buffer); + RemoveFile((char *) dest); + return -3; + } + + done += wrote; + } + while (read > 0); + + ProgressStop(); + + free(buffer); + fclose(source); + fclose(destination); + + if(sizesrc != done) + return -4; + + return 1; +} + +/**************************************************************************** + * MoveFile + * + * Move a file from srcpath to destdir + ***************************************************************************/ +extern "C" int MoveFile(const char *srcpath, char *destdir) +{ + if(CompareDevices(srcpath, destdir)) + { + if(RenameFile(srcpath, destdir)) + return 1; + else + return -1; + } + + int res = CopyFile(srcpath, destdir); + if(res < 0) + return -1; + + if(RemoveFile(srcpath)) + return 1; + + return -1; +} + +/**************************************************************************** + * RemoveFile + * + * Delete the file from a given filepath + ***************************************************************************/ +extern "C" bool RemoveFile(const char * filepath) +{ + return (remove(filepath) == 0); +} + +/**************************************************************************** + * RenameFile + * + * Rename the file from a given srcpath to a given destpath + ***************************************************************************/ +extern "C" bool RenameFile(const char * srcpath, const char * destpath) +{ + return (rename(srcpath, destpath) == 0); +} + +/**************************************************************************** + * RemoveDirectory + ***************************************************************************/ +extern "C" bool RemoveDirectory(const char *path) +{ + std::string folderpath = path; + while(folderpath[folderpath.size()-1] == '/') + folderpath.erase(folderpath.size()-1); + + bool isRoot = (folderpath.find('/') == std::string::npos); + if(isRoot) + folderpath += '/'; + + ProgressCancelEnable(true); + StartProgress(tr("Getting file list..."), tr("Please wait"), 0, false, false); + ShowProgress(0, 1); + + //! load list not sorted, to remove in correct order + DirList dir; + dir.LoadPath(folderpath.c_str(), 0, DirList::Dirs | DirList::Files | DirList::CheckSubfolders); + + int done = 0; + int fileCount = dir.GetFilecount(); + + //! remove files first + for(int i = 0; i < fileCount; i++) + { + if(!dir.IsDir(i)) + { + ShowProgress(tr("Deleting files..."), dir.GetFilename(i), 0, done, fileCount, false, false); + RemoveFile(dir.GetFilepath(i)); + done++; + } + } + + //! now remove all folders + for(int i = 0; i < fileCount; i++) + { + if(dir.IsDir(i)) + { + ShowProgress(tr("Deleting directories..."), dir.GetFilename(i), 0, done, fileCount, false, false); + RemoveFile(dir.GetFilepath(i)); + done++; + gprintf("%s\n", dir.GetFilepath(i)); + } + } + + ProgressStop(); + ProgressCancelEnable(false); + + return (remove(folderpath.c_str()) == 0); +} + +/**************************************************************************** + * RemoveDirectory + ***************************************************************************/ +extern "C" int CopyDirectory(const char *path, const char *dst) +{ + if(!path || !dst) + return -1; + + ProgressCancelEnable(true); + StartProgress(tr("Getting file list..."), tr("Please wait"), 0, true, true); + ShowProgress(0, 1); + + //! load list not sorted as there is no need to + DirList dir; + dir.LoadPath(path, 0, DirList::Dirs | DirList::Files | DirList::CheckSubfolders); + + int result = 0; + int fileCount = dir.GetFilecount(); + int pathlen = strlen(path); + + // we are done + if(fileCount == 0) { + ProgressStop(); + ProgressCancelEnable(false); + return 0; + } + + u64 totalDone = 0; + u64 totalSize = 0; + + for(int i = 0; i < fileCount; i++) + totalSize += dir.GetFilesize(i); + + char filepath[1024]; + + u32 blksize = BLOCKSIZE; + u8 * buffer = (u8 *) malloc(blksize); + if(buffer == NULL){ + ProgressStop(); + ProgressCancelEnable(false); + return -2; + } + + for(int i = 0; i < fileCount; i++) + { + const char *srcPath = dir.GetFilepath(i); + if(!srcPath) + continue; + + const char *filename = dir.GetFilename(i); + + snprintf(filepath, sizeof(filepath), "%s/%s", dst, srcPath+pathlen); + char *ptr = strrchr(filepath, '/'); + if(ptr) *ptr = 0; + //! create path for the file + CreateSubfolder(filepath); + + snprintf(filepath, sizeof(filepath), "%s/%s", dst, srcPath+pathlen); + + // Start copying file + FILE * source = fopen(srcPath, "rb"); + if(!source) + continue; + + FILE * destination = fopen(filepath, "wb"); + if(destination == NULL) + { + fclose(source); + continue; + } + + ShowProgress(tr("Copying files..."), filename, 0, totalDone, totalSize, true, true); + + blksize = BLOCKSIZE; + u64 done = 0; + u64 filesize = dir.GetFilesize(i); + + while(done < filesize) + { + if(ProgressCanceled()) + { + fclose(source); + fclose(destination); + free(buffer); + ProgressStop(); + ProgressCancelEnable(false); + return PROGRESS_CANCELED; + } + + //Display progress + ShowProgress(totalDone, totalSize); + + if(blksize > filesize - done) + blksize = filesize - done; + + if(fread(buffer, 1, blksize, source) != blksize) + { + result = -5; + break; + } + + if(fwrite(buffer, 1, blksize, destination) != blksize) + { + result = -5; + break; + } + + done += blksize; + totalDone += blksize; + } + + fclose(source); + fclose(destination); + } + + free(buffer); + ProgressStop(); + ProgressCancelEnable(false); + + return result; +} + +u64 GetDirectorySize(const char *path) +{ + DirList dir(path, 0, DirList::Files | DirList::CheckSubfolders); + + int fileCount = dir.GetFilecount(); + u64 totalSize = 0; + + for(int i = 0; i < fileCount; i++) + totalSize += dir.GetFilesize(i); + + return totalSize; +} diff --git a/source/FileOperations/fileops.h b/source/FileOperations/fileops.h new file mode 100644 index 0000000..95105ea --- /dev/null +++ b/source/FileOperations/fileops.h @@ -0,0 +1,54 @@ + /*************************************************************************** + * Copyright (C) 2009 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * fileops.h + * File operations for the WiiXplorer + * Handling all the needed file operations + ***************************************************************************/ +#ifndef _FILEOPS_H_ +#define _FILEOPS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +bool CreateSubfolder(const char * fullpath); +bool CheckFile(const char * filepath); +u64 FileSize(const char * filepath); +u64 GetDirectorySize(const char *path); +int LoadFileToMem(const char * filepath, u8 **buffer, u32 *size); +int LoadFileToMemWithProgress(const char *progressText, const char *filePath, u8 **buffer, u32 *size); +int CopyFile(const char * src, const char * dest); +int MoveFile(const char *srcpath, char *destdir); +int CopyDirectory(const char *path, const char *dst); +bool RenameFile(const char * srcpath, const char * destpath); +bool RemoveFile(const char * filepath); +bool RemoveDirectory(const char *path); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/FreeTypeGX.cpp b/source/FreeTypeGX.cpp new file mode 100644 index 0000000..144dc6b --- /dev/null +++ b/source/FreeTypeGX.cpp @@ -0,0 +1,608 @@ +/* + * FreeTypeGX is a wrapper class for libFreeType which renders a compiled + * FreeType parsable font into a GX texture for Wii homebrew development. + * Copyright (C) 2008 Armin Tamzarian + * Modified by Dimok, 2010 + * + * This file is part of FreeTypeGX. + * + * FreeTypeGX 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 3 of the License, or + * (at your option) any later version. + * + * FreeTypeGX 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 FreeTypeGX. If not, see . + */ + +#include "FreeTypeGX.h" +#include "memory/mem2.h" + +using namespace std; + +#define ALIGN8(x) (((x) + 7) & ~7) + +/** + * Convert a short char string to a wide char string. + * + * This routine converts a supplied short character string into a wide character string. + * Note that it is the user's responsibility to clear the returned buffer once it is no longer needed. + * + * @param strChar Character string to be converted. + * @return Wide character representation of supplied character string. + */ + +wchar_t* charToWideChar(const char* strChar) +{ + if (!strChar) return NULL; + + wchar_t *strWChar = new (std::nothrow) wchar_t[strlen(strChar) + 1]; + if (!strWChar) return NULL; + + int bt = mbstowcs(strWChar, strChar, strlen(strChar)); + if (bt > 0) + { + strWChar[bt] = 0; + return strWChar; + } + + wchar_t *tempDest = strWChar; + while ((*tempDest++ = *strChar++)) + ; + + return strWChar; +} + +/** + * Default constructor for the FreeTypeGX class for WiiXplorer. + */ +FreeTypeGX::FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize, bool lastFace) +{ + int faceIndex = 0; + ftPointSize = 0; + + FT_Init_FreeType(&ftLibrary); + if(lastFace) + { + FT_New_Memory_Face(ftLibrary, (FT_Byte *)fontBuffer, bufferSize, -1, &ftFace); + faceIndex = ftFace->num_faces - 1; // Use the last face + FT_Done_Face(ftFace); + ftFace = NULL; + } + FT_New_Memory_Face(ftLibrary, (FT_Byte *) fontBuffer, bufferSize, faceIndex, &ftFace); + + setVertexFormat(GX_VTXFMT1); + ftKerningEnabled = false;//FT_HAS_KERNING(ftFace); +} + +/** + * Default destructor for the FreeTypeGX class. + */ +FreeTypeGX::~FreeTypeGX() +{ + unloadFont(); + FT_Done_Face(ftFace); + FT_Done_FreeType(ftLibrary); +} + +/** + * Setup the vertex attribute formats for the glyph textures. + * + * This function sets up the vertex format for the glyph texture on the specified vertex format index. + * Note that this function should not need to be called except if the vertex formats are cleared or the specified + * vertex format index is modified. + * + * @param vertexIndex Vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file. + */ +void FreeTypeGX::setVertexFormat(uint8_t vertexInd) +{ + vertexIndex = vertexInd; + GX_SetVtxAttrFmt(vertexIndex, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); + GX_SetVtxAttrFmt(vertexIndex, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + GX_SetVtxAttrFmt(vertexIndex, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); +} + +/** + * Clears all loaded font glyph data. + * + * This routine clears all members of the font map structure and frees all allocated memory back to the system. + */ +void FreeTypeGX::unloadFont() +{ + if (this->fontData.size() == 0) return; + + map >::iterator itr; + map::iterator itr2; + + for (itr = fontData.begin(); itr != fontData.end(); itr++) + { + for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++) + MEM2_free(itr2->second.glyphDataTexture); + + itr->second.clear(); + } + + fontData.clear(); + ftgxAlign.clear(); +} + +/** + * Caches the given font glyph in the instance font texture buffer. + * + * This routine renders and stores the requested glyph's bitmap and relevant information into its own quickly addressible + * structure within an instance-specific map. + * + * @param charCode The requested glyph's character code. + * @return A pointer to the allocated font structure. + */ +ftgxCharData * FreeTypeGX::cacheGlyphData(wchar_t charCode, int16_t pixelSize) +{ + map >::iterator itr = fontData.find(pixelSize); + if (itr != fontData.end()) + { + map::iterator itr2 = itr->second.find(charCode); + if (itr2 != itr->second.end()) + { + return &itr2->second; + } + } + + FT_UInt gIndex; + uint16_t textureWidth = 0, textureHeight = 0; + + if (ftPointSize != pixelSize) + { + ftPointSize = pixelSize; + FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize); + + //!Cache ascender and decender as well + map::iterator itrAlign = ftgxAlign.find(ftPointSize); + if (itrAlign == ftgxAlign.end()) + { + ftgxAlign[ftPointSize].ascender = (int16_t) ftFace->size->metrics.ascender >> 6; + ftgxAlign[ftPointSize].descender = (int16_t) ftFace->size->metrics.descender >> 6; + ftgxAlign[ftPointSize].max = 0; + ftgxAlign[ftPointSize].min = 0; + } + } + + gIndex = FT_Get_Char_Index(ftFace, (FT_ULong) charCode); + if (gIndex != 0 && FT_Load_Glyph(ftFace, gIndex, FT_LOAD_DEFAULT | FT_LOAD_RENDER) == 0) + { + if (ftFace->glyph->format == FT_GLYPH_FORMAT_BITMAP) + { + FT_Bitmap *glyphBitmap = &ftFace->glyph->bitmap; + + textureWidth = ALIGN8(glyphBitmap->width); + textureHeight = ALIGN8(glyphBitmap->rows); + if(textureWidth == 0) + textureWidth = 8; + if(textureHeight == 0) + textureHeight = 8; + + fontData[pixelSize][charCode].renderOffsetX = (int16_t) ftFace->glyph->bitmap_left; + fontData[pixelSize][charCode].glyphAdvanceX = (uint16_t) (ftFace->glyph->advance.x >> 6); + fontData[pixelSize][charCode].glyphIndex = (uint32_t) gIndex; + fontData[pixelSize][charCode].textureWidth = (uint16_t) textureWidth; + fontData[pixelSize][charCode].textureHeight = (uint16_t) textureHeight; + fontData[pixelSize][charCode].renderOffsetY = (int16_t) ftFace->glyph->bitmap_top; + fontData[pixelSize][charCode].renderOffsetMax = (int16_t) ftFace->glyph->bitmap_top; + fontData[pixelSize][charCode].renderOffsetMin = (int16_t) glyphBitmap->rows - ftFace->glyph->bitmap_top; + fontData[pixelSize][charCode].glyphDataTexture = NULL; + + loadGlyphData(glyphBitmap, &fontData[pixelSize][charCode]); + + return &fontData[pixelSize][charCode]; + } + } + return NULL; +} + +/** + * Locates each character in this wrapper's configured font face and proccess them. + * + * This routine locates each character in the configured font face and renders the glyph's bitmap. + * Each bitmap and relevant information is loaded into its own quickly addressible structure within an instance-specific map. + */ +uint16_t FreeTypeGX::cacheGlyphDataComplete(int16_t pixelSize) +{ + uint32_t i = 0; + FT_UInt gIndex; + + FT_ULong charCode = FT_Get_First_Char(ftFace, &gIndex); + while (gIndex != 0) + { + if (cacheGlyphData(charCode, pixelSize) != NULL) ++i; + charCode = FT_Get_Next_Char(ftFace, charCode, &gIndex); + } + return (uint16_t) (i); +} + +/** + * Loads the rendered bitmap into the relevant structure's data buffer. + * + * This routine does a simple byte-wise copy of the glyph's rendered 8-bit grayscale bitmap into the structure's buffer. + * Each byte is converted from the bitmap's intensity value into the a uint32_t RGBA value. + * + * @param bmp A pointer to the most recently rendered glyph's bitmap. + * @param charData A pointer to an allocated ftgxCharData structure whose data represent that of the last rendered glyph. + */ + +void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData) +{ + int glyphSize = (charData->textureWidth * charData->textureHeight) >> 1; + + uint8_t *glyphData = (uint8_t *) MEM2_alloc(glyphSize); + memset(glyphData, 0x00, glyphSize); + + uint8_t *src = (uint8_t *)bmp->buffer; + uint8_t *dst = glyphData; + int32_t pos, x1, y1, x, y; + + for(y1 = 0; y1 < bmp->rows; y1 += 8) + { + for(x1 = 0; x1 < bmp->width; x1 += 8) + { + for(y = y1; y < (y1 + 8); y++) + { + for(x = x1; x < (x1 + 8); x += 2, dst++) + { + if(x >= bmp->width || y >= bmp->rows) + continue; + + pos = y * bmp->width + x; + *dst = (src[pos] & 0xF0); + + if(x+1 < bmp->width) + *dst |= (src[pos + 1] >> 4); + } + } + } + } + + DCFlushRange(glyphData, glyphSize); + charData->glyphDataTexture = glyphData; +} + +/** + * Determines the x offset of the rendered string. + * + * This routine calculates the x offset of the rendered string based off of a supplied positional format parameter. + * + * @param width Current pixel width of the string. + * @param format Positional format of the string. + */ +int16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format) +{ + if (format & FTGX_JUSTIFY_LEFT) + return 0; + else if (format & FTGX_JUSTIFY_CENTER) + return -(width >> 1); + else if (format & FTGX_JUSTIFY_RIGHT) return -width; + return 0; +} + +/** + * Determines the y offset of the rendered string. + * + * This routine calculates the y offset of the rendered string based off of a supplied positional format parameter. + * + * @param offset Current pixel offset data of the string. + * @param format Positional format of the string. + */ +int16_t FreeTypeGX::getStyleOffsetHeight(int16_t format, uint16_t pixelSize) +{ + map::iterator itrAlign = ftgxAlign.find(pixelSize); + if (itrAlign == ftgxAlign.end()) return 0; + + switch (format & FTGX_ALIGN_MASK) + { + case FTGX_ALIGN_TOP: + return itrAlign->second.ascender; + + case FTGX_ALIGN_MIDDLE: + default: + return (itrAlign->second.ascender + itrAlign->second.descender + 1) >> 1; + + case FTGX_ALIGN_BOTTOM: + return itrAlign->second.descender; + + case FTGX_ALIGN_BASELINE: + return 0; + + case FTGX_ALIGN_GLYPH_TOP: + return itrAlign->second.max; + + case FTGX_ALIGN_GLYPH_MIDDLE: + return (itrAlign->second.max + itrAlign->second.min + 1) >> 1; + + case FTGX_ALIGN_GLYPH_BOTTOM: + return itrAlign->second.min; + } + return 0; +} + +/** + * Processes the supplied text string and prints the results at the specified coordinates. + * + * This routine processes each character of the supplied text string, loads the relevant preprocessed bitmap buffer, + * a texture from said buffer, and loads the resultant texture into the EFB. + * + * @param x Screen X coordinate at which to output the text. + * @param y Screen Y coordinate at which to output the text. Note that this value corresponds to the text string origin and not the top or bottom of the glyphs. + * @param text NULL terminated string to output. + * @param color Optional color to apply to the text characters. If not specified default value is ftgxWhite: (GXColor){0xff, 0xff, 0xff, 0xff} + * @param textStyle Flags which specify any styling which should be applied to the rendered string. + * @return The number of characters printed. + */ + +uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color, + uint16_t textStyle, uint16_t textWidth, uint16_t widthLimit) +{ + if (!text) return 0; + + uint16_t fullTextWidth = textWidth > 0 ? textWidth : getWidth(text, pixelSize); + uint16_t x_pos = x, printed = 0; + uint16_t x_offset = 0, y_offset = 0; + GXTexObj glyphTexture; + FT_Vector pairDelta; + + if (textStyle & FTGX_JUSTIFY_MASK) + { + x_offset = getStyleOffsetWidth(fullTextWidth, textStyle); + } + if (textStyle & FTGX_ALIGN_MASK) + { + y_offset = getStyleOffsetHeight(textStyle, pixelSize); + } + + int i = 0; + + while (text[i]) + { + if (widthLimit > 0 && (x_pos - x) > widthLimit) break; + + ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize); + + if (glyphData != NULL) + { + if (ftKerningEnabled && i > 0) + { + FT_Get_Kerning(ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta); + x_pos += pairDelta.x >> 6; + } + + GX_InitTexObj(&glyphTexture, glyphData->glyphDataTexture, glyphData->textureWidth, glyphData->textureHeight, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE); + copyTextureToFramebuffer(&glyphTexture, glyphData->textureWidth, glyphData->textureHeight, x_pos + glyphData->renderOffsetX + x_offset, y - glyphData->renderOffsetY + y_offset, z, color); + + x_pos += glyphData->glyphAdvanceX; + ++printed; + } + ++i; + } + + if (textStyle & FTGX_STYLE_MASK) + { + getOffset(text, pixelSize, widthLimit); + drawTextFeature(x + x_offset, y + y_offset, z, pixelSize, fullTextWidth, &ftgxAlign[pixelSize], textStyle, + color); + } + + return printed; +} + +void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width, + ftgxDataOffset *offsetData, uint16_t format, GXColor color) +{ + uint16_t featureHeight = pixelSize >> 4 > 0 ? pixelSize >> 4 : 1; + + if (format & FTGX_STYLE_UNDERLINE) this->copyFeatureToFramebuffer(width, featureHeight, x, y + 1, z, color); + + if (format & FTGX_STYLE_STRIKE) this->copyFeatureToFramebuffer(width, featureHeight, x, y + - ((offsetData->max) >> 1), z, color); +} + +/** + * Processes the supplied string and return the width of the string in pixels. + * + * This routine processes each character of the supplied text string and calculates the width of the entire string. + * Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function. + * + * @param text NULL terminated string to calculate. + * @return The width of the text string in pixels. + */ +uint16_t FreeTypeGX::getWidth(const wchar_t *text, int16_t pixelSize) +{ + if (!text) return 0; + + uint16_t strWidth = 0; + FT_Vector pairDelta; + + int i = 0; + while (text[i]) + { + ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize); + + if (glyphData != NULL) + { + if (ftKerningEnabled && (i > 0)) + { + FT_Get_Kerning(ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex, + FT_KERNING_DEFAULT, &pairDelta); + strWidth += pairDelta.x >> 6; + } + + strWidth += glyphData->glyphAdvanceX; + } + ++i; + } + return strWidth; +} + +/** + * Single char width + */ +uint16_t FreeTypeGX::getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar) +{ + uint16_t strWidth = 0; + ftgxCharData * glyphData = cacheGlyphData(wChar, pixelSize); + + if (glyphData != NULL) + { + if (ftKerningEnabled && prevChar != 0x0000) + { + FT_Vector pairDelta; + FT_Get_Kerning(ftFace, fontData[pixelSize][prevChar].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, + &pairDelta); + strWidth += pairDelta.x >> 6; + } + strWidth += glyphData->glyphAdvanceX; + } + + return strWidth; +} + +/** + * Processes the supplied string and return the height of the string in pixels. + * + * This routine processes each character of the supplied text string and calculates the height of the entire string. + * Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function. + * + * @param text NULL terminated string to calculate. + * @return The height of the text string in pixels. + */ +uint16_t FreeTypeGX::getHeight(const wchar_t *text, int16_t pixelSize) +{ + getOffset(text, pixelSize); + + return ftgxAlign[pixelSize].max - ftgxAlign[pixelSize].min; +} + +/** + * Get the maximum offset above and minimum offset below the font origin line. + * + * This function calculates the maximum pixel height above the font origin line and the minimum + * pixel height below the font origin line and returns the values in an addressible structure. + * + * @param text NULL terminated string to calculate. + * @param offset returns the max and min values above and below the font origin line + * + */ +void FreeTypeGX::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit) +{ + if (ftgxAlign.find(pixelSize) != ftgxAlign.end()) return; + + int16_t strMax = 0, strMin = 9999; + uint16_t currWidth = 0; + + int i = 0; + + while (text[i]) + { + if (widthLimit > 0 && currWidth >= widthLimit) break; + + ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize); + + if (glyphData != NULL) + { + strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax; + strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin; + currWidth += glyphData->glyphAdvanceX; + } + + ++i; + } + + if (ftPointSize != pixelSize) + { + ftPointSize = pixelSize; + FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize); + } + + ftgxAlign[pixelSize].ascender = ftFace->size->metrics.ascender >> 6; + ftgxAlign[pixelSize].descender = ftFace->size->metrics.descender >> 6; + ftgxAlign[pixelSize].max = strMax; + ftgxAlign[pixelSize].min = strMin; +} + +/** + * Copies the supplied texture quad to the EFB. + * + * This routine uses the in-built GX quad builder functions to define the texture bounds and location on the EFB target. + * + * @param texObj A pointer to the glyph's initialized texture object. + * @param texWidth The pixel width of the texture object. + * @param texHeight The pixel height of the texture object. + * @param screenX The screen X coordinate at which to output the rendered texture. + * @param screenY The screen Y coordinate at which to output the rendered texture. + * @param color Color to apply to the texture. + */ +void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, + int16_t screenY, int16_t screenZ, GXColor color) +{ + GX_LoadTexObj(texObj, GX_TEXMAP0); + GX_InvalidateTexAll(); + + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + + GX_Begin(GX_QUADS, this->vertexIndex, 4); + GX_Position3s16(screenX, screenY, screenZ); + GX_Color4u8(color.r, color.g, color.b, color.a); + GX_TexCoord2f32(0.0f, 0.0f); + + GX_Position3s16(texWidth + screenX, screenY, screenZ); + GX_Color4u8(color.r, color.g, color.b, color.a); + GX_TexCoord2f32(1.0f, 0.0f); + + GX_Position3s16(texWidth + screenX, texHeight + screenY, screenZ); + GX_Color4u8(color.r, color.g, color.b, color.a); + GX_TexCoord2f32(1.0f, 1.0f); + + GX_Position3s16(screenX, texHeight + screenY, screenZ); + GX_Color4u8(color.r, color.g, color.b, color.a); + GX_TexCoord2f32(0.0f, 1.0f); + GX_End(); +} + +/** + * Creates a feature quad to the EFB. + * + * This function creates a simple quad for displaying underline or strikeout text styling. + * + * @param featureWidth The pixel width of the quad. + * @param featureHeight The pixel height of the quad. + * @param screenX The screen X coordinate at which to output the quad. + * @param screenY The screen Y coordinate at which to output the quad. + * @param color Color to apply to the texture. + */ +void FreeTypeGX::copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, + int16_t screenZ, GXColor color) +{ + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); + + GX_Begin(GX_QUADS, this->vertexIndex, 4); + GX_Position3s16(screenX, screenY, screenZ); + GX_Color4u8(color.r, color.g, color.b, color.a); + + GX_Position3s16(featureWidth + screenX, screenY, screenZ); + GX_Color4u8(color.r, color.g, color.b, color.a); + + GX_Position3s16(featureWidth + screenX, featureHeight + screenY, screenZ); + GX_Color4u8(color.r, color.g, color.b, color.a); + + GX_Position3s16(screenX, featureHeight + screenY, screenZ); + GX_Color4u8(color.r, color.g, color.b, color.a); + GX_End(); + + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); +} diff --git a/source/FreeTypeGX.h b/source/FreeTypeGX.h new file mode 100644 index 0000000..ffc856e --- /dev/null +++ b/source/FreeTypeGX.h @@ -0,0 +1,149 @@ +/* + * FreeTypeGX is a wrapper class for libFreeType which renders a compiled + * FreeType parsable font into a GX texture for Wii homebrew development. + * Copyright (C) 2008 Armin Tamzarian + * Modified by Dimok, 2010 + * + * This file is part of FreeTypeGX. + * + * FreeTypeGX 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 3 of the License, or + * (at your option) any later version. + * + * FreeTypeGX 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 FreeTypeGX. If not, see . + */ + +#ifndef FREETYPEGX_H_ +#define FREETYPEGX_H_ + +#include +#include +#include FT_FREETYPE_H +#include FT_BITMAP_H + +#include +#include +#include +#include + +/*! \struct ftgxCharData_ + * + * Font face character glyph relevant data structure. + */ +typedef struct ftgxCharData_ +{ + int16_t renderOffsetX; /**< Texture X axis bearing offset. */ + uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */ + uint32_t glyphIndex; /**< Charachter glyph index in the font face. */ + + uint16_t textureWidth; /**< Texture width in pixels/bytes. */ + uint16_t textureHeight; /**< Texture glyph height in pixels/bytes. */ + + int16_t renderOffsetY; /**< Texture Y axis bearing offset. */ + int16_t renderOffsetMax; /**< Texture Y axis bearing maximum value. */ + int16_t renderOffsetMin; /**< Texture Y axis bearing minimum value. */ + + uint8_t* glyphDataTexture; /**< Glyph texture bitmap data buffer. */ +} ftgxCharData; + +/*! \struct ftgxDataOffset_ + * + * Offset structure which hold both a maximum and minimum value. + */ +typedef struct ftgxDataOffset_ +{ + int16_t ascender; /**< Maximum data offset. */ + int16_t descender; /**< Minimum data offset. */ + int16_t max; /**< Maximum data offset. */ + int16_t min; /**< Minimum data offset. */ +} ftgxDataOffset; + +typedef struct ftgxCharData_ ftgxCharData; +typedef struct ftgxDataOffset_ ftgxDataOffset; + +#define _TEXT(t) L ## t /**< Unicode helper macro. */ + +#define FTGX_NULL 0x0000 +#define FTGX_JUSTIFY_LEFT 0x0001 +#define FTGX_JUSTIFY_CENTER 0x0002 +#define FTGX_JUSTIFY_RIGHT 0x0004 +#define FTGX_JUSTIFY_MASK 0x000f + +#define FTGX_ALIGN_TOP 0x0010 +#define FTGX_ALIGN_MIDDLE 0x0020 +#define FTGX_ALIGN_BOTTOM 0x0040 +#define FTGX_ALIGN_BASELINE 0x0080 +#define FTGX_ALIGN_GLYPH_TOP 0x0100 +#define FTGX_ALIGN_GLYPH_MIDDLE 0x0200 +#define FTGX_ALIGN_GLYPH_BOTTOM 0x0400 +#define FTGX_ALIGN_MASK 0x0ff0 + +#define FTGX_STYLE_UNDERLINE 0x1000 +#define FTGX_STYLE_STRIKE 0x2000 +#define FTGX_STYLE_MASK 0xf000 + +const GXColor ftgxWhite = ( GXColor ) +{ 0xff, 0xff, 0xff, 0xff}; /**< Constant color value used only to sanitize Doxygen documentation. */ + +wchar_t* charToWideChar(const char* p); + +/*! \class FreeTypeGX + * \brief Wrapper class for the libFreeType library with GX rendering. + * \author Armin Tamzarian + * \version 0.2.4 + * + * FreeTypeGX acts as a wrapper class for the libFreeType library. It supports precaching of transformed glyph data into + * a specified texture format. Rendering of the data to the EFB is accomplished through the application of high performance + * GX texture functions resulting in high throughput of string rendering. + */ +class FreeTypeGX +{ + private: + FT_Library ftLibrary; /**< FreeType FT_Library instance. */ + FT_Face ftFace; /**< FreeType reusable FT_Face typographic object. */ + int16_t ftPointSize; /**< Current set size of the rendered font. */ + bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */ + uint8_t vertexIndex; /**< Vertex format descriptor index. */ + std::map > fontData; /**< Map which holds the glyph data structures for the corresponding characters in one size. */ + std::map ftgxAlign; /**< Map which holds the ascender and decender for different sizes. */ + + int16_t getStyleOffsetWidth(uint16_t width, uint16_t format); + int16_t getStyleOffsetHeight(int16_t format, uint16_t pixelSize); + + void unloadFont(); + ftgxCharData *cacheGlyphData(wchar_t charCode, int16_t pixelSize); + uint16_t cacheGlyphDataComplete(int16_t pixelSize); + void loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData); + + void setDefaultMode(); + + void drawTextFeature(int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width, + ftgxDataOffset *offsetData, uint16_t format, GXColor color); + void copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, + int16_t screenZ, GXColor color); + void copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, + int16_t screenZ, GXColor color); + + public: + FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize, bool lastFace = false); + ~FreeTypeGX(); + + void setVertexFormat(uint8_t vertexIndex); + + uint16_t drawText(int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color = + ftgxWhite, uint16_t textStyling = FTGX_NULL, uint16_t textWidth = 0, uint16_t widthLimit = 0); + + uint16_t getWidth(const wchar_t *text, int16_t pixelSize); + uint16_t getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar = 0x0000); + uint16_t getHeight(const wchar_t *text, int16_t pixelSize); + void getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit = 0); +}; + +#endif /* FREETYPEGX_H_ */ diff --git a/source/GUI/GuiBannerGrid.cpp b/source/GUI/GuiBannerGrid.cpp new file mode 100644 index 0000000..f7d9a7d --- /dev/null +++ b/source/GUI/GuiBannerGrid.cpp @@ -0,0 +1,561 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 "GuiBannerGrid.h" +#include "themes/CTheme.h" +#include "settings/CSettings.h" +#include "settings/GameTitles.h" +#include "settings/newtitles.h" +#include "SystemMenu/SystemMenuResources.h" +#include "usbloader/GameList.h" +#include "gecko.h" + +//! some math to get the row and column from channel idx +static inline int Idx2Row(int sIdx) +{ + if(sIdx > 0) + return (sIdx / 4) % 3; + else if(sIdx < 0) + return (2 + ((sIdx + 1) / 4) % 3); + else + return 0; +} + +static inline int Idx2Column(int sIdx) +{ + if(sIdx == 0) + return 0; + + if(sIdx > 0) { + return ( (sIdx / 12) * 4 + sIdx % 4 ); + } + else + { + int column = (sIdx % 4); + if(column == 0) + column = -4; + column += ((sIdx + 1) / 12) * 4; + + return column; + } +} + +GuiBannerGrid::GuiBannerGrid(int listOffset) + : XOffset(thInt("0 - game bannergrid layout pos x")) + , YOffset(thInt("-50 - game bannergrid layout pos y")) + , fAnimation(0.f) + , fAnimStep(Settings.BannerGridSpeed) + , AnimationRunning(false) + , gridFrameColor(thColor("r=237 g=237 b=237 a=255 - banner icon frame color")) + , highliteColor(thColor("r=52 g=190 b=237 a=255 - banner icon highlite color")) +{ + GXColor gridTevColor[3]; + gridTevColor[0] = thColor("r=130 g=130 b=130 a=0 - banner icon frame edge tev color 1"); + gridTevColor[1] = thColor("r=180 g=180 b=180 a=255 - banner icon frame edge tev color 2"); + gridTevColor[2] = thColor("r=255 g=255 b=255 a=255 - banner icon frame edge tev color 3"); + + for(int i = 0; i < 3; i++) + gridFrameTevColor[i] = (GXColorS10) { gridTevColor[i].r, gridTevColor[i].g, gridTevColor[i].b, gridTevColor[i].a }; + + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigL.SetButtonOnlyTrigger(-1, WPAD_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_LEFT, PAD_BUTTON_LEFT); + trigR.SetButtonOnlyTrigger(-1, WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT, PAD_BUTTON_RIGHT); + trigPlus.SetButtonOnlyTrigger(-1, WPAD_BUTTON_PLUS | WPAD_CLASSIC_BUTTON_PLUS, PAD_TRIGGER_R); + trigMinus.SetButtonOnlyTrigger(-1, WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, PAD_TRIGGER_L); + + imgLeft = Resources::GetImageData("startgame_arrow_left.png"); + imgRight = Resources::GetImageData("startgame_arrow_right.png"); + imgNewData = Resources::GetImageData("new.png"); + + btnLeftImg = new GuiImage(imgLeft); + if (Settings.wsprompt) btnLeftImg->SetWidescreen(Settings.widescreen); + btnLeft = new GuiButton(btnLeftImg, btnLeftImg, ALIGN_LEFT, ALIGN_MIDDLE, 20, YOffset, &trigA, btnSoundOver, btnSoundClick2, 1); + btnLeft->SetTrigger(&trigL); + btnLeft->SetTrigger(&trigMinus); + btnLeft->SetParent(this); + + btnRightImg = new GuiImage(imgRight); + if (Settings.wsprompt) btnRightImg->SetWidescreen(Settings.widescreen); + btnRight = new GuiButton(btnRightImg, btnRightImg, ALIGN_RIGHT, ALIGN_MIDDLE, -20, YOffset, &trigA, btnSoundOver, btnSoundClick2, 1); + btnRight->SetTrigger(&trigR); + btnRight->SetTrigger(&trigPlus); + btnRight->SetParent(this); + + //! Get chanSel archive + if(SystemMenuResources::Instance()->GetChanSelAsh()) + { + U8Archive chanSelArc(SystemMenuResources::Instance()->GetChanSelAsh(), SystemMenuResources::Instance()->GetChanSelAshSize()); + + //! Create texture for the + gridFrameTex.Load(chanSelArc.GetFile("/arc/timg/IplTopMask4x3.tpl")); + gridFrameEdgeTex.Load(chanSelArc.GetFile("/arc/timg/IplTopMaskEgde4x3.tpl")); + gridHighliteTex.Load(chanSelArc.GetFile("/arc/timg/my_TV_f.tpl")); + + //! create static image frame + staticFrame.Load(chanSelArc); + } + + //! create vector with empty banner list + bannerList.resize(gameList.size(), NULL); + + //! Calculate the page count + //! 1 page is minumum to show statics even if no games are loaded + pageCnt = std::max((int)(bannerList.size() + 11) / 12, 1); + pageNo = LIMIT(listOffset / 12, 0, pageCnt-1); + + //! set screen properties + width = ScreenProps.x = screenwidth; + height = ScreenProps.y = screenheight; + + //! setup the gridview + guMtxIdentity(gridview); + guMtxTransApply(gridview, gridview, 0.0F, 0.0F, -9900.0F); + + for(int i = 0; i < MAX_BUTTONS; i++) + { + int row = Idx2Row(i); + int column = Idx2Column(i); + float fx = XOffset + chanWidth * column + ScreenProps.x * 0.5f - chanWidth * 2.f; + float fy = YOffset + chanHeight * row + (ScreenProps.y - chanHeight) * 0.5f - chanHeight; + + gridNewImg[i] = new GuiImage(imgNewData); + gridNewImg[i]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + gridNewImg[i]->SetPosition(-5, -5); + gridNewImg[i]->SetScale(0.95f); + gridNewImg[i]->SetEffect(EFFECT_PULSE, 5, 100); + + gridTT[i] = new GuiTooltip(NULL); + gridTT[i]->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + gridTT[i]->SetAlpha(thInt("255 - tooltip alpha")); + + gridBtn[i] = new GuiButton(chanWidth, chanHeight); + gridBtn[i]->SetPosition(fx, fy); + gridBtn[i]->SetTrigger(&trigA); + gridBtn[i]->SetSoundClick(btnSoundClick2); + gridBtn[i]->SetParent(this); + gridBtn[i]->SetIcon(gridNewImg[i]); + if(i >= (int) bannerList.size()) + gridBtn[i]->SetState(STATE_DISABLED); + } + + UpdateTooltips(); +} + +GuiBannerGrid::~GuiBannerGrid() +{ + for(int i = 0; i < MAX_BUTTONS; ++i) + { + delete gridBtn[i]; + delete gridTT[i]; + delete gridNewImg[i]; + } + + for(u32 i = 0; i < bannerList.size(); ++i) + { + if(bannerList[i] != NULL) + BannerAsync::RemoveBanner(bannerList[i]); + } + + delete imgLeft; + delete imgRight; + delete imgNewData; + + delete btnLeftImg; + delete btnRightImg; + + delete btnLeft; + delete btnRight; +} + +int GuiBannerGrid::GetClickedOption(void) +{ + for (int i = 0; i < MAX_BUTTONS; ++i) + { + if (gridBtn[i]->GetState() == STATE_CLICKED) + { + gridBtn[i]->SetState(STATE_SELECTED); + return pageNo * 12 + i; + } + } + return -1; +} + +int GuiBannerGrid::GetSelectedOption(void) +{ + for (int i = 0; i < MAX_BUTTONS; ++i) + { + if (gridBtn[i]->GetState() == STATE_SELECTED) + return pageNo * 12 + i; + } + return -1; +} + +void GuiBannerGrid::UpdateTooltips(void) +{ + int chIdx = pageNo * 12; + + for(int i = 0; i < MAX_BUTTONS; i++) + { + if(chIdx < 0 || chIdx >= (int) bannerList.size()) + { + gridBtn[i]->SetState(STATE_DISABLED); + } + else + { + if(gridBtn[i]->GetState() == STATE_DISABLED) + gridBtn[i]->SetState(STATE_DEFAULT); + gridTT[i]->SetText(GameTitles.GetTitle(gameList[chIdx])); + gridBtn[i]->SetToolTip(gridTT[i], 0, 30, ALIGN_CENTER, ALIGN_BOTTOM); + + if(gridTT[i]->GetLeft() < 20) + gridBtn[i]->SetToolTip(gridTT[i], 20 - gridTT[i]->GetLeft(), + 30, ALIGN_CENTER, ALIGN_BOTTOM); + + else if((gridTT[i]->GetLeft() + gridTT[i]->GetWidth()) > (screenwidth - 20)) + gridBtn[i]->SetToolTip(gridTT[i], (screenwidth - 20) - (gridTT[i]->GetLeft() + gridTT[i]->GetWidth()), + 30, ALIGN_CENTER, ALIGN_BOTTOM); + } + chIdx++; + } +} + +void GuiBannerGrid::GetIconCoordinates(int icon, f32 *x, f32 *y) +{ + int row = Idx2Row(icon % 12); + int column = Idx2Column(icon % 12); + *x = XOffset + chanWidth * column + ScreenProps.x * 0.5f - chanWidth * 2.f; + *y = YOffset + chanHeight * row + (ScreenProps.y - chanHeight) * 0.5f - chanHeight; +} + +void GuiBannerGrid::RenderHighliter(Mtx &modelview) +{ + u8 Tlut = 0; + gridHighliteTex.Apply(Tlut, GX_TEXMAP0, GX_MIRROR, GX_MIRROR); + + Mtx m1, mv; + guMtxIdentity(mv); + guMtxScaleApply(modelview, m1, 1.f, -1.f, 1.f); + guMtxTransApply(m1, m1,ScreenProps.x * 0.5f, ScreenProps.y * 0.5f, 0.f); + guMtxScaleApply(mv, mv, chanWidth, chanHeight, 0.f); + guMtxTransApply(mv, mv, -chanWidth * 0.5f, -chanHeight * 0.5f, 0.f); + guMtxConcat(m1, mv, mv); + GX_LoadPosMtxImm(mv, GX_PNMTX0); + + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_InvalidateTexAll(); + + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position3f32(0.f, 0.f, 0.f); + GX_Color4u8(highliteColor.r, highliteColor.g, highliteColor.b, highliteColor.a); + GX_TexCoord2f32(0.f, 2.f); + + GX_Position3f32(1.f, 0.f, 0.f); + GX_Color4u8(highliteColor.r, highliteColor.g, highliteColor.b, highliteColor.a); + GX_TexCoord2f32(2.f, 2.f); + + GX_Position3f32(1.f, 1.f, 0.f); + GX_Color4u8(highliteColor.r, highliteColor.g, highliteColor.b, highliteColor.a); + GX_TexCoord2f32(2.f, 0.f); + + GX_Position3f32(0.f, 1.f, 0.f); + GX_Color4u8(highliteColor.r, highliteColor.g, highliteColor.b, highliteColor.a); + GX_TexCoord2f32(0.f, 0.f); + GX_End(); +} + +void GuiBannerGrid::Update(GuiTrigger *t) +{ + if(!t || state == STATE_DISABLED) + return; + + for(int i = 0; i < MAX_BUTTONS && !AnimationRunning; i++) + gridBtn[i]->Update(t); + + if(pageNo > 0) + { + btnLeft->Update(t); + + if((btnLeft->GetState() == STATE_CLICKED) && !AnimationRunning) { + btnLeft->SetState(STATE_DEFAULT); + fAnimation -= chanWidth * 4.f; + pageNo--; + UpdateTooltips(); + } + } + + + if(pageNo < pageCnt-1) + { + btnRight->Update(t); + + if((btnRight->GetState() == STATE_CLICKED) && !AnimationRunning) { + btnRight->SetState(STATE_DEFAULT); + fAnimation += chanWidth * 4.f; + pageNo++; + UpdateTooltips(); + } + } +} + +void GuiBannerGrid::Draw() +{ + if(!this->IsVisible()) + return; + + u8 Tlut = 0; + + if(fAnimation > -fAnimStep && fAnimation < fAnimStep) + fAnimation = 0.0f; + else if(fAnimation > 0.0f) + fAnimation -= fAnimStep; + else if(fAnimation < 0.0f) + fAnimation += fAnimStep; + + AnimationRunning = (fAnimation != 0.0f); + + bool bSkipFrame = Settings.PAL50 && ((frameCount % 6) == 0); + + Mtx modelview; + guMtxTransApply(gridview, modelview, fAnimation, 0.f, 0.f); + + int chIdx = pageNo * 12; + + //! removed unneeded banners + for(int i = 0; i < (int) bannerList.size(); i++) + { + if((i < (chIdx - 24) || i > (chIdx + 36)) && bannerList[i] != NULL) + { + BannerAsync::RemoveBanner(bannerList[i]); + bannerList[i] = NULL; + } + } + + //! Load the games that are seen first and after that the rest + for(int i = chIdx+11; i >= chIdx; i--) // counting backwards so the loading is upwards + { + if(i >= 0 && i < (int) bannerList.size()) + { + if(!bannerList[i]) + bannerList[i] = new BannerAsync(gameList[i]); + + if(!bannerList[i]->getIcon()) + BannerAsync::PushFront(bannerList[i]); + } + } + + //! we start at the channels on pre-pre-page + chIdx -= 24; + + int GridCutLeft = 0; + int GridCutRight = vmode->fbWidth; + + for(int sIdx = -24; sIdx < 36; sIdx++, chIdx++) + { + int row = Idx2Row(sIdx); + int column = Idx2Column(sIdx); + + if(chIdx < 0 || chIdx >= pageCnt*12) + continue; + + if(chIdx >= 0 && chIdx < (int) bannerList.size() && !bannerList[chIdx]) + bannerList[chIdx] = new BannerAsync(gameList[chIdx]); + + Mtx mv1, mv2, iconview; + guMtxTransApply(modelview, iconview, XOffset + chanWidth * column - chanWidth * 1.5f, + -YOffset - chanHeight * row + chanHeight, 0.f); + + guMtxScaleApply(iconview, mv1, 1.f, -1.f, 1.f); + guMtxTransApply(mv1,mv1, (ScreenProps.x - chanWidth) * 0.5f, (ScreenProps.y - chanHeight) * 0.5f, 0.f); + guMtxTransApply(mv1,mv2, chanWidth, chanHeight, 0.f); + + f32 viewportv[6]; + f32 projectionv[7]; + + GX_GetViewportv(viewportv, vmode); + GX_GetProjectionv(projectionv, FSProjection2D, GX_ORTHOGRAPHIC); + + guVector vecTL; + guVector vecBR; + GX_Project(0.0f, 0.0f, 0.0f, mv1, projectionv, viewportv, &vecTL.x, &vecTL.y, &vecTL.z); + GX_Project(0.0f, 0.0f, 0.0f, mv2, projectionv, viewportv, &vecBR.x, &vecBR.y, &vecBR.z); + + //! Round scissor box offset up and the box size down + u32 scissorX = (u32)(0.5f + std::max(vecTL.x, (f32)std::max(-Settings.AdjustOverscanX, 0))); + u32 scissorY = (u32)(0.5f + std::max(vecTL.y, (f32)std::max(-Settings.AdjustOverscanY, 0))); + u32 scissorW = (u32)std::max(std::min(vecBR.x, ScreenProps.x-1+Settings.AdjustOverscanX) - scissorX, 0.0f); + u32 scissorH = (u32)std::max(vecBR.y - scissorY, 0.0f); + + GX_SetScissor(scissorX, scissorY, scissorW, scissorH ); + + // save scissor value for grid cut of left/right part + if(chIdx == 0) + GridCutLeft = scissorX; + if(chIdx == pageCnt*12-1) + GridCutRight = scissorX+scissorW; + + if(chIdx >= (int) bannerList.size() || !bannerList[chIdx]->getIcon()) + { + //! If out of range or the icon is not loaded yet render the static frame + staticFrame.Render(iconview, ScreenProps, Settings.widescreen); + } + else + { + Menu_DrawRectangle(0, 0, screenwidth, screenheight, (GXColor) { 0, 0, 0, 255}, 1); + bannerList[chIdx]->getIcon()->Render(iconview, ScreenProps, Settings.widescreen); + bannerList[chIdx]->getIcon()->AdvanceFrame(); + if(bSkipFrame) + bannerList[chIdx]->getIcon()->AdvanceFrame(); + } + } + + //! only advance the static animation once for the whole loop + staticFrame.AdvanceFrame(); + if(bSkipFrame) + staticFrame.AdvanceFrame(); + + //! scissor box for the grid + //! don't draw grid outside of overscan render range and cut off the stuff before first and after last element + u32 scissorX = (u32)std::max(-Settings.AdjustOverscanX, GridCutLeft); + u32 scissorY = (u32)std::max(-Settings.AdjustOverscanY, 0); + u32 scissorW = (u32)LIMIT(ScreenProps.x-1 + Settings.AdjustOverscanX * 2.f, 0.f, GridCutRight - scissorX); + u32 scissorH = (u32)std::max(ScreenProps.x-1 + Settings.AdjustOverscanY * 2.f, 0.f); + GX_SetScissor(scissorX, scissorY, scissorW, scissorH); + + //! Reset GX after icons + ReSetup_GX(); + + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_InvalidateTexAll(); + + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + Mtx mv; + guMtxIdentity(mv); + guMtxScaleApply(mv, mv, gridwidth, gridheight, 1.0f); + guMtxTransApply(mv, mv, (ScreenProps.x - gridwidth) * 0.5f + XOffset, + (ScreenProps.y - gridheight) * 0.5f + YOffset, + 0.f); + guMtxConcat(modelview, mv, mv); + + GX_LoadPosMtxImm(mv, GX_PNMTX0); + + // this texture uses the default environment + gridFrameTex.Apply(Tlut, GX_TEXMAP0, GX_MIRROR, GX_MIRROR); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position3f32(0.f, 0.f, 0.f); + GX_Color4u8(gridFrameColor.r, gridFrameColor.g, gridFrameColor.b, gridFrameColor.a); + GX_TexCoord2f32(0.f, 6.f); // 3 rows + + GX_Position3f32(1.f, 0.f, 0.f); + GX_Color4u8(gridFrameColor.r, gridFrameColor.g, gridFrameColor.b, gridFrameColor.a); + GX_TexCoord2f32(32.f, 6.f); // 16 columns, 3 rows + + GX_Position3f32(1.f, 1.f, 0.f); + GX_Color4u8(gridFrameColor.r, gridFrameColor.g, gridFrameColor.b, gridFrameColor.a); + GX_TexCoord2f32(32.f, 0.f); // 16 columns + + GX_Position3f32(0.f, 1.f, 0.f); + GX_Color4u8(gridFrameColor.r, gridFrameColor.g, gridFrameColor.b, gridFrameColor.a); + GX_TexCoord2f32(0.f, 0.f); + GX_End(); + + // this texture uses it's own tev and the same position as the above + gridFrameEdgeTex.Apply(Tlut, GX_TEXMAP0, GX_MIRROR, GX_MIRROR); + + // color registers + GX_SetTevColorS10(GX_TEVREG0, gridFrameTevColor[0]); + GX_SetTevColorS10(GX_TEVREG1, gridFrameTevColor[1]); + GX_SetTevColorS10(GX_TEVREG2, gridFrameTevColor[2]); + + // texture environment + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL ); + GX_SetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0); + GX_SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C1); + GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_FALSE, GX_TEVPREV ); + GX_SetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K3_A ); + GX_SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_A0, GX_CA_A1, GX_CA_TEXA, GX_CA_ZERO); + GX_SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_FALSE, GX_TEVPREV ); + GX_SetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_K3_A ); + GX_SetNumTevStages(1); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position3f32(0.f, 0.f, 0.f); + GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); + GX_TexCoord2f32(0.f, 6.f); // 3 rows + + GX_Position3f32(1.f, 0.f, 0.f); + GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); + GX_TexCoord2f32(32.f, 6.f); // 16 columns, 3 rows + + GX_Position3f32(1.f, 1.f, 0.f); + GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); + GX_TexCoord2f32(32.f, 0.f); // 16 columns + + GX_Position3f32(0.f, 1.f, 0.f); + GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); + GX_TexCoord2f32(0.f, 0.f); + GX_End(); + + // reset GX configs + ReSetup_GX(); + + // render highlter + for(int sIdx = 0; sIdx < MAX_BUTTONS; sIdx++) + { + // only render selected and when no animation is on going + if(!AnimationRunning && gridBtn[sIdx]->GetState() == STATE_SELECTED) + { + int row = Idx2Row(sIdx); + int column = Idx2Column(sIdx); + Mtx hlview; + guMtxTransApply(modelview, hlview, XOffset + chanWidth * column - chanWidth * 1.5f, + -YOffset - chanHeight * row + chanHeight, 0.f); + RenderHighliter(hlview); + } + } + + // reset GX configs + ReSetup_GX(); + + // remove scissor again + GX_SetScissor(0, 0, vmode->fbWidth, vmode->efbHeight); + + if(pageNo > 0) + btnLeft->Draw(); + if(pageNo < pageCnt-1) + btnRight->Draw(); + + for(int i = 0; i < MAX_BUTTONS; i++) + { + if(AnimationRunning) + gridBtn[i]->ResetState(); + + if (!AnimationRunning && Settings.marknewtitles && (pageNo * 12 + i) < gameList.size() + && NewTitles::Instance()->IsNew(gameList[pageNo * 12 + i]->id)) + gridBtn[i]->Draw(); + + gridBtn[i]->DrawTooltip(); + } +} diff --git a/source/GUI/GuiBannerGrid.h b/source/GUI/GuiBannerGrid.h new file mode 100644 index 0000000..6f765e1 --- /dev/null +++ b/source/GUI/GuiBannerGrid.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 _GUIBANNERGRID_H_ +#define _GUIBANNERGRID_H_ + +#include +#include "gui.h" +#include "gui_gamebrowser.h" +#include "usbloader/disc.h" +#include "banner/BannerAsync.h" +#include "banner/Texture.h" +#include "SystemMenu/StaticFrame.h" + +#define MAX_BUTTONS 12 + +class GuiBannerGrid : public GuiGameBrowser +{ +public: + GuiBannerGrid(int listOffset); + virtual ~GuiBannerGrid(); + int GetClickedOption(void); + int GetSelectedOption(void); + int getListOffset(void) const { return pageNo * 12; } + void GetIconCoordinates(int icon, f32 *x, f32 *y); + void Update(GuiTrigger *t); + void SetPage(int page) { pageNo = LIMIT(page, 0, pageCnt-1); UpdateTooltips(); } + void Draw(); +private: + void RenderHighliter(Mtx &modelview); + void UpdateTooltips(void); + + static constexpr float gridwidth = 2048.f; + static constexpr float gridheight = 288.f; + + static constexpr float chanWidth = 128.f; + static constexpr float chanHeight = 96.f; + + const int XOffset; + const int YOffset; + + float fAnimation; + float fAnimStep; + + bool AnimationRunning; + + int pageNo; + int pageCnt; + Vec2f ScreenProps; + + Texture gridFrameTex; + Texture gridFrameEdgeTex; + Texture gridHighliteTex; + StaticFrame staticFrame; + GXColor gridFrameColor; + GXColor highliteColor; + GXColorS10 gridFrameTevColor[3]; + Mtx gridview; + std::vector bannerList; + + GuiTrigger trigA; + GuiTrigger trigL; + GuiTrigger trigR; + GuiTrigger trigPlus; + GuiTrigger trigMinus; + + GuiImageData * imgLeft; + GuiImageData * imgRight; + GuiImageData * imgNewData; + + GuiImage * btnLeftImg; + GuiImage * btnRightImg; + GuiImage * gridNewImg[MAX_BUTTONS]; + + GuiButton * btnLeft; + GuiButton * btnRight; + GuiButton * gridBtn[MAX_BUTTONS]; + + GuiTooltip * gridTT[MAX_BUTTONS]; +}; + +#endif diff --git a/source/GUI/LoadCoverImage.cpp b/source/GUI/LoadCoverImage.cpp new file mode 100644 index 0000000..2449a42 --- /dev/null +++ b/source/GUI/LoadCoverImage.cpp @@ -0,0 +1,65 @@ +#include "GUI/gui.h" +#include "usbloader/disc.h" +#include "FileOperations/fileops.h" +#include "settings/CSettings.h" +#include "themes/CTheme.h" + +/**************************************************************************** + * LoadCoverImage + ***************************************************************************/ +GuiImageData *LoadCoverImage(struct discHdr *header, bool Prefere3D, bool noCover) +{ + if (!header) return NULL; + GuiImageData *Cover = NULL; + char ID3[4]; + char IDfull[7]; + char Path[255]; + bool flag = Prefere3D; + + snprintf(ID3, sizeof(ID3), "%s", (char *) header->id); + snprintf(IDfull, sizeof(IDfull), "%s", (char *) header->id); + + for (int i = 0; i < 2; ++i) + { + char *coverPath = flag ? Settings.covers_path : Settings.covers2d_path; + flag = !flag; + //Load full id image + snprintf(Path, sizeof(Path), "%s%s.png", coverPath, IDfull); + + if(!CheckFile(Path)) + { + snprintf(Path, sizeof(Path), "%s%s.png", coverPath, ID3); + if(!CheckFile(Path)) + continue; + } + + delete Cover; + Cover = new (std::nothrow) GuiImageData(Path); + //Load short id image + if (!Cover || !Cover->GetImage()) + { + snprintf(Path, sizeof(Path), "%s%s.png", coverPath, ID3); + delete Cover; + Cover = new (std::nothrow) GuiImageData(Path); + } + if (Cover && Cover->GetImage()) break; + } + //Load no image + if (noCover && (!Cover || !Cover->GetImage())) + { + flag = Prefere3D; + for (int i = 0; i < 2; ++i) + { + delete Cover; + Cover = Resources::GetImageData(flag ? "nocover.png" : "nocoverFlat.png"); + if (Cover && Cover->GetImage()) break; + flag = !flag; + } + } + if (Cover && !Cover->GetImage()) + { + delete Cover; + Cover = NULL; + } + return Cover; +} diff --git a/source/GUI/LoadCoverImage.h b/source/GUI/LoadCoverImage.h new file mode 100644 index 0000000..dae4283 --- /dev/null +++ b/source/GUI/LoadCoverImage.h @@ -0,0 +1,6 @@ +#ifndef LOADCOVERIMAGE_H_ +#define LOADCOVERIMAGE_H_ + +GuiImageData *LoadCoverImage(struct discHdr *header, bool Prefere3D = true, bool noCover = true); + +#endif diff --git a/source/GUI/OptionList.cpp b/source/GUI/OptionList.cpp new file mode 100644 index 0000000..41dda39 --- /dev/null +++ b/source/GUI/OptionList.cpp @@ -0,0 +1,135 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include "OptionList.hpp" + +OptionList::OptionList() +{ +} + +OptionList::~OptionList() +{ + ClearList(); +} + +void OptionList::SetName(int i, const char *format, ...) +{ + if(i < (int) name.size()) + name[i].clear(); + + if(!format) + return; + + char *tmp=0; + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va)>=0) && tmp) + { + if(i >= (int) name.size()) + { + Resize(i+1); + } + + name[i].assign(tmp); + + listChanged = true; + } + va_end(va); + + if(tmp) + free(tmp); +} + +void OptionList::SetValue(int i, const char *format, ...) +{ + if(i < (int) value.size()) + value[i].clear(); + + char *tmp=0; + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va)>=0) && tmp) + { + if(i >= (int) value.size()) + { + Resize(i+1); + } + + value[i].assign(tmp); + + listChanged = true; + } + va_end(va); + + if(tmp) + free(tmp); +} + +const char * OptionList::GetName(int i) +{ + if(i < 0 || i >= (int) name.size()) + return NULL; + + return name.at(i).c_str(); +} + +const char * OptionList::GetValue(int i) +{ + if(i < 0 || i >= (int) value.size()) + return NULL; + + return value.at(i).c_str(); +} + +void OptionList::Resize(int size) +{ + name.resize(size); + value.resize(size); + listChanged = true; +} + +void OptionList::RemoveOption(int i) +{ + if(i < 0 || i >= (int) name.size()) + return; + + name.erase(name.begin()+i); + value.erase(value.begin()+i); + listChanged = true; +} + +void OptionList::ClearList() +{ + name.clear(); + value.clear(); + std::vector().swap(name); + std::vector().swap(value); + listChanged = true; +} diff --git a/source/GUI/OptionList.hpp b/source/GUI/OptionList.hpp new file mode 100644 index 0000000..9b913ad --- /dev/null +++ b/source/GUI/OptionList.hpp @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef OPTIONLIST_HPP_ +#define OPTIONLIST_HPP_ + +#include +#include + +class OptionList +{ + public: + OptionList(); + ~OptionList(); + void SetName(int i, const char *format, ...) __attribute__((format (printf, 3, 4))); + void SetValue(int i, const char *format, ...) __attribute__((format (printf, 3, 4))); + const char * GetName(int i); + const char * GetValue(int i); + void Resize(int size); + int GetLength() { return name.size(); } + bool IsChanged() { bool ret = listChanged; listChanged = false; return ret;} + void RemoveOption(int i); + void ClearList(); + private: + std::vector name; + std::vector value; + bool listChanged; +}; + +#endif + diff --git a/source/GUI/Text.cpp b/source/GUI/Text.cpp new file mode 100644 index 0000000..144dd48 --- /dev/null +++ b/source/GUI/Text.cpp @@ -0,0 +1,331 @@ +#include "settings/CSettings.h" +#include "utils/tools.h" +#include "Text.hpp" + +Text::Text(const char * t, int s, GXColor c) : + GuiText(t, s, c) +{ + maxWidth = 400; + linestodraw = 9; + curLineStart = 0; + FirstLineOffset = 0; + wText = NULL; + + if (!text) return; + + wText = new (std::nothrow) wString(text); + if (!wText) + { + return; + } + + if (wText->size() == 0) + { + wText->push_back(L' '); + wText->push_back(0); + } + + textWidth = (font ? font : fontSystem)->getWidth(wText->data(), currentSize); + delete[] text; + text = NULL; + + SetMaxWidth(maxWidth); +} + +Text::Text(const wchar_t * t, int s, GXColor c) : + GuiText((wchar_t *) NULL, s, c) +{ + maxWidth = 400; + linestodraw = 9; + curLineStart = 0; + FirstLineOffset = 0; + wText = NULL; + + if (!t) return; + + wText = new (std::nothrow) wString(t); + if (!wText) + { + return; + } + + if (wText->size() == 0) + { + wText->push_back(L' '); + wText->push_back(0); + } + + textWidth = (font ? font : fontSystem)->getWidth(wText->data(), currentSize); + + SetMaxWidth(maxWidth); +} + +Text::~Text() +{ + if (wText) delete wText; + wText = NULL; + + TextLines.clear(); + ClearDynamicText(); +} + +void Text::SetText(const char * t) +{ + wchar_t * tmp = charToWideChar(t); + if (!tmp) return; + + if (wText) delete wText; + + wText = new (std::nothrow) wString(tmp); + if (!wText) + { + return; + } + + if (wText->size() == 0) + { + wText->push_back(L' '); + wText->push_back(0); + } + + textWidth = (font ? font : fontSystem)->getWidth(wText->data(), currentSize); + + delete[] tmp; + + ClearDynamicText(); + CalcLineOffsets(); +} + +void Text::SetText(const wchar_t * t) +{ + if (!t) return; + + if (wText) delete wText; + + wText = new wString(t); + textWidth = (font ? font : fontSystem)->getWidth(wText->data(), currentSize); + CalcLineOffsets(); +} + +void Text::SetMaxWidth(int w) +{ + maxWidth = w; + curLineStart = 0; + Refresh(); +} + +void Text::SetTextLine(int line) +{ + if (line < 0) + line = 0; + else if (line > (int) TextLines.size() - 1) line = TextLines.size() - 1; + + curLineStart = line; + + FillRows(); + + while ((int) textDyn.size() < linestodraw && curLineStart > 0) + { + PreviousLine(); + } +} + +void Text::SetTextPos(int pos) +{ + if (!wText) return; + + int diff = 10000; + + for (u32 i = 0; i < TextLines.size(); i++) + { + int curDiff = abs(TextLines[i].LineOffset - pos); + if (curDiff < diff) + { + diff = curDiff; + curLineStart = i; + } + } + + FillRows(); + + while ((int) textDyn.size() < linestodraw && curLineStart > 0) + { + PreviousLine(); + } +} + +const wchar_t * Text::GetText() +{ + return wText->c_str(); +} + +std::string Text::GetUTF8String(void) const +{ + return wText->toUTF8(); +} + +int Text::GetLineOffset(int ind) +{ + if (TextLines.size() == 0) return 0; + + if (ind < 0) return TextLines[0].LineOffset; + + if (ind >= (int) TextLines.size() - 1) return TextLines[TextLines.size() - 1].LineOffset; + + return TextLines[ind].LineOffset; +} + +const wchar_t * Text::GetTextLine(int ind) +{ + if (filling || textDyn.size() == 0) return NULL; + + if (ind < 0) return textDyn[0]; + + if (ind >= (int) textDyn.size()) return textDyn[textDyn.size() - 1]; + + return textDyn[ind]; +} + +void Text::Refresh() +{ + CalcLineOffsets(); + FillRows(); +} + +void Text::NextLine() +{ + if (!wText || (curLineStart + 1 > ((int) TextLines.size() - linestodraw))) return; + + ++curLineStart; + + FillRows(); +} + +void Text::PreviousLine() +{ + if (!wText || curLineStart - 1 < 0) return; + + --curLineStart; + + FillRows(); +} + +void Text::FillRows() +{ + if (!wText) return; + + filling = true; + + ClearDynamicText(); + + for (int i = 0; i < linestodraw && curLineStart+i < (int) TextLines.size(); i++) + { + if (i >= (int) textDyn.size()) + { + textDyn.resize(i + 1); + textDyn[i] = new wchar_t[maxWidth]; + } + int offset = TextLines[curLineStart + i].LineOffset; + int count = TextLines[curLineStart + i].CharCount + 1; + + for (int n = 0; n < count && offset + n < (int) wText->size(); n++) + textDyn[i][n] = wText->at(offset + n); + + textDyn[i][count] = 0; + } + + filling = false; + + return; +} + +void Text::CalcLineOffsets() +{ + if (!wText) return; + + TextLines.clear(); + + TextLine TmpLine; + TmpLine.CharCount = 0; + TmpLine.LineOffset = 0; + TmpLine.width = 0; + + const wchar_t * origTxt = wText->c_str(); + int ch = 0; + int lastSpace = -1; + int currWidth = 0; + int i = 0; + + while (origTxt[ch]) + { + currWidth += fontSystem->getCharWidth(origTxt[ch], currentSize, ch > 0 ? origTxt[ch - 1] : 0x0000); + + if (currWidth >= maxWidth) + { + if (lastSpace > 0) + { + ch = lastSpace; + } + TmpLine.CharCount = ch - TmpLine.LineOffset; + TmpLine.width = currWidth; + TextLines.push_back(TmpLine); + currWidth = 0; + lastSpace = -1; + i = -1; + TmpLine.LineOffset = ch + 1; + } + else if (origTxt[ch] == '\n') + { + TmpLine.CharCount = ch - TmpLine.LineOffset; + TmpLine.width = currWidth; + TextLines.push_back(TmpLine); + currWidth = 0; + lastSpace = -1; + i = -1; + TmpLine.LineOffset = ch + 1; + } + else if (origTxt[ch] == ' ') + { + lastSpace = ch; + } + + ch++; + i++; + } + + TmpLine.CharCount = ch - TmpLine.LineOffset; + TmpLine.width = currWidth; + + if (TmpLine.CharCount-1 > 0) + { + TmpLine.CharCount -= 1; + TextLines.push_back(TmpLine); + } +} + +void Text::Draw() +{ + if (textDyn.size() == 0) return; + + if (!this->IsVisible()) return; + + GXColor c = color; + c.a = this->GetAlpha(); + + int newSize = (int) (size * GetScale()); + + if (newSize != currentSize) + { + currentSize = LIMIT(newSize, 1, 100); + + if (wText) textWidth = (font ? font : fontSystem)->getWidth(wText->data(), currentSize); + } + + u16 lineheight = newSize + 6; + + for (u32 i = 0; i < textDyn.size(); i++) + { + if (!filling) (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop() + i * lineheight, 0, + textDyn[i], currentSize, c, style, 0, maxWidth); + } +} diff --git a/source/GUI/Text.hpp b/source/GUI/Text.hpp new file mode 100644 index 0000000..513915a --- /dev/null +++ b/source/GUI/Text.hpp @@ -0,0 +1,69 @@ +#ifndef _TEXT_HPP_ +#define _TEXT_HPP_ + +#include "GUI/gui.h" +#include "wstring.hpp" + +typedef struct +{ + int LineOffset; + int CharCount; + int width; +} TextLine; + +class Text: public GuiText +{ + public: + //!Constructor + //!\param t Text + //!\param s Font size + //!\param c Font color + Text(const char * t, int s, GXColor c); + Text(const wchar_t * t, int s, GXColor c); + virtual ~Text(); + //!Sets the text of the GuiText element + //!\param t Text + void SetText(const char * t); + void SetText(const wchar_t * t); + //!Set the max texwidth + void SetMaxWidth(int width); + //!Go to next line + void NextLine(); + //!Go to previous line + void PreviousLine(); + //!Refresh the rows to draw + void Refresh(); + //!Set the text line + void SetTextLine(int line); + //!Set to the char pos in text + void SetTextPos(int pos); + //!Refresh the rows to draw + int GetCurrPos() { return curLineStart; }; + //!Get the count of loaded lines + int GetLinesCount() { return textDyn.size(); }; + //!Get the total count of lines + int GetTotalLinesCount() { return TextLines.size(); }; + //!Get the original full Text + const wchar_t * GetText(); + //!Get the original full Text as wString + wString * GetwString() { return wText; }; + //!Get the original Text as a UTF-8 text + std::string GetUTF8String() const; + //!Get a Textline + const wchar_t * GetTextLine(int ind); + //!Get the offset in the text of a drawn Line + int GetLineOffset(int ind); + //!Constantly called to draw the text + void Draw(); + protected: + void CalcLineOffsets(); + void FillRows(); + + wString * wText; + std::vector TextLines; + int curLineStart; + int FirstLineOffset; + bool filling; +}; + +#endif diff --git a/source/GUI/gui.h b/source/GUI/gui.h new file mode 100644 index 0000000..778b679 --- /dev/null +++ b/source/GUI/gui.h @@ -0,0 +1,929 @@ +/**************************************************************************** + * LibWiiGui by Tantric (C) 2009 + * USB Loader GX Team (C) 2009-2011 + * + * The LibWiiGui library was used as the base for the creation of + * the GUI in USB Loader GX. + * Several modifications and additions were made to the library + * It does no longer match the original LibWiiGui implementation. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef LIBWIIGUI_H +#define LIBWIIGUI_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gui_imagedata.h" +#include "FreeTypeGX.h" +#include "video.h" +#include "input.h" +#include "OptionList.hpp" +#include "SoundOperations/gui_sound.h" +#include "SoundOperations/gui_bgm.h" +#include "utils/timer.h" +#include "sigslot.h" + +//! Frequently used variables +extern FreeTypeGX *fontSystem; +extern GuiSound *btnSoundClick; +extern GuiSound *btnSoundClick2; +extern GuiSound *btnSoundOver; +extern GuiBGM *bgMusic; + +#define SCROLL_INITIAL_DELAY 20 +#define SCROLL_LOOP_DELAY 3 +#define PAGESIZE 9 +#define FILEBROWSERSIZE 8 +#define MAX_OPTIONS 170 + +typedef void (*UpdateCallback)(void * e); + +enum +{ + ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE +}; + +enum +{ + STATE_DEFAULT, STATE_SELECTED, STATE_CLICKED, STATE_HELD, STATE_DISABLED +}; + +enum +{ + IMAGE_TEXTURE, IMAGE_COLOR, IMAGE_DATA, IMAGE_COPY +}; + +enum +{ + TRIGGER_SIMPLE, TRIGGER_HELD, TRIGGER_BUTTON_ONLY +}; + +enum +{ + WRAP, DOTTED, SCROLL_HORIZONTAL, SCROLL_NONE +}; + + +typedef struct _POINT { + s16 x; + s16 y; +} POINT; + +typedef struct _paddata +{ + u16 btns_d; + u16 btns_u; + u16 btns_h; + s8 stickX; + s8 stickY; + s8 substickX; + s8 substickY; + u8 triggerL; + u8 triggerR; +} PADData; + + +#define EFFECT_SLIDE_TOP 1 +#define EFFECT_SLIDE_BOTTOM 2 +#define EFFECT_SLIDE_RIGHT 4 +#define EFFECT_SLIDE_LEFT 8 +#define EFFECT_SLIDE_IN 16 +#define EFFECT_SLIDE_OUT 32 +#define EFFECT_FADE 64 +#define EFFECT_SCALE 128 +#define EFFECT_COLOR_TRANSITION 256 +#define EFFECT_PULSE 512 +#define EFFECT_ROCK_VERTICLE 1024 +#define EFFECT_GOROUND 2048 + +//!Menu input trigger management. Determine if action is neccessary based on input data by comparing controller input data to a specific trigger element. +class GuiTrigger +{ + public: + //!Constructor + GuiTrigger(); + //!Destructor + virtual ~GuiTrigger(); + //!Sets a simple trigger. Requires: element is selected, and trigger button is pressed + //!\param ch Controller channel number + //!\param wiibtns Wii controller trigger button(s) - classic controller buttons are considered separately + //!\param gcbtns GameCube controller trigger button(s) + void SetSimpleTrigger(s32 ch, u32 wiibtns, u16 gcbtns); + //!Sets a held trigger. Requires: element is selected, and trigger button is pressed + //!\param ch Controller channel number + //!\param wiibtns Wii controller trigger button(s) - classic controller buttons are considered separately + //!\param gcbtns GameCube controller trigger button(s) + void SetHeldTrigger(s32 ch, u32 wiibtns, u16 gcbtns); + //!Sets a button-only trigger. Requires: Trigger button is pressed + //!\param ch Controller channel number + //!\param wiibtns Wii controller trigger button(s) - classic controller buttons are considered separately + //!\param gcbtns GameCube controller trigger button(s) + void SetButtonOnlyTrigger(s32 ch, u32 wiibtns, u16 gcbtns); + //!Get X/Y value from Wii Joystick (classic, nunchuk) input + //!\param right Controller stick (left = 0, right = 1) + //!\param axis Controller stick axis (x-axis = 0, y-axis = 1) + //!\return Stick value + s8 WPAD_Stick(u8 right, int axis); + //!Move menu selection left (via pad/joystick). Allows scroll delay and button overriding + //!\return true if selection should be moved left, false otherwise + bool Left(); + //!Move menu selection right (via pad/joystick). Allows scroll delay and button overriding + //!\return true if selection should be moved right, false otherwise + bool Right(); + //!Move menu selection up (via pad/joystick). Allows scroll delay and button overriding + //!\return true if selection should be moved up, false otherwise + bool Up(); + //!Move menu selection down (via pad/joystick). Allows scroll delay and button overriding + //!\return true if selection should be moved down, false otherwise + bool Down(); + + u8 type; //!< trigger type (TRIGGER_SIMPLE, TRIGGER_HELD, TRIGGER_BUTTON_ONLY) + s32 chan; //!< Trigger controller channel (0-3, -1 for all) + WPADData wpad; //!< Wii controller trigger data + PADData pad; //!< GameCube controller trigger data +}; + +extern GuiTrigger userInput[4]; + +//!Primary GUI class. Most other classes inherit from this class. +class GuiElement +{ + public: + //!Constructor + GuiElement(); + //!Destructor + virtual ~GuiElement(); + //!Set the element's parent + //!\param e Pointer to parent element + void SetParent(GuiElement * e); + //!Gets the element's parent + //!\return Pointer to parent element + GuiElement * GetParent() { return parentElement; } + //!Gets the current leftmost coordinate of the element + //!Considers horizontal alignment, x offset, width, and parent element's GetLeft() / GetWidth() values + //!\return left coordinate + int GetLeft(); + //!Gets the current topmost coordinate of the element + //!Considers vertical alignment, y offset, height, and parent element's GetTop() / GetHeight() values + //!\return top coordinate + int GetTop(); + //!Sets the minimum y offset of the element + //!\param y Y offset + void SetMinY(int y); + //!Gets the minimum y offset of the element + //!\return Minimum Y offset + int GetMinY() { return ymin; } + //!Sets the maximum y offset of the element + //!\param y Y offset + void SetMaxY(int y); + //!Gets the maximum y offset of the element + //!\return Maximum Y offset + int GetMaxY() { return ymax; } + //!Sets the minimum x offset of the element + //!\param x X offset + void SetMinX(int x); + //!Gets the minimum x offset of the element + //!\return Minimum X offset + int GetMinX() { return xmin; } + //!Sets the maximum x offset of the element + //!\param x X offset + void SetMaxX(int x); + //!Gets the maximum x offset of the element + //!\return Maximum X offset + int GetMaxX() { return xmax; } + //!Gets the current width of the element. Does not currently consider the scale + //!\return width + virtual int GetWidth() { return width; } + //!Gets the height of the element. Does not currently consider the scale + //!\return height + virtual int GetHeight() { return height; } + //!Sets the size (width/height) of the element + //!\param w Width of element + //!\param h Height of element + void SetSize(int w, int h); + //!Checks whether or not the element is visible + //!\return true if visible, false otherwise + bool IsVisible() { return visible; } + //!Checks whether or not the element is selectable + //!\return true if selectable, false otherwise + bool IsSelectable(); + //!Checks whether or not the element is clickable + //!\return true if clickable, false otherwise + bool IsClickable(); + //!Checks whether or not the element is holdable + //!\return true if holdable, false otherwise + bool IsHoldable(); + //!Sets whether or not the element is selectable + //!\param s Selectable + void SetSelectable(bool s); + //!Sets whether or not the element is clickable + //!\param c Clickable + void SetClickable(bool c); + //!Sets whether or not the element is holdable + //!\param c Holdable + void SetHoldable(bool d); + //!Gets the element's current state + //!\return state + int GetState() { return state; } + //!Gets the controller channel that last changed the element's state + //!\return Channel number (0-3, -1 = no channel) + int GetStateChan() { return stateChan; } + //!Sets the element's alpha value + //!\param a alpha value + void SetAlpha(int a); + //!Gets the element's alpha value + //!Considers alpha, alphaDyn, and the parent element's GetAlpha() value + //!\return alpha + int GetAlpha(); + //!Gets the element's AngleDyn value + //!\return alpha + float GetAngleDyn(); + //!Sets the element's scale + //!\param s scale (1 is 100%) + void SetScale(float s); + //!Gets the element's current scale + //!Considers scale, scaleDyn, and the parent element's GetScale() value + virtual float GetScale(); + //!Set a new GuiTrigger for the element + //!\param t Pointer to GuiTrigger + void SetTrigger(GuiTrigger * t); + //!\overload + //!\param i Index of trigger array to set + //!\param t Pointer to GuiTrigger + void SetTrigger(u8 i, GuiTrigger * t); + //!Remove GuiTrigger for the element + //!\param i Index of trigger array to set + void RemoveTrigger(u8 i); + //!Checks whether rumble was requested by the element + //!\return true is rumble was requested, false otherwise + bool Rumble() { return rumble; } + //!Sets whether or not the element is requesting a rumble event + //!\param r true if requesting rumble, false if not + void SetRumble(bool r); + //!Set an effect for the element + //!\param e Effect to enable + //!\param a Amount of the effect (usage varies on effect) + //!\param t Target amount of the effect (usage varies on effect) + void SetEffect(int e, int a, int t = 0); + //!This SetEffect is for EFFECT_GOROUND only + //!\param e Effect to enable + //!\param speed is for Circlespeed + //!\param circles Circleamount in degree ike 180 for 1/2 circle or 720 for 2 circles + //!\param r Circle Radius in pixel + //!\param startdegree Degree where to start circling + //!\param anglespeedset Set the speed of Angle rotating make 1 for same speed as Circlespeed + //! or 0.5 for half the speed of the circlingspeed. Turn Anglecircling off by 0 to this param. + //!\param center_x x co-ordinate of the center of circle. + //!\param center_y y co-ordinate of the center of circle. + void SetEffect(int e, int speed, f32 circles, int r, f32 startdegree, f32 anglespeedset, int center_x, + int center_y); + //!Gets the frequency from the above effect + //!\return element frequency + float GetFrequency(); + //!Sets an effect to be enabled on wiimote cursor over + //!\param e Effect to enable + //!\param a Amount of the effect (usage varies on effect) + //!\param t Target amount of the effect (usage varies on effect) + void SetEffectOnOver(int e, int a, int t = 0); + //!Shortcut to SetEffectOnOver(EFFECT_SCALE, 4, 110) + void SetEffectGrow(); + //!Stops the current element effect + void StopEffect(); + //!Gets the current element effects + //!\return element effects + int GetEffect() { return effects; } + //!Gets the current element on over effects + //!\return element on over effects + int GetEffectOnOver() { return effectsOver; } + //!Checks whether the specified coordinates are within the element's boundaries + //!\param x X coordinate + //!\param y Y coordinate + //!\return true if contained within, false otherwise + bool IsInside(int x, int y); + //!Sets the element's position + //!\param x X coordinate + //!\param y Y coordinate + void SetPosition(int x, int y, int z = 0); + //!Sets the element's relative position + int GetRelLeft(); + int GetRelTop(); + //!Sets the element's setup position + int GetLeftPos() const { return xoffset; } + int GetTopPos() const { return yoffset; } + //!Updates the element's effects (dynamic values) + //!Called by Draw(), used for animation purposes + void UpdateEffects(); + //!Sets a function to called after after Update() + //!Callback function can be used to response to changes in the state of the element, and/or update the element's attributes + void SetUpdateCallback(UpdateCallback u); + //!Sets the element's visibility + //!\param v Visibility (true = visible) + virtual void SetVisible(bool v); + //!Sets the element's state + //!\param s State (STATE_DEFAULT, STATE_SELECTED, STATE_CLICKED, STATE_DISABLED) + //!\param c Controller channel (0-3, -1 = none) + virtual void SetState(int s, int c = -1); + //!Resets the element's state to STATE_DEFAULT + virtual void ResetState(); + //!Gets whether or not the element is in STATE_SELECTED + //!\return true if selected, false otherwise + virtual int GetSelected(); + //!Sets the element's alignment respective to its parent element + //!\param hor Horizontal alignment (ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER) + //!\param vert Vertical alignment (ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE) + virtual void SetAlignment(int hor, int vert); + //!Called constantly to allow the element to respond to the current input data + //!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD + virtual void Update(GuiTrigger * t); + //!Called constantly to redraw the element + virtual void Draw(); + virtual void DrawTooltip(); + protected: + void LockElement(); + void UnlockElement(); + // static mutex_t mutex; + static mutex_t _lock_mutex; + lwp_t _lock_thread; + u16 _lock_count; + lwpq_t _lock_queue; + friend class SimpleLock; + + //int position2; //! B Scrollbariable + bool visible; //!< Visibility of the element. If false, Draw() is skipped + int width; //!< Element width + int height; //!< Element height + int xoffset; //!< Element X offset + int yoffset; //!< Element Y offset + int zoffset; //!< Element Z offset + int ymin; //!< Element's min Y offset allowed + int ymax; //!< Element's max Y offset allowed + int xmin; //!< Element's min X offset allowed + int xmax; //!< Element's max X offset allowed + int xoffsetDyn; //!< Element X offset, dynamic (added to xoffset value for animation effects) + int yoffsetDyn; //!< Element Y offset, dynamic (added to yoffset value for animation effects) + int temp_xoffset; //!< Element Temp X offset + int temp_yoffset; //!< Element Temp Y offset + f32 degree; //!< Degree where to start for EFFECT_GOROUND enter it in ° like 60° + f32 frequency; //!< Speed for EFFECT_GOROUND || can also be negative for other direction + int Radius; //!< The radius in which the Element goes round for EFFECT_GOROUND + f32 circleamount; //!< Circleamount for the EFFECT_GOROUND effect + f32 xoffsetDynFloat; //!< Integer sucks float is need by some parts + f32 yoffsetDynFloat; //!< Integer sucks float is need by some parts + int changervar; //!< Changervariable for some stuff + int alpha; //!< Element alpha value (0-255) + f32 scale; //!< Element scale (1 = 100%) + f32 angleDyn; //!< AngleDyn for EFFECT_GOROUND + f32 anglespeed; //! _elements; //!< Contains all elements within the GuiWindow +}; + +//!Display, manage, and manipulate images in the GUI +class GuiImage: public GuiElement +{ + public: + //!Constructor + GuiImage(); + //!\overload + //!\param img Pointer to GuiImageData element + GuiImage(GuiImageData * img); + //!\overload + //!Sets up a new image from the image data specified + //!\param img + //!\param w Image width + //!\param h Image height + GuiImage(u8 * img, int w, int h); + //!\overload + //!Creates an image filled with the specified color + //!\param w Image width + //!\param h Image height + //!\param c Image color + GuiImage(int w, int h, GXColor c); + //! Copy Constructor + GuiImage(GuiImage &srcimage); + GuiImage(GuiImage *srcimage); + //! = operator for copying images + GuiImage &operator=(GuiImage &srcimage); + //!Destructor + virtual ~GuiImage(); + //!Sets the image rotation angle for drawing + //!\param a Angle (in degrees) + void SetAngle(float a); + //!Gets the image rotation angle for drawing + float GetAngle(); + //!Sets the number of times to draw the image horizontally + //!\param t Number of times to draw the image + void SetTileHorizontal(int t); + void SetTileVertical(int t); + // true set horizontal scale to 0.8 //added + void SetWidescreen(bool w); + //!Constantly called to draw the image + void Draw(); + //!Gets the image data + //!\return pointer to image data + u8 * GetImage(); + //!Sets up a new image using the GuiImageData object specified + //!\param img Pointer to GuiImageData object + void SetImage(GuiImageData * img); + //!\overload + //!\param img Pointer to image data + //!\param w Width + //!\param h Height + void SetImage(u8 * img, int w, int h); + //!Gets the pixel color at the specified coordinates of the image + //!\param x X coordinate + //!\param y Y coordinate + GXColor GetPixel(int x, int y); + //!Sets the pixel color at the specified coordinates of the image + //!\param x X coordinate + //!\param y Y coordinate + //!\param color Pixel color + void SetPixel(int x, int y, GXColor color); + //!Sets the image to grayscale + void SetGrayscale(void); + //!Set/disable the use of parentelement angle (default true) + void SetParentAngle(bool a); + //!Directly modifies the image data to create a color-striped effect + //!Alters the RGB values by the specified amount + //!\param s Amount to increment/decrement the RGB values in the image + void ColorStripe(int s); + //!Sets a stripe effect on the image, overlaying alpha blended rectangles + //!Does not alter the image data + //!\param s Alpha amount to draw over the image + void SetStripe(int s); + s32 z; + void SetSkew(int XX1, int YY1, int XX2, int YY2, int XX3, int YY3, int XX4, int YY4); + void SetSkew(int *skew /* int skew[8] */); + int xx1; + int yy1; + int xx2; + int yy2; + int xx3; + int yy3; + int xx4; + int yy4; + int rxx1; + int ryy1; + int rxx2; + int ryy2; + int rxx3; + int ryy3; + int rxx4; + int ryy4; + protected: + int imgType; //!< Type of image data (IMAGE_TEXTURE, IMAGE_COLOR, IMAGE_DATA) + u8 * image; //!< Poiner to image data. May be shared with GuiImageData data + f32 imageangle; //!< Angle to draw the image + int tileHorizontal; //!< Number of times to draw (tile) the image horizontally + int tileVertical; //!< Number of times to draw (tile) the image vertically + u8 stripe; //!< Alpha value (0-255) to apply a stripe effect to the texture + short widescreen; //added + bool parentangle; +}; +//!Display, manage, and manipulate text in the GUI +class GuiText: public GuiElement +{ + public: + //!Constructor + //!\param t Text + //!\param s Font size + //!\param c Font color + GuiText(const char * t, int s, GXColor c); + //!\overload + //!\param t Text + //!\param s Font size + //!\param c Font color + GuiText(const wchar_t * t, int s, GXColor c); + //!\overload + //!\Assumes SetPresets() has been called to setup preferred text attributes + //!\param t Text + GuiText(const char * t); + //!Destructor + virtual ~GuiText(); + //!Sets the text of the GuiText element + //!\param t Text + virtual void SetText(const char * t); + virtual void SetText(const wchar_t * t); + virtual void SetTextf(const char *format, ...) __attribute__( ( format( printf, 2, 3 ) ) ); + //!Sets up preset values to be used by GuiText(t) + //!Useful when printing multiple text elements, all with the same attributes set + //!\param sz Font size + //!\param c Font color + //!\param w Maximum width of texture image (for text wrapping) + //!\param wrap Wrapmode when w>0 + //!\param s Font style + //!\param h Text alignment (horizontal) + //!\param v Text alignment (vertical) + static void SetPresets(int sz, GXColor c, int w, u16 s, int h, int v); + //!Sets the font size + //!\param s Font size + void SetFontSize(int s); + //!Sets the maximum width of the drawn texture image + //!If the text exceeds this, it is wrapped to the next line + //!\param w Maximum width + //!\param m WrapMode + void SetMaxWidth(int w = 0, int m = WRAP); + //!Sets the font color + //!\param c Font color + void SetColor(GXColor c); + //!Sets the FreeTypeGX style attributes + //!\param s Style attributes + //!\param m Style-Mask attributes + void SetStyle(u16 s); + //!Sets the text alignment + //!\param hor Horizontal alignment (ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER) + //!\param vert Vertical alignment (ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE) + void SetAlignment(int hor, int vert); + //!Set PassChar + void SetPassChar(wchar_t p); + //!Sets the font + //!\param f Font + void SetFont(FreeTypeGX *f); + //!Get the original text as char + virtual const wchar_t * GetText(); + //!Overload for GetWidth() + int GetWidth() { return GetTextWidth(); } + //!Get the Horizontal Size of Text + int GetTextWidth(); + int GetTextWidth(int ind); + //!Get the max textwidth + int GetTextMaxWidth(); + //!Gets the total line number + virtual int GetLinesCount() { return 1; } + //!Get fontsize + int GetFontSize() { return size; } + //!Set max lines to draw + void SetLinesToDraw(int l); + void SetWidescreen(bool b) { widescreen = b; } + //!Get current Textline (for position calculation) + const wchar_t * GetDynText(int ind = 0); + virtual const wchar_t * GetTextLine(int ind) { return GetDynText(ind); } + //!Change the font + //!\param font bufferblock + //!\param font filesize + bool SetFont(const u8 *font, const u32 filesize); + //!Constantly called to draw the text + void Draw(); + protected: + //!Clear the dynamic text + void ClearDynamicText(); + //!Create a dynamic dotted text if the text is too long + void MakeDottedText(); + //!Scroll the text once + void ScrollText(); + //!Wrap the text to several lines + void WrapText(); + + wchar_t *text; + std::vector textDyn; + int wrapMode; //!< Wrapping toggle + int textScrollPos; //!< Current starting index of text string for scrolling + int textScrollInitialDelay; //!< Delay to wait before starting to scroll + int textScrollDelay; //!< Scrolling speed + int size; //!< Font size + int maxWidth; //!< Maximum width of the generated text object (for text wrapping) + u16 style; //!< FreeTypeGX style attributes + GXColor color; //!< Font color + FreeTypeGX *font; + int textWidth; + int currentSize; + int linestodraw; + wchar_t passChar; + bool widescreen; +}; + +//!Display, manage, and manipulate tooltips in the GUI. +class GuiTooltip: public GuiElement +{ + public: + //!Constructor + //!\param t Text + GuiTooltip(const char *t, int Alpha = 255); + //!Destructor + virtual ~GuiTooltip(); + //!Gets the element's current scale + //!Considers scale, scaleDyn, and the parent element's GetScale() value + float GetScale(); + //!Sets the text of the GuiTooltip element + //!\param t Text + void SetText(const char * t); + void SetWidescreen(bool w); // timely a dummy + //!Constantly called to draw the GuiButton + void Draw(); + protected: + GuiImageData * tooltipLeft; + GuiImageData * tooltipTile; + GuiImageData * tooltipRight; + GuiImage * leftImage; //!< Tooltip left-image + GuiImage * tileImage; //!< Tooltip tile-image + GuiImage * rightImage; //!< Tooltip right-image + GuiText *text; +}; + +//!Display, manage, and manipulate buttons in the GUI. Buttons can have images, icons, text, and sound set (all of which are optional) +class GuiButton: public GuiElement +{ + public: + //!Constructor + //!\param w Width + //!\param h Height + GuiButton(int w, int h); + //!\param img is the button GuiImage. it uses the height & width of this image for the button + //!\param imgOver is the button's over GuiImage + //!\param hor is horizontal alingment of the button + //!\param vert is verticle alignment of the button + //!\param x is xposition of the button + //!\param y is yposition of the button + //!\param trig is a GuiTrigger to assign to this button + //!\param sndOver is a GuiSound used for soundOnOver for this button + //!\param sndClick is a GuiSound used for clickSound of this button + //!\param grow sets effect grow for this button. 1 for yes ;0 for no + GuiButton(GuiImage* img, GuiImage* imgOver, int hor, int vert, int x, int y, GuiTrigger* trig, + GuiSound* sndOver, GuiSound* sndClick, u8 grow); + //!\param same as all the parameters for the above button plus the following + //!\param tt is a GuiTooltip assigned to this button + //!\param ttx and tty are the xPOS and yPOS for this tooltip in relationship to the button + //!\param h_align and v_align are horizontal and verticle alignment for the tooltip in relationship to the button + GuiButton(GuiImage* img, GuiImage* imgOver, int hor, int vert, int x, int y, GuiTrigger* trig, + GuiSound* sndOver, GuiSound* sndClick, u8 grow, GuiTooltip* tt, int ttx, int tty, int h_align, + int v_align); + //!Destructor + virtual ~GuiButton(); + //!Sets the button's image + //!\param i Pointer to GuiImage object + void SetImage(GuiImage* i); + //!Sets the button's image on over + //!\param i Pointer to GuiImage object + void SetImageOver(GuiImage* i); + //!Sets the button's image on hold + //!\param i Pointer to GuiImage object + void SetAngle(float a); + void SetImageHold(GuiImage* i); + //!Sets the button's image on click + //!\param i Pointer to GuiImage object + void SetImageClick(GuiImage* i); + //!Sets the button's icon + //!\param i Pointer to GuiImage object + void SetIcon(GuiImage* i); + //!Sets the button's icon on over + //!\param i Pointer to GuiImage object + void SetIconOver(GuiImage* i); + //!Sets the button's icon on hold + //!\param i Pointer to GuiImage object + void SetIconHold(GuiImage* i); + //!Sets the button's icon on click + //!\param i Pointer to GuiImage object + void SetIconClick(GuiImage* i); + //!Sets the button's label + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void SetLabel(GuiText* t, int n = 0); + //!Sets the button's label on over (eg: different colored text) + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void SetLabelOver(GuiText* t, int n = 0); + //!Sets the button's label on hold + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void SetLabelHold(GuiText* t, int n = 0); + //!Sets the button's label on click + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void SetLabelClick(GuiText* t, int n = 0); + //!Sets the sound to play on over + //!\param s Pointer to GuiSound object + void SetSoundOver(GuiSound * s); + //!Sets the sound to play on hold + //!\param s Pointer to GuiSound object + void SetSoundHold(GuiSound * s); + //!Sets the sound to play on click + //!\param s Pointer to GuiSound object + void SetSoundClick(GuiSound * s); + //!\param reset the soundover to NULL + void RemoveSoundOver(); + //!\param reset the soundclick to NULL + void RemoveSoundClick(); + //!Constantly called to draw the GuiButtons ToolTip + //!Sets the button's Tooltip on over + //!\param tt Pointer to GuiElement object, x & y Positioning, h & v Align + void SetToolTip(GuiTooltip* tt, int x, int y, int h = ALIGN_RIGHT, int v = ALIGN_TOP); + + void RemoveToolTip(); + //!Constantly called to draw the GuiButton + void Draw(); + void DrawTooltip(); + //!Constantly called to allow the GuiButton to respond to updated input data + //!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD + void Update(GuiTrigger * t); + //!Deactivate/Activate pointing on Games while B scrolling + void ScrollIsOn(int f); + void SetSkew(int XX1, int YY1, int XX2, int YY2, int XX3, int YY3, int XX4, int YY4); + void SetSkew(int *skew /* int skew[8] */); + virtual void SetState(int s, int c = -1); + sigslot::signal3 Clicked; + sigslot::signal3 Held; + protected: + GuiImage * image; //!< Button image (default) + GuiImage * imageOver; //!< Button image for STATE_SELECTED + GuiImage * imageHold; //!< Button image for STATE_HELD + GuiImage * imageClick; //!< Button image for STATE_CLICKED + GuiImage * icon; //!< Button icon (drawn after button image) + GuiImage * iconOver; //!< Button icon for STATE_SELECTED + GuiImage * iconHold; //!< Button icon for STATE_HELD + GuiImage * iconClick; //!< Button icon for STATE_CLICKED + GuiTooltip *toolTip; + Timer ToolTipDelay; + bool bOldTooltipVisible; + GuiText * label[3]; //!< Label(s) to display (default) + GuiText * labelOver[3]; //!< Label(s) to display for STATE_SELECTED + GuiText * labelHold[3]; //!< Label(s) to display for STATE_HELD + GuiText * labelClick[3]; //!< Label(s) to display for STATE_CLICKED + GuiSound * soundOver; //!< Sound to play for STATE_SELECTED + GuiSound * soundHold; //!< Sound to play for STATE_HELD + GuiSound * soundClick; //!< Sound to play for STATE_CLICKED +}; + +typedef struct _keytype +{ + char ch, chShift, chalt, chalt2; +} Key; + +//!On-screen keyboard +class GuiKeyboard: public GuiWindow +{ + public: + GuiKeyboard(char * t, u32 m, int min, int lang); + virtual ~GuiKeyboard(); + void SetVisibleText(bool v) { textVisible = v; } + const char *GetText() { return kbtextstr; } + void Update(GuiTrigger * t); + protected: + void SetDisplayText(const char *text); + + bool textVisible; + char kbtextstr[256]; + u32 kbtextmaxlen; + Key keys[4][11]; + int shift; + int caps; + int alt; + int alt2; + u16 min; + GuiText * kbText; + GuiImage * keyTextboxImg; + GuiText * keyCapsText; + GuiImage * keyCapsImg; + GuiImage * keyCapsOverImg; + GuiButton * keyCaps; + GuiText * keyAltText; + GuiImage * keyAltImg; + GuiImage * keyAltOverImg; + GuiButton * keyAlt; + GuiText * keyAlt2Text; + GuiImage * keyAlt2Img; + GuiImage * keyAlt2OverImg; + GuiButton * keyAlt2; + GuiText * keyShiftText; + GuiImage * keyShiftImg; + GuiImage * keyShiftOverImg; + GuiButton * keyShift; + GuiText * keyBackText; + GuiImage * keyBackImg; + GuiImage * keyBackOverImg; + GuiButton * keyBack; + GuiText * keyClearText; + GuiImage * keyClearImg; + GuiImage * keyClearOverImg; + GuiButton * keyClear; + GuiImage * keySpaceImg; + GuiImage * keySpaceOverImg; + GuiButton * keySpace; + GuiButton * keyBtn[4][11]; + GuiImage * keyImg[4][11]; + GuiImage * keyImgOver[4][11]; + GuiText * keyTxt[4][11]; + GuiImageData * keyTextbox; + GuiImageData * key; + GuiImageData * keyOver; + GuiImageData * keyMedium; + GuiImageData * keyLarge; + GuiTrigger * trigA; + GuiTrigger * trigB; +}; + +#endif diff --git a/source/GUI/gui_box.cpp b/source/GUI/gui_box.cpp new file mode 100644 index 0000000..c87ab02 --- /dev/null +++ b/source/GUI/gui_box.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "gui_box.hpp" + +void GuiBox::Draw() +{ + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); + u32 n = filled ? 4 : 5; + f32 x = GetLeft(); + f32 y = GetTop(); + f32 x2 = x + width; + f32 y2 = y + height; + guVector v[] = { { x, y, 0.0f }, { x2, y, 0.0f }, { x2, y2, 0.0f }, { x, y2, 0.0f }, { x, y, 0.0f } }; + + int alpha = GetAlpha(); + + GX_Begin(filled ? GX_TRIANGLEFAN : GX_LINESTRIP, GX_VTXFMT0, n); + for (u32 i = 0; i < n; i++) + { + GX_Position3f32(v[i].x, v[i].y, v[i].z); + GX_Color4u8(color[i].r, color[i].g, color[i].b, alpha); + } + GX_End(); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); +} diff --git a/source/GUI/gui_box.hpp b/source/GUI/gui_box.hpp new file mode 100644 index 0000000..4ecd952 --- /dev/null +++ b/source/GUI/gui_box.hpp @@ -0,0 +1,47 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GUIBOX_HPP_ +#define GUIBOX_HPP_ + +#include "GUI/gui.h" + +class GuiBox : public GuiElement +{ + public: + GuiBox() : filled(true) { SetColor((GXColor) {255, 255, 255, 255}); } + GuiBox(int w, int h) : filled(true) { width = w; height = h; SetColor((GXColor) {255, 255, 255, 255}); } + //! Set one color for the whole square + void SetColor(const GXColor c) { LOCK(this); for(int i = 0; i < 4; ++i) color[i] = c; } + //! Set Color for each corner having a nice fluent flow into the color of the other corners + //! 0 = up/left, 1 = up/right, 2 = buttom/left, 3 = buttom/right + void SetColor(int i, const GXColor c) { LOCK(this); if(i < 4) color[i] = c; } + void SetSize(int w, int h) { LOCK(this); width = w; height = h; } + void SetFilled(bool f) { LOCK(this); filled = f; } + void Draw(); + protected: + GXColor color[4]; + bool filled; +}; + +#endif diff --git a/source/GUI/gui_button.cpp b/source/GUI/gui_button.cpp new file mode 100644 index 0000000..a4164ef --- /dev/null +++ b/source/GUI/gui_button.cpp @@ -0,0 +1,544 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_button.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" +#include "settings/CSettings.h" + +static int scrollison = 0; + +/** + * Constructor for the GuiButton class. + */ + +GuiButton::GuiButton(int w, int h) +{ + width = w; + height = h; + image = NULL; + imageOver = NULL; + imageHold = NULL; + imageClick = NULL; + icon = NULL; + iconOver = NULL; + iconHold = NULL; + iconClick = NULL; + toolTip = NULL; + + for (int i = 0; i < 3; i++) + { + label[i] = NULL; + labelOver[i] = NULL; + labelHold[i] = NULL; + labelClick[i] = NULL; + } + + soundOver = NULL; + soundHold = NULL; + soundClick = NULL; + selectable = true; + holdable = false; + clickable = true; + bOldTooltipVisible = false; +} + +GuiButton::GuiButton(GuiImage* img, GuiImage* imgOver, int hor, int vert, int x, int y, GuiTrigger* trig, + GuiSound* sndOver, GuiSound* sndClick, u8 grow) +{ + width = img ? img->GetWidth() : 0; + height = img ? img->GetHeight() : 0; + image = img; + if(image) image->SetParent(this); + imageOver = imgOver; + if (imageOver) imageOver->SetParent(this); + imageHold = NULL; + imageClick = NULL; + icon = NULL; + iconOver = NULL; + iconHold = NULL; + iconClick = NULL; + toolTip = NULL; + alignmentHor = hor; + alignmentVert = vert; + xoffset = x; + yoffset = y; + trigger[0] = trig; + + for (int i = 0; i < 3; i++) + { + label[i] = NULL; + labelOver[i] = NULL; + labelHold[i] = NULL; + labelClick[i] = NULL; + } + + soundOver = sndOver; + soundHold = NULL; + soundClick = sndClick; + selectable = true; + holdable = false; + clickable = true; + bOldTooltipVisible = false; + + if (grow == 1) + { + effectsOver |= EFFECT_SCALE; + effectAmountOver = 4; + effectTargetOver = 110; + } +} + +GuiButton::GuiButton(GuiImage* img, GuiImage* imgOver, int hor, int vert, int x, int y, GuiTrigger* trig, + GuiSound* sndOver, GuiSound* sndClick, u8 grow, GuiTooltip* tt, int ttx, int tty, int h_align, int v_align) +{ + width = img ? img->GetWidth() : 0; + height = img ? img->GetHeight() : 0; + image = img; + if(image) image->SetParent(this); + imageOver = imgOver; + if (imageOver) imageOver->SetParent(this); + imageHold = NULL; + imageClick = NULL; + icon = NULL; + iconOver = NULL; + iconHold = NULL; + iconClick = NULL; + toolTip = NULL; + alignmentHor = hor; + alignmentVert = vert; + xoffset = x; + yoffset = y; + trigger[0] = trig; + + for (int i = 0; i < 3; i++) + { + label[i] = NULL; + labelOver[i] = NULL; + labelHold[i] = NULL; + labelClick[i] = NULL; + } + + soundOver = sndOver; + soundHold = NULL; + soundClick = sndClick; + selectable = true; + holdable = false; + clickable = true; + bOldTooltipVisible = false; + + if (grow == 1) + { + effectsOver |= EFFECT_SCALE; + effectAmountOver = 4; + effectTargetOver = 110; + } + + toolTip = tt; + if(toolTip) + { + toolTip->SetParent(this); + toolTip->SetAlignment(h_align, v_align); + toolTip->SetPosition(ttx, tty); + toolTip->SetVisible(false); + } +} + +/** + * Destructor for the GuiButton class. + */ +GuiButton::~GuiButton() +{ +} + +void GuiButton::SetImage(GuiImage* img) +{ + LOCK( this ); + image = img; + if (img) img->SetParent(this); +} +void GuiButton::SetImageOver(GuiImage* img) +{ + LOCK( this ); + imageOver = img; + if (img) img->SetParent(this); +} +void GuiButton::SetImageHold(GuiImage* img) +{ + LOCK( this ); + imageHold = img; + if (img) img->SetParent(this); +} +void GuiButton::SetImageClick(GuiImage* img) +{ + LOCK( this ); + imageClick = img; + if (img) img->SetParent(this); +} +void GuiButton::SetIcon(GuiImage* img) +{ + LOCK( this ); + icon = img; + if (img) img->SetParent(this); +} +void GuiButton::SetIconOver(GuiImage* img) +{ + LOCK( this ); + iconOver = img; + if (img) img->SetParent(this); +} +void GuiButton::SetIconHold(GuiImage* img) +{ + LOCK( this ); + iconHold = img; + if (img) img->SetParent(this); +} +void GuiButton::SetIconClick(GuiImage* img) +{ + LOCK( this ); + iconClick = img; + if (img) img->SetParent(this); +} +void GuiButton::SetLabel(GuiText* txt, int n) +{ + LOCK( this ); + label[n] = txt; + if (txt) txt->SetParent(this); +} +void GuiButton::SetLabelOver(GuiText* txt, int n) +{ + LOCK( this ); + labelOver[n] = txt; + if (txt) txt->SetParent(this); +} +void GuiButton::SetLabelHold(GuiText* txt, int n) +{ + LOCK( this ); + labelHold[n] = txt; + if (txt) txt->SetParent(this); +} +void GuiButton::SetLabelClick(GuiText* txt, int n) +{ + LOCK( this ); + labelClick[n] = txt; + if (txt) txt->SetParent(this); +} +void GuiButton::SetSoundOver(GuiSound * snd) +{ + LOCK( this ); + soundOver = snd; +} +void GuiButton::SetSoundHold(GuiSound * snd) +{ + LOCK( this ); + soundHold = snd; +} +void GuiButton::SetSoundClick(GuiSound * snd) +{ + LOCK( this ); + soundClick = snd; +} + +void GuiButton::SetToolTip(GuiTooltip* tt, int x, int y, int h_align, int v_align) +{ + LOCK( this ); + if (tt) + { + toolTip = tt; + toolTip->SetParent(this); + toolTip->SetAlignment(h_align, v_align); + toolTip->SetPosition(x, y); + toolTip->SetVisible(false); + } +} + +void GuiButton::RemoveToolTip() +{ + LOCK( this ); + toolTip = NULL; +} + +void GuiButton::RemoveSoundOver() +{ + LOCK( this ); + soundOver = NULL; +} +void GuiButton::RemoveSoundClick() +{ + LOCK( this ); + soundClick = NULL; +} +void GuiButton::SetSkew(int XX1, int YY1, int XX2, int YY2, int XX3, int YY3, int XX4, int YY4) +{ + if (image) + { + image->xx1 = XX1; + image->yy1 = YY1; + image->xx2 = XX2; + image->yy2 = YY2; + image->xx3 = XX3; + image->yy3 = YY3; + image->xx4 = XX4; + image->yy4 = YY4; + } +} + +void GuiButton::SetSkew(int *skew) +{ + if (image) image->SetSkew(skew); +} + +void GuiButton::SetState(int s, int c) +{ + GuiElement::SetState(s, c); + + if(c < 0 || c > 3) + return; + + if (s == STATE_CLICKED) + { + POINT p = {0, 0}; + + if (userInput[c].wpad.ir.valid) + { + p.x = userInput[c].wpad.ir.x; + p.y = userInput[c].wpad.ir.y; + } + Clicked(this, c, p); + } +} + +/** + * Draw the button on screen + */ +void GuiButton::Draw() +{ + LOCK( this ); + if (!this->IsVisible()) return; + + // draw image + if ((state == STATE_SELECTED || state == STATE_HELD) && imageOver) + imageOver->Draw(); + else if (image) image->Draw(); + // draw icon + if ((state == STATE_SELECTED || state == STATE_HELD) && iconOver) + iconOver->Draw(); + else if (icon) icon->Draw(); + // draw text + for (int i = 0; i < 3; i++) + { + if ((state == STATE_SELECTED || state == STATE_HELD) && labelOver[i]) + labelOver[i]->Draw(); + else if (label[i]) label[i]->Draw(); + } + + this->UpdateEffects(); +} +void GuiButton::DrawTooltip() +{ + if (!toolTip) + return; + + LOCK( this ); + + bool isVisible = this->IsVisible() && state == STATE_SELECTED; + + if (isVisible) + { + if(!bOldTooltipVisible) { + ToolTipDelay.reset(); + } + else if(!toolTip->IsVisible() && (int) ToolTipDelay.elapsed_millisecs() > Settings.TooltipDelay) + { + toolTip->SetEffect(EFFECT_FADE, 20); + toolTip->SetVisible(true); + } + } + else + { + if(bOldTooltipVisible) + toolTip->SetEffect(EFFECT_FADE, -20); + + if(toolTip->GetEffect() == 0) + toolTip->SetVisible(false); + } + + toolTip->Draw(); + + bOldTooltipVisible = isVisible; +} +void GuiButton::ScrollIsOn(int f) +{ + scrollison = f; +} + +void GuiButton::Update(GuiTrigger * t) +{ + LOCK( this ); + if (!this->IsVisible() || state == STATE_CLICKED || state == STATE_DISABLED || !t) + return; + else if (parentElement && parentElement->GetState() == STATE_DISABLED) return; + +#ifdef HW_RVL + // cursor + if ( t->wpad.ir.valid ) + { + if ( this->IsInside( t->wpad.ir.x, t->wpad.ir.y ) ) + { + if ( state == STATE_DEFAULT ) // we weren't on the button before! + + { + if ( scrollison == 0 ) + { + this->SetState( STATE_SELECTED, t->chan ); + } + + if ( this->Rumble() && scrollison == 0 ) + rumbleRequest[t->chan] = 1; + + if ( soundOver && scrollison == 0 ) + soundOver->Play(); + + if ( effectsOver && !effects && scrollison == 0 ) + { + // initiate effects + effects = effectsOver; + effectAmount = effectAmountOver; + effectTarget = effectTargetOver; + } + } + } + else + { + if ( state == STATE_SELECTED && ( stateChan == t->chan || stateChan == -1 ) ) + this->ResetState(); + + if ( effectTarget == effectTargetOver && effectAmount == effectAmountOver ) + { + // initiate effects (in reverse) + effects = effectsOver; + effectAmount = -effectAmountOver; + effectTarget = 100; + } + } + } +#else + + if (state == STATE_SELECTED && (stateChan == t->chan || stateChan == -1)) this->ResetState(); + + if (effectTarget == effectTargetOver && effectAmount == effectAmountOver) + { + // initiate effects (in reverse) + effects = effectsOver; + effectAmount = -effectAmountOver; + effectTarget = 100; + } + +#endif + + // button triggers + if (this->IsClickable() && scrollison == 0) + { + s32 wm_btns, wm_btns_trig, cc_btns, cc_btns_trig; + for (int i = 0; i < 6; i++) + { + if (trigger[i] && (trigger[i]->chan == -1 || trigger[i]->chan == t->chan)) + { + // higher 16 bits only (wiimote) + wm_btns = t->wpad.btns_d << 16; + wm_btns_trig = trigger[i]->wpad.btns_d << 16; + + // lower 16 bits only (classic controller) + cc_btns = t->wpad.btns_d >> 16; + cc_btns_trig = trigger[i]->wpad.btns_d >> 16; + + if( ((t->wpad.btns_d > 0 && wm_btns == wm_btns_trig) + || (t->wpad.exp.type == WPAD_EXP_CLASSIC && cc_btns == cc_btns_trig)) + || (t->pad.btns_d > 0 && t->pad.btns_d == trigger[i]->pad.btns_d)) + { + if (t->chan == stateChan || stateChan == -1) + { + if (state == STATE_SELECTED) + { + this->SetState(STATE_CLICKED, t->chan); + + if (soundClick) soundClick->Play(); + } + else if (trigger[i]->type == TRIGGER_BUTTON_ONLY) + { + this->SetState(STATE_CLICKED, t->chan); + if (soundClick) soundClick->Play(); + } + } + } + } + } + } + + if (this->IsHoldable()) + { + bool held = false; + s32 wm_btns, wm_btns_h, wm_btns_trig, cc_btns, cc_btns_h, cc_btns_trig; + + for (int i = 0; i < 6; i++) + { + if (trigger[i] && (trigger[i]->chan == -1 || trigger[i]->chan == t->chan)) + { + // higher 16 bits only (wiimote) + wm_btns = t->wpad.btns_d << 16; + wm_btns_h = t->wpad.btns_h << 16; + wm_btns_trig = trigger[i]->wpad.btns_h << 16; + + // lower 16 bits only (classic controller) + cc_btns = t->wpad.btns_d >> 16; + cc_btns_h = t->wpad.btns_h >> 16; + cc_btns_trig = trigger[i]->wpad.btns_h >> 16; + + if( (t->wpad.btns_d > 0 && wm_btns == wm_btns_trig) + || (t->wpad.exp.type == WPAD_EXP_CLASSIC && cc_btns == cc_btns_trig) + || (t->pad.btns_d > 0 && t->pad.btns_d == trigger[i]->pad.btns_d)) + { + if (trigger[i]->type == TRIGGER_HELD && state == STATE_SELECTED && (t->chan == stateChan || stateChan == -1)) + this->SetState(STATE_CLICKED, t->chan); + } + + if( (t->wpad.btns_h > 0 && wm_btns_h == wm_btns_trig) + || (t->wpad.exp.type == WPAD_EXP_CLASSIC && cc_btns_h == cc_btns_trig) + || (t->pad.btns_h > 0 && t->pad.btns_h == trigger[i]->pad.btns_h) + ) + { + if (trigger[i]->type == TRIGGER_HELD) + held = true; + } + + if (!held && state == STATE_HELD && stateChan == t->chan) + { + this->ResetState(); + } + else if (held && state == STATE_CLICKED && stateChan == t->chan) + { + this->SetState(STATE_HELD, t->chan); + } + else if (held && state == STATE_HELD && Held.connected()) + { + POINT p = {0, 0}; + + if (userInput[t->chan].wpad.ir.valid) + { + p.x = userInput[t->chan].wpad.ir.x; + p.y = userInput[t->chan].wpad.ir.y; + } + Held(this, t->chan, p); + } + } + } + } + + if (updateCB) updateCB(this); +} + diff --git a/source/GUI/gui_checkbox.cpp b/source/GUI/gui_checkbox.cpp new file mode 100644 index 0000000..6724f30 --- /dev/null +++ b/source/GUI/gui_checkbox.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "gui_checkbox.hpp" + +#define WHITEBOX_RED_SIZE 4 + +GuiCheckbox::GuiCheckbox(int s) + : GuiButton(30, 30), Checked(false), MultiStates(false) +{ + style = s; + Checksign.SetParent(this); + Cross.SetParent(this); + Plus.SetParent(this); + Blackbox.SetParent(this); + Whitebox.SetParent(this); + Checksign.SetColor((GXColor) {0, 0, 0, 255}); + Cross.SetColor((GXColor) {0, 0, 0, 255}); + Plus.SetColor((GXColor) {0, 0, 0, 255}); + Blackbox.SetColor((GXColor) {0, 0, 0, 255}); + Whitebox.SetColor((GXColor) {255, 255, 255, 255}); + + SetSize(30, 30); +} + +GuiCheckbox::GuiCheckbox(int w, int h, int s) + : GuiButton(w, h), Checked(false), MultiStates(false) +{ + style = s; + Checksign.SetParent(this); + Cross.SetParent(this); + Plus.SetParent(this); + Blackbox.SetParent(this); + Whitebox.SetParent(this); + Checksign.SetColor((GXColor) {0, 0, 0, 255}); + Cross.SetColor((GXColor) {0, 0, 0, 255}); + Plus.SetColor((GXColor) {0, 0, 0, 255}); + Blackbox.SetColor((GXColor) {0, 0, 0, 255}); + Whitebox.SetColor((GXColor) {255, 255, 255, 255}); + + SetSize(w, h); +} + +void GuiCheckbox::SetSize(int w, int h) +{ + width = w; + height = h; + Checksign.SetSize(w-WHITEBOX_RED_SIZE, h-WHITEBOX_RED_SIZE); + Checksign.SetPosition(WHITEBOX_RED_SIZE/2, WHITEBOX_RED_SIZE/2); + Cross.SetSize(w-WHITEBOX_RED_SIZE, h-WHITEBOX_RED_SIZE); + Cross.SetPosition(WHITEBOX_RED_SIZE/2, WHITEBOX_RED_SIZE/2); + Plus.SetSize(w-WHITEBOX_RED_SIZE, h-WHITEBOX_RED_SIZE); + Plus.SetPosition(WHITEBOX_RED_SIZE/2, WHITEBOX_RED_SIZE/2); + Blackbox.SetSize(w, h); + Whitebox.SetSize(w-WHITEBOX_RED_SIZE, h-WHITEBOX_RED_SIZE); + Whitebox.SetPosition(WHITEBOX_RED_SIZE/2, WHITEBOX_RED_SIZE/2); + SetAlignment(alignmentHor, alignmentVert); +} + +void GuiCheckbox::SetClickSize(int w, int h) +{ + width = w; + height = h; +} + +void GuiCheckbox::SetTransparent(bool b) +{ + Blackbox.SetFilled(b); + Whitebox.SetFilled(b); +} + +void GuiCheckbox::SetState(int s, int c) +{ + if(s == STATE_CLICKED) + { + if(MultiStates) + { + if(!Checked) + Checked = !Checked; + else + style++; + + if(style == MAX_CHECKBOX_STYLE) + { + Checked = !Checked; + style = CHECKSIGN; + } + } + else + Checked = !Checked; + } + + GuiButton::SetState(s, c); +} + +void GuiCheckbox::SetAlignment(int h, int v) +{ + GuiButton::SetAlignment(h, v); + Checksign.SetAlignment(h, v); + Cross.SetAlignment(h, v); + Plus.SetAlignment(h, v); + Blackbox.SetAlignment(h, v); + Whitebox.SetAlignment(h, v); + + if(h == ALIGN_RIGHT) + { + Checksign.SetPosition(-WHITEBOX_RED_SIZE/2, Checksign.GetTopPos()); + Cross.SetPosition(-WHITEBOX_RED_SIZE/2, Cross.GetTopPos()); + Plus.SetPosition(-WHITEBOX_RED_SIZE/2, Plus.GetTopPos()); + Whitebox.SetPosition(-WHITEBOX_RED_SIZE/2, Whitebox.GetTopPos()); + } + else if(h == ALIGN_CENTER) + { + Checksign.SetPosition(0, Checksign.GetTopPos()); + Cross.SetPosition(0, Cross.GetTopPos()); + Plus.SetPosition(0, Plus.GetTopPos()); + Whitebox.SetPosition(0, Whitebox.GetTopPos()); + } + if(v == ALIGN_BOTTOM) + { + Checksign.SetPosition(Checksign.GetLeftPos(), -WHITEBOX_RED_SIZE/2); + Cross.SetPosition(Cross.GetLeftPos(), -WHITEBOX_RED_SIZE/2); + Plus.SetPosition(Plus.GetLeftPos(), -WHITEBOX_RED_SIZE/2); + Whitebox.SetPosition(Whitebox.GetLeftPos(), -WHITEBOX_RED_SIZE/2); + } + else if(v == ALIGN_MIDDLE) + { + Checksign.SetPosition(Checksign.GetLeftPos(), 0); + Cross.SetPosition(Cross.GetLeftPos(), 0); + Plus.SetPosition(Plus.GetLeftPos(), 0); + Whitebox.SetPosition(Whitebox.GetLeftPos(), 0); + } +} + +void GuiCheckbox::Draw() +{ + GuiButton::Draw(); + Blackbox.Draw(); + Whitebox.Draw(); + if(Checked) + { + if(style == CHECKSIGN) + Checksign.Draw(); + else if (style == PLUS) + Plus.Draw(); + else + Cross.Draw(); + } +} diff --git a/source/GUI/gui_checkbox.hpp b/source/GUI/gui_checkbox.hpp new file mode 100644 index 0000000..fc3f1c3 --- /dev/null +++ b/source/GUI/gui_checkbox.hpp @@ -0,0 +1,68 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GUICHECKBOX_HPP_ +#define GUICHECKBOX_HPP_ + +#include "GUI/gui.h" +#include "GUI/gui_box.hpp" +#include "GUI/gui_cross.hpp" +#include "GUI/gui_checksign.hpp" +#include "GUI/gui_plus.hpp" + +class GuiCheckbox : public GuiButton +{ + public: + GuiCheckbox(int style = CHECKSIGN); + GuiCheckbox(int w, int h, int style = CHECKSIGN); + void SetTransparent(bool b); + void SetSize(int w, int h); + void SetClickSize(int w, int h); + void SetAlignment(int h, int v); + void SetChecked(bool c) { LOCK(this); Checked = c; } + void SetStyle(int st) { LOCK(this); style = st; } + void SetMultiStates(bool m) { LOCK(this); MultiStates = m; } + bool IsChecked() const { return Checked; } + int GetStyle() { return style; } + virtual void SetState(int s, int c = -1); + virtual void Draw(); + enum + { + CHECKSIGN, + CROSS, + PLUS, + MAX_CHECKBOX_STYLE + }; + protected: + GuiChecksign Checksign; + GuiCross Cross; + GuiPlus Plus; + GuiBox Blackbox; + GuiBox Whitebox; + int style; + bool Checked; + bool MultiStates; + +}; + +#endif diff --git a/source/GUI/gui_checkboxbrowser.cpp b/source/GUI/gui_checkboxbrowser.cpp new file mode 100644 index 0000000..95dc205 --- /dev/null +++ b/source/GUI/gui_checkboxbrowser.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "gui_checkboxbrowser.hpp" +#include "themes/Resources.h" +#include "themes/gettheme.h" +#include "wstring.hpp" + + +GuiCheckboxBrowser::GuiCheckboxBrowser(int w, int h, int s) + : scrollBar(h-10) +{ + width = w; + height = h; + backgroundImg = NULL; + selectedItem = 0; + pageIndex = 0; + pressedChan = -1; + maxTextWidth = 280; + maxSize = s; + scrollBar.SetParent(this); + scrollBar.SetAlignment(thAlign("right - checkbox browser scrollbar align hor"), thAlign("top - checkbox browser scrollbar align ver")); + scrollBar.SetPosition(thInt("0 - checkbox browser scrollbar pos x"), thInt("5 - checkbox browser scrollbar pos y")); + scrollBar.SetButtonScroll(WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B); + scrollBar.listChanged.connect(this, &GuiCheckboxBrowser::onListChange); + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + markImgData = Resources::GetImageData("checkBoxSelection.png"); + markImg = new GuiImage(markImgData); + markImg->SetParent(this); +} + +GuiCheckboxBrowser::~GuiCheckboxBrowser() +{ + Clear(); + + delete markImg; + delete markImgData; +} + +void GuiCheckboxBrowser::SetImage(GuiImage *Img) +{ + LOCK(this); + backgroundImg = Img; + if(backgroundImg) + backgroundImg->SetParent(this); +} + +void GuiCheckboxBrowser::Clear() +{ + LOCK(this); + checkBoxDrawn.clear(); + textLineDrawn.clear(); + + for(u32 i = 0; i < checkBoxList.size(); ++i) + { + delete textLineList[i]; + delete checkBoxList[i]; + } + + textLineList.clear(); + checkBoxList.clear(); +} + +bool GuiCheckboxBrowser::AddEntrie(const string &text, bool checked, int style, bool multistates) +{ + LOCK(this); + int currentSize = checkBoxList.size(); + textLineList.resize(currentSize+1); + checkBoxList.resize(currentSize+1); + + checkBoxList[currentSize] = new GuiCheckbox(30, 30); + checkBoxList[currentSize]->SetParent(this); + checkBoxList[currentSize]->SetChecked(checked); + checkBoxList[currentSize]->SetStyle(style); + checkBoxList[currentSize]->SetMultiStates(multistates); + checkBoxList[currentSize]->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); + checkBoxList[currentSize]->SetTrigger(&trigA); + checkBoxList[currentSize]->SetClickSize(width-30-scrollBar.GetWidth(), 30); + checkBoxList[currentSize]->Clicked.connect(this, &GuiCheckboxBrowser::OnCheckboxClick); + + textLineList[currentSize] = new GuiText(text.c_str(), 18, thColor("r=0 g=0 b=0 a=255 - checkbox browser text color")); + textLineList[currentSize]->SetParent(this); + textLineList[currentSize]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + textLineList[currentSize]->SetMaxWidth(maxTextWidth, DOTTED); + + if(textLineDrawn.size() < (u32) maxSize) + { + textLineDrawn.push_back(textLineList[currentSize]); + checkBoxDrawn.push_back(checkBoxList[currentSize]); + } + + return true; +} + +void GuiCheckboxBrowser::OnCheckboxClick(GuiButton *sender, int chan, const POINT &pointer) +{ + LOCK(this); + sender->ResetState(); + + for(u32 i = 0; i < checkBoxDrawn.size(); ++i) + { + if(sender == checkBoxDrawn[i]) + { + checkBoxClicked(checkBoxDrawn[i], pageIndex+i); + return; + } + } +} + +void GuiCheckboxBrowser::onListChange(int SelItem, int SelInd) +{ + LOCK(this); + selectedItem = SelItem; + pageIndex = SelInd; + RefreshList(); +} + +void GuiCheckboxBrowser::RefreshList() +{ + LOCK(this); + while(pageIndex+checkBoxDrawn.size() > checkBoxList.size()) + --pageIndex; + + if(checkBoxDrawn.size() == 0) + selectedItem = 0; + else if(selectedItem >= (int) checkBoxDrawn.size()) + selectedItem = checkBoxDrawn.size()-1; + + for(u32 i = 0; i < checkBoxDrawn.size(); i++) + { + checkBoxDrawn[i] = checkBoxList[pageIndex+i]; + checkBoxDrawn[i]->SetPosition(-scrollBar.GetWidth()-10, 15+i*(checkBoxDrawn[i]->GetHeight()+6)); + + textLineDrawn[i] = textLineList[pageIndex+i]; + textLineDrawn[i]->SetPosition(25, 10+i*(checkBoxDrawn[i]->GetHeight()+6)+(checkBoxDrawn[i]->GetHeight()-textLineDrawn[i]->GetFontSize())/2+2); + } + scrollBar.SetSelectedItem(selectedItem); + scrollBar.SetSelectedIndex(pageIndex); +} + +void GuiCheckboxBrowser::Draw() +{ + LOCK(this); + if(backgroundImg) + backgroundImg->Draw(); + + for(u32 i = 0; i < checkBoxDrawn.size(); ++i) + { + textLineDrawn[i]->Draw(); + checkBoxDrawn[i]->Draw(); + } + + markImg->Draw(); + + if(checkBoxList.size() >= (u32) maxSize) + scrollBar.Draw(); +} + +void GuiCheckboxBrowser::Update(GuiTrigger *t) +{ + if(state == STATE_DISABLED || !t) + return; + + LOCK(this); + if(checkBoxList.size() >= maxSize) + scrollBar.Update(t); + + if((t->wpad.btns_d & (WPAD_BUTTON_B | WPAD_BUTTON_DOWN | WPAD_BUTTON_UP | WPAD_BUTTON_LEFT | WPAD_BUTTON_RIGHT | + WPAD_CLASSIC_BUTTON_B | WPAD_CLASSIC_BUTTON_UP | WPAD_CLASSIC_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_RIGHT)) || + (t->pad.btns_d & (PAD_BUTTON_UP | PAD_BUTTON_DOWN))) + pressedChan = t->chan; + + for(u32 i = 0; i < checkBoxDrawn.size(); i++) + { + if(pressedChan == -1 || (!t->wpad.btns_h && !t->pad.btns_h)) + { + if(i != (u32) selectedItem && checkBoxDrawn[i]->GetState() == STATE_SELECTED) { + textLineList[i]->SetMaxWidth(maxTextWidth, DOTTED); + checkBoxDrawn[i]->ResetState(); + } + else if(i == (u32) selectedItem && checkBoxDrawn[i]->GetState() == STATE_DEFAULT) { + checkBoxDrawn[selectedItem]->SetState(STATE_SELECTED, -1); + textLineList[i]->SetMaxWidth(maxTextWidth, SCROLL_HORIZONTAL); + } + + checkBoxDrawn[i]->Update(t); + + if(checkBoxDrawn[i]->GetState() == STATE_SELECTED) + selectedItem = i; + } + + if(i == (u32) selectedItem) + markImg->SetPosition(5, 15+i*(checkBoxDrawn[i]->GetHeight()+6)+(checkBoxDrawn[i]->GetHeight()-markImg->GetHeight())/2); + } + + if(pressedChan == t->chan && !t->wpad.btns_d && !t->wpad.btns_h) + pressedChan = -1; + + scrollBar.SetPageSize(checkBoxDrawn.size()); + scrollBar.SetSelectedItem(selectedItem); + scrollBar.SetSelectedIndex(pageIndex); + scrollBar.SetEntrieCount(checkBoxList.size()); +} diff --git a/source/GUI/gui_checkboxbrowser.hpp b/source/GUI/gui_checkboxbrowser.hpp new file mode 100644 index 0000000..1f70850 --- /dev/null +++ b/source/GUI/gui_checkboxbrowser.hpp @@ -0,0 +1,71 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef CHECKBOXBROWSER_HPP_ +#define CHECKBOXBROWSER_HPP_ + +#include +#include +#include "gui_checkbox.hpp" +#include "gui_scrollbar.hpp" + +using namespace std; + +class GuiCheckboxBrowser : public GuiElement, public sigslot::has_slots<> +{ + public: + GuiCheckboxBrowser(int w, int h, int maxSize = 7); + virtual ~GuiCheckboxBrowser(); + bool AddEntrie(const string &text, bool checked = false, int style = GuiCheckbox::CHECKSIGN, bool multistates = false); + int GetSelected() const { return pageIndex+selectedItem; } + bool IsChecked(u32 i) { if(i >= checkBoxList.size()) return false; else return checkBoxList[i]->IsChecked(); } + GuiCheckbox *GetCheckbox(u32 i) { if(i >= checkBoxList.size()) return NULL; else return checkBoxList[i]; } + void SetMaxTextWidth(u32 w) { maxTextWidth = w; } + void SetImage(GuiImage *Img); + void RefreshList(); + void Clear(); + void Draw(); + void Update(GuiTrigger *t); + sigslot::signal2 checkBoxClicked; + private: + void onListChange(int SelItem, int SelInd); + void OnCheckboxClick(GuiButton *sender, int chan, const POINT &pointer); + u16 maxSize; + int selectedItem; + int pageIndex; + int pressedChan; + int maxTextWidth; + bool blocked; + + GuiScrollbar scrollBar; + GuiTrigger trigA; + GuiImage *backgroundImg; + GuiImageData *markImgData; + GuiImage *markImg; + vector textLineDrawn; + vector checkBoxDrawn; + vector textLineList; + vector checkBoxList; +}; + +#endif diff --git a/source/GUI/gui_checksign.cpp b/source/GUI/gui_checksign.cpp new file mode 100644 index 0000000..f7e2e42 --- /dev/null +++ b/source/GUI/gui_checksign.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "gui_checksign.hpp" + +void GuiChecksign::Draw() +{ + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); + + f32 x1Line1 = (float) GetLeft() + width*0.1f; + f32 y1Line1 = (float) GetTop() + height*0.65f; + f32 x2Line1 = GetLeft() + width*0.3f; + f32 y2Line1 = (float) GetTop() + (float) height - height*0.1f; + + f32 x1Line2 = x2Line1; + f32 y1Line2 = y2Line1; + f32 x2Line2 = (float) GetLeft() + (float) width - width*0.1f; + f32 y2Line2 = (float) GetTop() + height*0.1f; + + int alpha = GetAlpha(); + + GX_Begin(GX_LINES, GX_VTXFMT0, 4); + GX_Position3f32(x1Line1, y1Line1, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_Position3f32(x2Line1, y2Line1, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_Position3f32(x1Line2, y1Line2, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_Position3f32(x2Line2, y2Line2, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_End(); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); +} diff --git a/source/GUI/gui_checksign.hpp b/source/GUI/gui_checksign.hpp new file mode 100644 index 0000000..d650d57 --- /dev/null +++ b/source/GUI/gui_checksign.hpp @@ -0,0 +1,43 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GUICHECKSIGN_HPP_ +#define GUICHECKSIGN_HPP_ + +#include "GUI/gui.h" + +class GuiChecksign : public GuiElement +{ + public: + GuiChecksign() : Linewidth(2.0f) { color = (GXColor) {0, 0, 0, 255}; GX_SetLineWidth((u8) (Linewidth*6.0f), 0); } + //! Max line width is 42.5 pixel + void SetLinewidth(float w) { LOCK(this); Linewidth = w; GX_SetLineWidth((u8) (Linewidth*6.0f), 0); } + void SetColor(const GXColor c) { LOCK(this); color = c; } + void SetSize(int w, int h) { LOCK(this); width = w; height = h; } + void Draw(); + protected: + GXColor color; + float Linewidth; +}; + +#endif diff --git a/source/GUI/gui_circle.cpp b/source/GUI/gui_circle.cpp new file mode 100644 index 0000000..b2fd4a6 --- /dev/null +++ b/source/GUI/gui_circle.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "gui_circle.hpp" + +GuiCircle::GuiCircle() + : radius(100.0f), filled(true), accuracy(36) +{ + + color = (GXColor) {0, 0, 0, 255}; + SetLinewidth(1.0f); +} + +GuiCircle::GuiCircle(float r) + : radius(r), filled(true), accuracy(36) +{ + color = (GXColor) {0, 0, 0, 255}; + SetLinewidth(1.0f); +} + +void GuiCircle::SetLinewidth(float s) +{ + LOCK(this); + Linewidth = s; + GX_SetLineWidth((u8) (s*6.0f), 0); +} + +void GuiCircle::Draw() +{ + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); + + int loopAmount = filled ? accuracy : accuracy+1; + + GX_Begin(filled ? GX_TRIANGLEFAN : GX_LINESTRIP, GX_VTXFMT0, loopAmount); + for(int i = 0; i < loopAmount; ++i) + { + f32 rad = (f32) i / (f32) accuracy * 360.0f; + f32 x = cos(DegToRad(rad)) * radius + GetLeft(); + f32 y = sin(DegToRad(rad)) * radius + GetTop(); + + GX_Position3f32(x, y, 0.0f); + GX_Color4u8(color.r, color.g, color.b, color.a); + } + GX_End(); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); +} diff --git a/source/GUI/gui_circle.hpp b/source/GUI/gui_circle.hpp new file mode 100644 index 0000000..ae4be06 --- /dev/null +++ b/source/GUI/gui_circle.hpp @@ -0,0 +1,49 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GUICIRCLE_HPP_ +#define GUICIRCLE_HPP_ + +#include "gui.h" + +class GuiCircle : public GuiElement +{ + public: + GuiCircle(); + GuiCircle(float radius); + void SetRadius(float r) { LOCK(this); radius = r; } + void SetInnerRadius(float r) { SetLinewidth((radius-r)*2.0f); } + void SetColor(const GXColor c) { LOCK(this); color = c; } + void SetAccuracy(int a) { LOCK(this); accuracy = a; } + void SetFilled(bool f) { LOCK(this); filled = f; } + void SetLinewidth(float s); + void Draw(); + protected: + GXColor color; + float radius; + float Linewidth; + bool filled; + int accuracy; +}; + +#endif diff --git a/source/GUI/gui_cross.cpp b/source/GUI/gui_cross.cpp new file mode 100644 index 0000000..e630471 --- /dev/null +++ b/source/GUI/gui_cross.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "gui_cross.hpp" + +void GuiCross::Draw() +{ + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); + + f32 x1 = GetLeft(); + f32 x2 = x1 + width; + f32 y1 = GetTop(); + f32 y2 = y1 + height; + + int alpha = GetAlpha(); + + GX_Begin(GX_LINES, GX_VTXFMT0, 4); + GX_Position3f32(x1, y1, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_Position3f32(x2, y2, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_Position3f32(x2, y1, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_Position3f32(x1, y2, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_End(); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); +} diff --git a/source/GUI/gui_cross.hpp b/source/GUI/gui_cross.hpp new file mode 100644 index 0000000..375efaa --- /dev/null +++ b/source/GUI/gui_cross.hpp @@ -0,0 +1,43 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GUICROSS_HPP_ +#define GUICROSS_HPP_ + +#include "GUI/gui.h" + +class GuiCross : public GuiElement +{ + public: + GuiCross() : Linewidth(2.0f) { color = (GXColor) {0, 0, 0, 255}; GX_SetLineWidth((u8) (Linewidth*6.0f), 0); } + //! Max line width is 42.5 pixel + void SetLinewidth(float w) { LOCK(this); Linewidth = w; GX_SetLineWidth((u8) (Linewidth*6.0f), 0); } + void SetColor(const GXColor c) { LOCK(this); color = c; } + void SetSize(int w, int h) { LOCK(this); width = w; height = h; } + void Draw(); + protected: + GXColor color; + float Linewidth; +}; + +#endif diff --git a/source/GUI/gui_diskcover.cpp b/source/GUI/gui_diskcover.cpp new file mode 100644 index 0000000..dc19285 --- /dev/null +++ b/source/GUI/gui_diskcover.cpp @@ -0,0 +1,98 @@ +#include "gui_diskcover.h" +#include "settings/CSettings.h" + +GuiDiskCover::GuiDiskCover() +{ + PosZ = 50; + Distance = 55; + OldDegBeta = 0.0; + deg_beta = 0.0; + eff_step = 0; + // spin_angle = 0; + spin_speedup = 1.0; + spin_up = false; +} +GuiDiskCover::GuiDiskCover(GuiImageData *Disk) : + GuiImage(Disk) +{ + PosZ = 50; + Distance = 55; + OldDegBeta = 0.0; + deg_beta = 0.0; + eff_step = 0; + // spin_angle = 0; + spin_speedup = 1.0; + spin_up = false; +} +GuiDiskCover::~GuiDiskCover() +{ +} + +void GuiDiskCover::SetBeta(f32 beta) +{ + deg_beta = beta; +} +void GuiDiskCover::SetBetaRotateEffect(f32 beta, u16 step) +{ + eff_beta = beta / (f32) step; + eff_step = step; +} +bool GuiDiskCover::GetBetaRotateEffect() +{ + return eff_step != 0; +} + +void GuiDiskCover::SetState(int s, int c) +{ + if(state == STATE_DEFAULT && s == STATE_DISABLED) + { + PosZ = 0; + Distance = 0; + OldDegBeta = deg_beta; + deg_beta = 0.0f; + } + else if(state == STATE_DISABLED && s == STATE_DEFAULT) + { + PosZ = 50; + Distance = 55; + deg_beta = OldDegBeta; + } + + GuiImage::SetState(s, c); +} + +void Menu_DrawDiskCover(f32 xpos, f32 ypos, f32 zpos, u16 width, u16 height, u16 distance, u8 data[], f32 deg_alpha, + f32 deg_beta, f32 scaleX, f32 scaleY, u8 alpha, bool shadow); + +void GuiDiskCover::Draw() +{ + LOCK( this ); + if (!image || !this->IsVisible()) return; + float currScale = this->GetScale(); + + Menu_DrawDiskCover(this->GetLeft(), this->GetTop(), PosZ, width, height, Distance, image, imageangle, deg_beta, + widescreen ? currScale * Settings.WSFactor : currScale, currScale, 64, true); + Menu_DrawDiskCover(this->GetLeft(), this->GetTop(), PosZ, width, height, Distance, image, imageangle, deg_beta, + widescreen ? currScale * Settings.WSFactor : currScale, currScale, this->GetAlpha(), false); + + if (eff_step) + { + deg_beta += eff_beta; + eff_step--; + } + GuiImage::imageangle += spin_speedup; + while (GuiImage::imageangle >= 360.0) + GuiImage::imageangle -= 360.0; + + if (spin_up) + { + if (spin_speedup < 11) // speed up + spin_speedup += 0.20; + } + else + { + if (spin_speedup > 1) spin_speedup -= 0.05; //slow down + } + + this->UpdateEffects(); +} diff --git a/source/GUI/gui_diskcover.h b/source/GUI/gui_diskcover.h new file mode 100644 index 0000000..4c83df3 --- /dev/null +++ b/source/GUI/gui_diskcover.h @@ -0,0 +1,32 @@ +#ifndef _GUIDISCCOVER_H_ +#define _GUIDISCCOVER_H_ + +#include "gui.h" + +class GuiDiskCover: public GuiImage +{ + public: + GuiDiskCover(); + GuiDiskCover(GuiImageData * img); + virtual ~GuiDiskCover(); + void SetBeta(f32 beta); + void SetBetaRotateEffect(f32 beta, u16 Step); + bool GetBetaRotateEffect(); + + void SetSpin(bool Up) { spin_up = Up; } + void SetState(int s, int c = -1); + void Draw(); + private: + f32 deg_beta; + f32 eff_beta; + u16 eff_step; + + // f32 spin_angle; + f32 spin_speedup; + int PosZ; + int Distance; + f32 OldDegBeta; + bool spin_up; +}; + +#endif /* _GUIDISCCOVER_H_ */ diff --git a/source/GUI/gui_element.cpp b/source/GUI/gui_element.cpp new file mode 100644 index 0000000..491e85e --- /dev/null +++ b/source/GUI/gui_element.cpp @@ -0,0 +1,747 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_element.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" + +/** + * Constructor for the Object class. + */ +//mutex_t GuiElement::mutex = LWP_MUTEX_NULL; +mutex_t GuiElement::_lock_mutex = LWP_MUTEX_NULL; +GuiElement::GuiElement() +{ + xoffset = 0; + yoffset = 0; + zoffset = 0; + xmin = 0; + xmax = 0; + ymin = 0; + ymax = 0; + width = 0; + height = 0; + alpha = 255; + scale = 1; + state = STATE_DEFAULT; + stateChan = -1; + trigger[0] = NULL; + trigger[1] = NULL; + trigger[2] = NULL; + trigger[3] = NULL; + trigger[4] = NULL; + trigger[5] = NULL; + parentElement = NULL; + rumble = true; + selectable = false; + clickable = false; + holdable = false; + visible = true; + updateCB = NULL; + yoffsetDyn = 0; + xoffsetDyn = 0; + yoffsetDynFloat = 0; + alphaDyn = -1; + scaleDyn = 1; + effects = 0; + effectAmount = 0; + effectTarget = 0; + effectsOver = 0; + effectAmountOver = 0; + effectTargetOver = 0; + frequency = 0.0f; + changervar = 0; + degree = -90.0f; + circleamount = 360.0f; + Radius = 150; + angleDyn = 0.0f; + anglespeed = 0.0f; + + // default alignment - align to top left + alignmentVert = ALIGN_TOP; + alignmentHor = ALIGN_LEFT; + // if(mutex == LWP_MUTEX_NULL) LWP_MutexInit(&mutex, true); + if (_lock_mutex == LWP_MUTEX_NULL) LWP_MutexInit(&_lock_mutex, true); + _lock_thread = LWP_THREAD_NULL; + _lock_count = 0; + _lock_queue = LWP_TQUEUE_NULL; + +} + +/** + * Destructor for the GuiElement class. + */ +GuiElement::~GuiElement() +{ + // LWP_MutexDestroy(mutex); +} + +void GuiElement::SetParent(GuiElement * e) +{ + LOCK( this ); + parentElement = e; +} + +/** + * Get the left position of the GuiElement. + * @see SetLeft() + * @return Left position in pixel. + */ +int GuiElement::GetLeft() +{ + int x = 0; + int pWidth = 0; + int pLeft = 0; + + if (parentElement) + { + pWidth = parentElement->GetWidth(); + pLeft = parentElement->GetLeft(); + } + + if (effects & (EFFECT_SLIDE_IN | EFFECT_SLIDE_OUT | EFFECT_GOROUND | EFFECT_ROCK_VERTICLE)) pLeft += xoffsetDyn; + + switch (alignmentHor) + { + case ALIGN_LEFT: + x = pLeft; + break; + case ALIGN_CENTER: + x = pLeft + (pWidth / 2) - (width / 2); + break; + case ALIGN_RIGHT: + x = pLeft + pWidth - width; + break; + } + return x + xoffset; +} + +/** + * Get the top position of the GuiElement. + * @see SetTop() + * @return Top position in pixel. + */ +int GuiElement::GetTop() +{ + int y = 0; + int pHeight = 0; + int pTop = 0; + + if (parentElement) + { + pHeight = parentElement->GetHeight(); + pTop = parentElement->GetTop(); + } + + if (effects & (EFFECT_SLIDE_IN | EFFECT_SLIDE_OUT | EFFECT_GOROUND | EFFECT_ROCK_VERTICLE)) pTop += yoffsetDyn; + + switch (alignmentVert) + { + case ALIGN_TOP: + y = pTop; + break; + case ALIGN_MIDDLE: + y = pTop + (pHeight / 2) - (height / 2); + break; + case ALIGN_BOTTOM: + y = pTop + pHeight - height; + break; + } + return y + yoffset; +} + +int GuiElement::GetRelLeft() +{ + GuiElement *tmp = parentElement; + parentElement = NULL; + int pos = GetLeft(); + parentElement = tmp; + + return pos; +} + +int GuiElement::GetRelTop() +{ + GuiElement *tmp = parentElement; + parentElement = NULL; + int pos = GetTop(); + parentElement = tmp; + + return pos; +} + +void GuiElement::SetMinX(int x) +{ + LOCK( this ); + xmin = x; +} + +void GuiElement::SetMaxX(int x) +{ + LOCK( this ); + xmax = x; +} + +void GuiElement::SetMinY(int y) +{ + LOCK( this ); + ymin = y; +} + +void GuiElement::SetMaxY(int y) +{ + LOCK( this ); + ymax = y; +} + +/** + * Set the width and height of the GuiElement. + * @param[in] Width Width in pixel. + * @param[in] Height Height in pixel. + * @see SetWidth() + * @see SetHeight() + */ +void GuiElement::SetSize(int w, int h) +{ + LOCK( this ); + + width = w; + height = h; +} + +/** + * Set visible. + * @param[in] Visible Set to true to show GuiElement. + * @see IsVisible() + */ +void GuiElement::SetVisible(bool v) +{ + LOCK( this ); + visible = v; +} + +void GuiElement::SetAlpha(int a) +{ + LOCK( this ); + alpha = a; +} + +int GuiElement::GetAlpha() +{ + int a; + + if (alphaDyn >= 0) + a = alphaDyn; + else a = alpha; + + if (parentElement) a *= parentElement->GetAlpha() / 255.0; + + return a; +} + +float GuiElement::GetAngleDyn() +{ + float a = 0.0; + + if (angleDyn) a = angleDyn; + + if (parentElement && !angleDyn) a = parentElement->GetAngleDyn(); + + return a; +} + +void GuiElement::SetScale(float s) +{ + LOCK( this ); + scale = s; +} + +float GuiElement::GetScale() +{ + float s = scale * scaleDyn; + + if (parentElement) s *= parentElement->GetScale(); + + return s; +} + +void GuiElement::SetState(int s, int c) +{ + LOCK( this ); + state = s; + stateChan = c; +} + +void GuiElement::ResetState() +{ + LOCK( this ); + if (state != STATE_DISABLED) + { + state = STATE_DEFAULT; + stateChan = -1; + } +} + +void GuiElement::SetClickable(bool c) +{ + LOCK( this ); + clickable = c; +} + +void GuiElement::SetSelectable(bool s) +{ + LOCK( this ); + selectable = s; +} + +void GuiElement::SetHoldable(bool d) +{ + LOCK( this ); + holdable = d; +} + +bool GuiElement::IsSelectable() +{ + if (state == STATE_DISABLED || state == STATE_CLICKED) + return false; + else return selectable; +} + +bool GuiElement::IsClickable() +{ + if (state == STATE_DISABLED || state == STATE_CLICKED || state == STATE_HELD) + return false; + else return clickable; +} + +bool GuiElement::IsHoldable() +{ + if (state == STATE_DISABLED) + return false; + else return holdable; +} + +void GuiElement::SetTrigger(GuiTrigger * t) +{ + LOCK( this ); + if (!trigger[0]) + trigger[0] = t; + else if (!trigger[1]) + trigger[1] = t; + else if (!trigger[2]) + trigger[2] = t; + else if (!trigger[3]) + trigger[3] = t; + else if (!trigger[4]) + trigger[4] = t; + else if (!trigger[5]) + trigger[5] = t; + else // both were assigned, so we'll just overwrite the first one + trigger[0] = t; +} + +void GuiElement::SetTrigger(u8 i, GuiTrigger * t) +{ + LOCK( this ); + trigger[i] = t; +} + +void GuiElement::RemoveTrigger(u8 i) +{ + LOCK( this ); + trigger[i] = NULL; +} + +void GuiElement::SetRumble(bool r) +{ + LOCK( this ); + rumble = r; +} + +float GuiElement::GetFrequency() +{ + LOCK( this ); + return frequency; +} + +void GuiElement::SetEffect(int eff, int speed, f32 circles, int r, f32 startdegree, f32 anglespeedset, int center_x, + int center_y) +{ + + if (eff & EFFECT_GOROUND) + { + xoffsetDyn = 0; //!position of circle in x + yoffsetDyn = 0; //!position of circle in y + Radius = r; //!radius of the circle + degree = startdegree; //!for example -90 (°) to start at top of circle + circleamount = circles; //!circleamoutn in degrees for example 360 for 1 circle + angleDyn = 0.0f; //!this is used by the code to calc the angle + anglespeed = anglespeedset; //!This is anglespeed depending on circle speed 1 is same speed and 0.5 half speed + temp_xoffset = center_x; //!position of center in x + temp_yoffset = center_y; //!position of center in y + } + effects |= eff; + effectAmount = speed; //!Circlespeed +} + +void GuiElement::SetEffect(int eff, int amount, int target) +{ + LOCK( this ); + if (eff & EFFECT_SLIDE_IN) + { + // these calculations overcompensate a little + if (eff & EFFECT_SLIDE_TOP) + yoffsetDyn = -screenheight; + else if (eff & EFFECT_SLIDE_LEFT) + xoffsetDyn = -screenwidth; + else if (eff & EFFECT_SLIDE_BOTTOM) + yoffsetDyn = screenheight; + else if (eff & EFFECT_SLIDE_RIGHT) xoffsetDyn = screenwidth; + } + + if ((eff & EFFECT_FADE) && amount > 0) + { + alphaDyn = 0; + } + else if ((eff & EFFECT_FADE) && amount < 0) + { + alphaDyn = alpha; + + } + else if (eff & EFFECT_ROCK_VERTICLE) + { + changervar = 0; + yoffsetDyn = 0; + yoffsetDynFloat = 0.0; + } + + effects |= eff; + effectAmount = amount; + effectTarget = target; +} + +void GuiElement::SetEffectOnOver(int eff, int amount, int target) +{ + LOCK( this ); + effectsOver |= eff; + effectAmountOver = amount; + effectTargetOver = target; +} + +void GuiElement::SetEffectGrow() +{ + SetEffectOnOver(EFFECT_SCALE, 4, 110); +} + +void GuiElement::StopEffect() +{ + xoffsetDyn = 0; + yoffsetDyn = 0; + effects = 0; + effectsOver = 0; + effectAmount = 0; + effectAmountOver = 0; + effectTarget = 0; + effectTargetOver = 0; + scaleDyn = 1; + frequency = 0.0f; + changervar = 0; + //angleDyn = 0.0f; + anglespeed = 0.0f; +} + +void GuiElement::UpdateEffects() +{ + LOCK( this ); + + if (effects & (EFFECT_SLIDE_IN | EFFECT_SLIDE_OUT | EFFECT_GOROUND)) + { + if (effects & EFFECT_SLIDE_IN) + { + if (effects & EFFECT_SLIDE_LEFT) + { + xoffsetDyn += effectAmount; + + if (xoffsetDyn >= 0) + { + xoffsetDyn = 0; + effects = 0; + } + } + else if (effects & EFFECT_SLIDE_RIGHT) + { + xoffsetDyn -= effectAmount; + + if (xoffsetDyn <= 0) + { + xoffsetDyn = 0; + effects = 0; + } + } + else if (effects & EFFECT_SLIDE_TOP) + { + yoffsetDyn += effectAmount; + + if (yoffsetDyn >= 0) + { + yoffsetDyn = 0; + effects = 0; + } + } + else if (effects & EFFECT_SLIDE_BOTTOM) + { + yoffsetDyn -= effectAmount; + + if (yoffsetDyn <= 0) + { + yoffsetDyn = 0; + effects = 0; + } + } + } + else + { + if (effects & EFFECT_SLIDE_LEFT) + { + xoffsetDyn -= effectAmount; + + if (xoffsetDyn <= -screenwidth) effects = 0; // shut off effect + } + else if (effects & EFFECT_SLIDE_RIGHT) + { + xoffsetDyn += effectAmount; + + if (xoffsetDyn >= screenwidth) effects = 0; // shut off effect + } + else if (effects & EFFECT_SLIDE_TOP) + { + yoffsetDyn -= effectAmount; + + if (yoffsetDyn <= -screenheight) effects = 0; // shut off effect + } + else if (effects & EFFECT_SLIDE_BOTTOM) + { + yoffsetDyn += effectAmount; + + if (yoffsetDyn >= screenheight) effects = 0; // shut off effect + } + } + } + + if (effects & EFFECT_GOROUND) + { + //!< check out gui.h for info + xoffset = temp_xoffset; + yoffset = temp_yoffset; + if (fabs(frequency) < circleamount) + { + angleDyn = (frequency + degree + 90.0f) * anglespeed; + xoffsetDyn = (int) lround(((f32) Radius) * cosf((frequency + degree) * PI / 180.0f)); + yoffsetDyn = (int) lround(((f32) Radius) * sinf((frequency + degree) * PI / 180.0f)); + frequency += ((f32) effectAmount) * 0.01f; + } + else + { + f32 temp_frequency = ((effectAmount < 0) ? -1.0f : 1.0f) * circleamount; + angleDyn = (temp_frequency + degree + 90.0f) * anglespeed; + xoffsetDyn = (int) lround(((f32) Radius) * cosf((temp_frequency + degree) * PI / 180.0f)); + yoffsetDyn = (int) lround(((f32) Radius) * sinf((temp_frequency + degree) * PI / 180.0f)); + xoffset += xoffsetDyn; + yoffset += yoffsetDyn; + effects ^= EFFECT_GOROUND; + frequency = 0.0f; + } + } + + if (effects & EFFECT_ROCK_VERTICLE) + { + //move up to 10pixel above 0 + if (changervar == 0 && yoffsetDynFloat < 11.0f) + { + yoffsetDynFloat += (effectAmount * 0.01f); + } + else if (yoffsetDynFloat > 10.0f) + { + changervar = 1; + } + //move down till 10pixel under 0 + if (changervar == 1 && yoffsetDynFloat > -11.0f) + { + yoffsetDynFloat -= (effectAmount * 0.01f); + } + else if (yoffsetDynFloat < -10.0f) + { + changervar = 0; + } + yoffsetDyn = (int) (yoffsetDynFloat); + } + + if (effects & EFFECT_FADE) + { + alphaDyn += effectAmount; + + if (effectAmount < 0 && alphaDyn <= 0) + { + alphaDyn = 0; + effects = 0; // shut off effect + } + else if (effectAmount > 0 && alphaDyn >= alpha) + { + alphaDyn = alpha; + effects = 0; // shut off effect + } + } + if (effects & EFFECT_SCALE) + { + scaleDyn += effectAmount / 100.0f; + + if ((effectAmount < 0 && scaleDyn <= effectTarget / 100.0f) || (effectAmount > 0 && scaleDyn >= effectTarget + / 100.0f)) + { + scaleDyn = effectTarget / 100.0f; + effects = 0; // shut off effect + } + } + if (effects & EFFECT_PULSE) + { + int percent = 10; //go down from target by this + + if ((scaleDyn <= (effectTarget * 0.01f)) && (!changervar)) + { + scaleDyn += (effectAmount * 0.001f); + } + else if (scaleDyn > (effectTarget * 0.01f)) + { + changervar = 1; + } + if ((scaleDyn >= ((effectTarget - percent) * 0.01f)) && (changervar)) + { + scaleDyn -= (effectAmount * 0.001f); + } + else if (scaleDyn < ((effectTarget - percent) * 0.01f)) + { + changervar = 0; + } + } +} + +void GuiElement::Update(GuiTrigger * t) +{ + LOCK( this ); + if (updateCB) updateCB(this); +} + +void GuiElement::SetUpdateCallback(UpdateCallback u) +{ + LOCK( this ); + updateCB = u; +} + +void GuiElement::SetPosition(int xoff, int yoff, int zoff) +{ + LOCK( this ); + xoffset = xoff; + yoffset = yoff; + zoffset = zoff; +} + +void GuiElement::SetAlignment(int hor, int vert) +{ + LOCK( this ); + alignmentHor = hor; + alignmentVert = vert; +} + +int GuiElement::GetSelected() +{ + return -1; +} + +/** + * Draw an element on screen. + */ +void GuiElement::Draw() +{ +} + +/** + * Draw Tooltips on screen. + */ +void GuiElement::DrawTooltip() +{ +} + +/** + * Check if a position is inside the GuiElement. + * @param[in] x X position in pixel. + * @param[in] y Y position in pixel. + */ +bool GuiElement::IsInside(int x, int y) +{ + if (x > this->GetLeft() && x < (this->GetLeft() + width) && y > this->GetTop() && y < (this->GetTop() + height)) return true; + return false; +} +void GuiElement::LockElement() +{ + // LWP_MutexLock(mutex); + for (;;) // loop while element is locked by self + { + LWP_MutexLock(_lock_mutex); + + if (_lock_thread == LWP_THREAD_NULL) // element is not locked + { + _lock_thread = LWP_GetSelf(); // mark as locked + _lock_count = 1; // set count of lock to 1 + LWP_MutexUnlock(_lock_mutex); + return; + } + else if (_lock_thread == LWP_GetSelf()) // thread is locked by my self + { + _lock_count++; // inc count of locks; + LWP_MutexUnlock(_lock_mutex); + return; + } + else // otherwise the element is locked by an other thread + { + if (_lock_queue == LWP_TQUEUE_NULL) // no queue - meens it is the first access to the locked element + LWP_InitQueue(&_lock_queue); // init queue + LWP_MutexUnlock(_lock_mutex); + LWP_ThreadSleep(_lock_queue); // and sleep + // try lock again; + } + } +} +void GuiElement::UnlockElement() +{ + // LWP_MutexUnlock(mutex); + LWP_MutexLock(_lock_mutex); + // only the thread was locked this element, can call unlock + if (_lock_thread == LWP_GetSelf()) // but we check it here safe is safe + { + if (--_lock_count == 0) // dec count of locks and check if it last lock; + { + _lock_thread = LWP_THREAD_NULL; // mark as unlocked + if (_lock_queue != LWP_TQUEUE_NULL) // has a queue + { + LWP_CloseQueue(_lock_queue); // close the queue and wake all waited threads + _lock_queue = LWP_TQUEUE_NULL; + } + } + } + LWP_MutexUnlock(_lock_mutex); +} + +SimpleLock::SimpleLock(GuiElement *e) : + element(e) +{ + element->LockElement(); +} +SimpleLock::~SimpleLock() +{ + element->UnlockElement(); +} diff --git a/source/GUI/gui_filebrowser.cpp b/source/GUI/gui_filebrowser.cpp new file mode 100644 index 0000000..cf47fcd --- /dev/null +++ b/source/GUI/gui_filebrowser.cpp @@ -0,0 +1,217 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_filebrowser.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui_filebrowser.h" +#include "prompts/filebrowser.h" +#include "settings/CSettings.h" +#include "themes/CTheme.h" + +/** + * Constructor for the GuiFileBrowser class. + */ +GuiFileBrowser::GuiFileBrowser(int w, int h) + : scrollBar(h-10) +{ + width = w; + height = h; + selectedItem = 0; + selectable = true; + triggerdisabled = false; // trigger disable + + trigA = new GuiTrigger; + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + bgFileSelection = new GuiImageData(Resources::GetFile("bg_browser.png"), Resources::GetFileSize("bg_browser.png")); + bgFileSelectionImg = new GuiImage(bgFileSelection); + bgFileSelectionImg->SetParent(this); + bgFileSelectionImg->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + + bgFileSelectionEntry = Resources::GetImageData("bg_browser_selection.png"); + + fileFolder = Resources::GetImageData("icon_folder.png"); + + scrollBar.SetParent(this); + scrollBar.SetAlignment(ALIGN_RIGHT, ALIGN_TOP); + scrollBar.SetPosition(0, 5); + scrollBar.listChanged.connect(this, &GuiFileBrowser::onListChange); + + for (int i = 0; i < FILEBROWSERSIZE; i++) + { + fileListText[i] = new GuiText((char *) NULL, 20, ( GXColor ) {0, 0, 0, 0xff}); + fileListText[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + fileListText[i]->SetPosition(5, 0); + fileListText[i]->SetMaxWidth(bgFileSelectionImg->GetWidth() - (scrollBar.GetWidth() + 40), DOTTED); + + fileListTextOver[i] = new GuiText((char *) NULL, 20, ( GXColor ) {0, 0, 0, 0xff}); + fileListTextOver[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + fileListTextOver[i]->SetPosition(5, 0); + fileListTextOver[i]->SetMaxWidth(bgFileSelectionImg->GetWidth() - (scrollBar.GetWidth() + 40), SCROLL_HORIZONTAL); + + fileListBg[i] = new GuiImage(bgFileSelectionEntry); + fileListFolder[i] = new GuiImage(fileFolder); + fileList[i] = new GuiButton(350, 30); + fileList[i]->SetParent(this); + fileList[i]->SetLabel(fileListText[i]); + fileList[i]->SetLabelOver(fileListTextOver[i]); + fileList[i]->SetImageOver(fileListBg[i]); + fileList[i]->SetPosition(2, 30 * i + 3); + fileList[i]->SetTrigger(trigA); + fileList[i]->SetRumble(false); + fileList[i]->SetSoundClick(btnSoundClick); + } +} + +/** + * Destructor for the GuiFileBrowser class. + */ +GuiFileBrowser::~GuiFileBrowser() +{ + delete bgFileSelectionImg; + + delete bgFileSelection; + delete bgFileSelectionEntry; + delete fileFolder; + + delete trigA; + + for (int i = 0; i < FILEBROWSERSIZE; i++) + { + delete fileListText[i]; + delete fileListTextOver[i]; + delete fileList[i]; + delete fileListBg[i]; + delete fileListFolder[i]; + } +} + +void GuiFileBrowser::DisableTriggerUpdate(bool set) +{ + LOCK( this ); + triggerdisabled = set; +} + +void GuiFileBrowser::ResetState() +{ + LOCK( this ); + state = STATE_DEFAULT; + stateChan = -1; + selectedItem = 0; + + for (int i = 0; i < FILEBROWSERSIZE; i++) + { + fileList[i]->ResetState(); + } +} + +void GuiFileBrowser::UpdateList() +{ + LOCK( this ); + for (int i = 0; i < FILEBROWSERSIZE; i++) + { + if (browser->pageIndex + i < (int) browser->browserList.size()) + { + if (fileList[i]->GetState() == STATE_DISABLED) + fileList[i]->SetState(STATE_DEFAULT); + + fileList[i]->SetVisible(true); + + fileListText[i]->SetText(browser->browserList[browser->pageIndex + i].displayname); + fileListTextOver[i]->SetText(browser->browserList[browser->pageIndex + i].displayname); + + if (browser->browserList[browser->pageIndex + i].isdir) // directory + { + fileList[i]->SetIcon(fileListFolder[i]); + fileListText[i]->SetPosition(30, 0); + fileListTextOver[i]->SetPosition(30, 0); + } + else + { + fileList[i]->SetIcon(NULL); + fileListText[i]->SetPosition(10, 0); + fileListTextOver[i]->SetPosition(10, 0); + } + } + else + { + fileList[i]->SetVisible(false); + fileList[i]->SetState(STATE_DISABLED); + } + } +} + +void GuiFileBrowser::onListChange(int SelItem, int SelInd) +{ + selectedItem = SelItem; + browser->pageIndex = SelInd; + UpdateList(); +} + +/** + * Draw the button on screen + */ +void GuiFileBrowser::Draw() +{ + LOCK( this ); + if (!this->IsVisible()) return; + + bgFileSelectionImg->Draw(); + + for (int i = 0; i < FILEBROWSERSIZE; i++) + { + fileList[i]->Draw(); + } + + if(browser->browserList.size() > FILEBROWSERSIZE) + scrollBar.Draw(); + + this->UpdateEffects(); +} + +void GuiFileBrowser::Update(GuiTrigger * t) +{ + LOCK( this ); + if (state == STATE_DISABLED || !t || triggerdisabled) + return; + + static int pressedChan = -1; + + if((t->wpad.btns_d & (WPAD_BUTTON_B | WPAD_BUTTON_DOWN | WPAD_BUTTON_UP | WPAD_BUTTON_LEFT | WPAD_BUTTON_RIGHT | + WPAD_CLASSIC_BUTTON_B | WPAD_CLASSIC_BUTTON_UP | WPAD_CLASSIC_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_RIGHT)) || + (t->pad.btns_d & (PAD_BUTTON_UP | PAD_BUTTON_DOWN))) + pressedChan = t->chan; + + if(browser->browserList.size() > FILEBROWSERSIZE) + scrollBar.Update(t); + + if(pressedChan == -1 || (!t->wpad.btns_h && !t->pad.btns_h)) + { + for (int i = 0; i < FILEBROWSERSIZE; i++) + { + if (i != selectedItem && fileList[i]->GetState() == STATE_SELECTED) + fileList[i]->ResetState(); + else if (i == selectedItem && fileList[i]->GetState() == STATE_DEFAULT) + fileList[selectedItem]->SetState(STATE_SELECTED, -1); + + fileList[i]->Update(t); + + if (fileList[i]->GetState() == STATE_SELECTED) + selectedItem = i; + } + } + + + if(pressedChan == t->chan && !t->wpad.btns_d && !t->wpad.btns_h) + pressedChan = -1; + + scrollBar.SetPageSize(FILEBROWSERSIZE); + scrollBar.SetSelectedItem(selectedItem); + scrollBar.SetSelectedIndex(browser->pageIndex); + scrollBar.SetEntrieCount(browser->browserList.size()); +} diff --git a/source/GUI/gui_filebrowser.h b/source/GUI/gui_filebrowser.h new file mode 100644 index 0000000..d055453 --- /dev/null +++ b/source/GUI/gui_filebrowser.h @@ -0,0 +1,40 @@ +#ifndef GUI_FILEBROWSER_H_ +#define GUI_FILEBROWSER_H_ + +#include "gui.h" +#include "gui_scrollbar.hpp" + +//!Display a list of files +class GuiFileBrowser: public GuiElement, public sigslot::has_slots<> +{ + public: + GuiFileBrowser(int w, int h); + virtual ~GuiFileBrowser(); + void DisableTriggerUpdate(bool set); + void ResetState(); + void Draw(); + void UpdateList(); + void Update(GuiTrigger * t); + GuiButton * fileList[PAGESIZE]; + protected: + void onListChange(int SelItem, int SelInd); + int selectedItem; + bool triggerdisabled; + + GuiText * fileListText[PAGESIZE]; + GuiText * fileListTextOver[PAGESIZE]; + GuiImage * fileListBg[PAGESIZE]; + GuiImage * fileListFolder[PAGESIZE]; + + GuiImage * bgFileSelectionImg; + + GuiImageData * bgFileSelection; + GuiImageData * bgFileSelectionEntry; + GuiImageData * fileFolder; + + GuiTrigger * trigA; + GuiScrollbar scrollBar; +}; + + +#endif diff --git a/source/GUI/gui_gamebrowser.h b/source/GUI/gui_gamebrowser.h new file mode 100644 index 0000000..0750f30 --- /dev/null +++ b/source/GUI/gui_gamebrowser.h @@ -0,0 +1,41 @@ + /**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GUIGAMEBROWSER_H_ +#define GUIGAMEBROWSER_H_ + +#include "gui.h" + +class GuiGameBrowser : public GuiElement +{ + public: + GuiGameBrowser() {} + virtual ~GuiGameBrowser() {} + virtual int GetClickedOption() { return -1; } + virtual int GetSelectedOption() { return -1; } + virtual void SetSelectedOption(int ind) {} + virtual void setListOffset(int off) {} + virtual int getListOffset() const { return 0; } +}; + +#endif /* GUIGAMEBROWSER_H_ */ diff --git a/source/GUI/gui_gamecarousel.cpp b/source/GUI/gui_gamecarousel.cpp new file mode 100644 index 0000000..b11830a --- /dev/null +++ b/source/GUI/gui_gamecarousel.cpp @@ -0,0 +1,459 @@ +/**************************************************************************** + * libwiigui + * + * gui_gamecarousel.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" +#include "wpad.h" +#include "menu.h" + +#include +#include "gui_image_async.h" +#include "gui_gamecarousel.h" +#include "usbloader/GameList.h" +#include "settings/GameTitles.h" +#include "settings/CSettings.h" +#include "GUI/LoadCoverImage.h" +#include "themes/CTheme.h" +#include "utils/tools.h" +#include "main.h" + +#include +#include +#include + +#define SCALE 0.8f +#define DEG_OFFSET 7 +#define RADIUS 780 +#define IN_SPEED 175 +#define SHIFT_SPEED 75 +#define SPEED_STEP 4 +#define SPEED_LIMIT 250 + +static inline int OFFSETLIMIT(int Offset, int gameCnt) +{ + while (Offset < 0) + Offset += gameCnt; + return Offset % gameCnt; +} +#define GetGameIndex(pageEntry, listOffset, gameCnt) OFFSETLIMIT(listOffset+pageEntry, gameCnt) +static GuiImageData *GameCarouselLoadCoverImage(void * Arg) +{ + return LoadCoverImage((struct discHdr *) Arg, true, false); +} +/** + * Constructor for the GuiGameCarousel class. + */ +GuiGameCarousel::GuiGameCarousel(int w, int h, const char *themePath, int offset) : + noCover(Resources::GetFile("nocover.png"), Resources::GetFileSize("nocover.png")) +{ + width = w; + height = h; + pagesize = (gameList.size() < 11) ? gameList.size() : 11; + listOffset = (gameList.size() < 11) ? LIMIT(offset, 0, MAX(0, gameList.size()-1)) : LIMIT(offset, 0, MAX(0, gameList.size()-1))-2; + selectable = true; + selectedItem = -1; + clickedItem = -1; + + speed = 0; + + trigA = new GuiTrigger; + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigL = new GuiTrigger; + trigL->SetButtonOnlyTrigger(-1, WPAD_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_LEFT, PAD_BUTTON_LEFT); + trigR = new GuiTrigger; + trigR->SetButtonOnlyTrigger(-1, WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT, PAD_BUTTON_RIGHT); + trigPlus = new GuiTrigger; + trigPlus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_PLUS | WPAD_CLASSIC_BUTTON_PLUS, PAD_TRIGGER_R); + trigMinus = new GuiTrigger; + trigMinus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, PAD_TRIGGER_L); + + imgLeft = Resources::GetImageData("startgame_arrow_left.png"); + imgRight = Resources::GetImageData("startgame_arrow_right.png"); + + btnLeftImg = new GuiImage(imgLeft); + if (Settings.wsprompt == ON) btnLeftImg->SetWidescreen(Settings.widescreen); + btnLeft = new GuiButton(imgLeft->GetWidth(), imgLeft->GetHeight()); + btnLeft->SetAlignment(thAlign("left - carousel layout left arrow align hor"), thAlign("top - carousel layout left arrow align ver")); + btnLeft->SetPosition(thInt("20 - carousel layout left arrow pos x"), thInt("65 - carousel layout left arrow pos y")); + btnLeft->SetParent(this); + btnLeft->SetImage(btnLeftImg); + btnLeft->SetSoundOver(btnSoundOver); + btnLeft->SetTrigger(trigA); + btnLeft->SetTrigger(trigL); + btnLeft->SetTrigger(trigMinus); + btnLeft->SetEffectGrow(); + + btnRightImg = new GuiImage(imgRight); + if (Settings.wsprompt == ON) btnRightImg->SetWidescreen(Settings.widescreen); + btnRight = new GuiButton(imgRight->GetWidth(), imgRight->GetHeight()); + btnRight->SetParent(this); + btnRight->SetAlignment(thAlign("right - carousel layout right arrow align hor"), thAlign("top - carousel layout right arrow align ver")); + btnRight->SetPosition(thInt("-20 - carousel layout right arrow pos x"), thInt("65 - carousel layout right arrow pos y")); + btnRight->SetImage(btnRightImg); + btnRight->SetSoundOver(btnSoundOver); + btnRight->SetTrigger(trigA); + btnRight->SetTrigger(trigR); + btnRight->SetTrigger(trigPlus); + btnRight->SetEffectGrow(); + + gamename = new GuiText(" ", 18, thColor("r=55 g=190 b=237 a=255 - carousel game name text color")); + gamename->SetParent(this); + gamename->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + gamename->SetPosition(0, 330); + gamename->SetMaxWidth(280, DOTTED); + + gameIndex = new int[pagesize]; + game.resize(pagesize); + coverImg.resize(pagesize); + + Refresh(); +} + +/** + * Destructor for the GuiGameCarousel class. + */ +GuiGameCarousel::~GuiGameCarousel() +{ + delete imgRight; + delete imgLeft; + delete btnLeftImg; + delete btnRightImg; + delete btnRight; + delete btnLeft; + + delete trigA; + delete trigL; + delete trigR; + delete trigPlus; + delete trigMinus; + delete gamename; + + GuiImageAsync::ClearQueue(); + + for (u32 i = 0; i < game.size(); ++i) + delete coverImg[i]; + for (u32 i = 0; i < game.size(); ++i) + delete game[i]; + + delete[] gameIndex; + +} + +void GuiGameCarousel::setListOffset(int off) +{ + LOCK( this ); + if(gameList.size() < 11) + listOffset = MIN(off, gameList.size()-1); + else + listOffset = MIN(off, gameList.size()) - 2; + + Refresh(); +} + +int GuiGameCarousel::getListOffset() const +{ + if(gameList.size() < 11) + return listOffset; + else + return (listOffset + 2) % gameList.size(); +} + +void GuiGameCarousel::SetSelectedOption(int ind) +{ + LOCK(this); + selectedItem = LIMIT(ind, 0, MIN(pagesize, MAX(0, gameList.size()-1))); +} + +void GuiGameCarousel::Refresh() +{ + for (int i = 0; i < pagesize; i++) + { + //------------------------ + // Index + //------------------------ + gameIndex[i] = GetGameIndex( i, listOffset, gameList.size() ); + + //------------------------ + // Image + //------------------------ + delete coverImg[i]; + coverImg[i] = new (std::nothrow) GuiImageAsync(GameCarouselLoadCoverImage, gameList[gameIndex[i]], sizeof(struct discHdr), &noCover); + if (coverImg[i]) coverImg[i]->SetWidescreen(Settings.widescreen); + + //------------------------ + // GameButton + //------------------------ + delete game[i]; + game[i] = new GuiButton(122, 244); + game[i]->SetParent(this); + game[i]->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + game[i]->SetPosition(0, 740); + game[i]->SetImage(coverImg[i]); + game[i]->SetScale(SCALE); + game[i]->SetRumble(false); + game[i]->SetTrigger(trigA); + game[i]->SetSoundClick(btnSoundClick); + game[i]->SetClickable(true); + game[i]->SetEffect(EFFECT_GOROUND, IN_SPEED, 90 - (pagesize - 2 * i - 1) * DEG_OFFSET / 2, RADIUS, 180, 1, 0, RADIUS); + } +} + +void GuiGameCarousel::SetFocus(int f) +{ + LOCK( this ); + if (!gameList.size()) return; + + for (int i = 0; i < pagesize; i++) + game[i]->ResetState(); + + if (f == 1 && selectedItem >= 0) game[selectedItem]->SetState(STATE_SELECTED); +} + +void GuiGameCarousel::ResetState() +{ + LOCK( this ); + if (state != STATE_DISABLED) + { + state = STATE_DEFAULT; + stateChan = -1; + } + + for (int i = 0; i < pagesize; i++) + { + game[i]->ResetState(); + } +} + +int GuiGameCarousel::GetClickedOption() +{ + LOCK( this ); + int found = -1; + if (clickedItem >= 0) + { + for (int i = pagesize - 1; i >= 0; i--) + game[i]->ResetState(); + + game[clickedItem]->SetState(STATE_SELECTED); + found = gameIndex[clickedItem]; + clickedItem = -1; + } + return found; +} + +int GuiGameCarousel::GetSelectedOption() +{ + LOCK( this ); + int found = -1; + for (int i = 0; i < pagesize; i++) + { + if (game[i]->GetState() == STATE_SELECTED) + { + game[i]->SetState(STATE_SELECTED); + found = gameIndex[i]; + break; + } + } + return found; +} + +/** + * Draw the button on screen + */ +void GuiGameCarousel::Draw() +{ + LOCK( this ); + if (!this->IsVisible() || !gameList.size()) return; + + for (int i = 0; i < pagesize; i++) + game[i]->Draw(); + + gamename->Draw(); + + if (gameList.size() > 6) + { + btnRight->Draw(); + btnLeft->Draw(); + } + + //!Draw tooltip after the Images to have it on top + if (Settings.tooltips == ON) + for (int i = 0; i < pagesize; i++) + game[i]->DrawTooltip(); + + this->UpdateEffects(); +} + +void GuiGameCarousel::Update(GuiTrigger * t) +{ + LOCK( this ); + if (state == STATE_DISABLED || !t || !gameList.size() || !pagesize) return; + + btnRight->Update(t); + btnLeft->Update(t); + + if ((game[0]->GetEffect() & EFFECT_GOROUND) || (game[pagesize - 1]->GetEffect() & EFFECT_GOROUND)) + { + return; // skip when rotate + } + + // find selected + clicked + int selectedItem_old = selectedItem; + selectedItem = -1; + clickedItem = -1; + for (int i = pagesize - 1; i >= 0; i--) + { + game[i]->Update(t); + if (game[i]->GetState() == STATE_SELECTED) + { + selectedItem = i; + } + if (game[i]->GetState() == STATE_CLICKED) + { + clickedItem = i; + } + + } + + /// OnOver-Effect + GameText + Tooltop + if (selectedItem_old != selectedItem) + { + if (selectedItem >= 0) + { + game[selectedItem]->SetEffect(EFFECT_SCALE, 1, 130); + gamename->SetText(GameTitles.GetTitle(gameList[gameIndex[selectedItem]])); + } + else gamename->SetText((char*) NULL); + if (selectedItem_old >= 0) game[selectedItem_old]->SetEffect(EFFECT_SCALE, -1, 100); + } + // navigation + if (gameList.size() > 6) + { + + int newspeed = 0; + // Left/Right Navigation + if (btnLeft->GetState() == STATE_CLICKED) + { + u32 buttons = t->wpad.btns_h; + u32 buttonsPAD = t->pad.btns_h; + if (!((buttons & WPAD_BUTTON_A) || (buttons & WPAD_BUTTON_MINUS) || + (buttons & WPAD_CLASSIC_BUTTON_A) || (buttons & WPAD_CLASSIC_BUTTON_MINUS) || + (buttonsPAD & PAD_BUTTON_A) || (buttonsPAD & PAD_TRIGGER_L) || t->Left())) + { + btnLeft->ResetState(); + return; + } + + if (Settings.xflip == XFLIP_SYSMENU || Settings.xflip == XFLIP_YES || Settings.xflip == XFLIP_DISK3D) + newspeed = SHIFT_SPEED; + else newspeed = -SHIFT_SPEED; + } + else if (btnRight->GetState() == STATE_CLICKED) + { + u32 buttons = t->wpad.btns_h; + u32 buttonsPAD = t->pad.btns_h; + if (!((buttons & WPAD_BUTTON_A) || (buttons & WPAD_BUTTON_PLUS) || + (buttons & WPAD_CLASSIC_BUTTON_A) || (buttons & WPAD_CLASSIC_BUTTON_PLUS) || + (buttonsPAD & PAD_BUTTON_A) || (buttonsPAD & PAD_TRIGGER_R) || t->Right())) + { + btnRight->ResetState(); + return; + } + if (Settings.xflip == XFLIP_SYSMENU || Settings.xflip == XFLIP_YES || Settings.xflip == XFLIP_DISK3D) + newspeed = -SHIFT_SPEED; + else newspeed = SHIFT_SPEED; + } + if (newspeed) + { + if (speed == 0) + speed = newspeed; + else if (speed > 0) + { + if ((speed += SPEED_STEP) > SPEED_LIMIT) speed = SPEED_LIMIT; + } + else + { + if ((speed -= SPEED_STEP) < -SPEED_LIMIT) speed = -SPEED_LIMIT; + } + } + else speed = 0; + + if (speed > 0) // rotate right + { + GuiButton *tmpButton; + listOffset = OFFSETLIMIT(listOffset - 1, gameList.size()); // set the new listOffset + // Save right Button + TollTip and destroy right Image + Image-Data + delete coverImg[pagesize - 1]; + coverImg[pagesize - 1] = NULL; + game[pagesize - 1]->SetImage(NULL); + tmpButton = game[pagesize - 1]; + + // Move all Page-Entries one step right + for (int i = pagesize - 1; i >= 1; i--) + { + coverImg[i] = coverImg[i - 1]; + game[i] = game[i - 1]; + gameIndex[i] = gameIndex[i - 1]; + } + // set saved Button & gameIndex to right + gameIndex[0] = listOffset; + coverImg[0] = new GuiImageAsync(GameCarouselLoadCoverImage, gameList[gameIndex[0]], sizeof(struct discHdr), + &noCover); + coverImg[0] ->SetWidescreen(Settings.widescreen); + + game[0] = tmpButton; + game[0] ->SetImage(coverImg[0]); + + for (int i = 0; i < pagesize; i++) + { + game[i]->StopEffect(); + game[i]->ResetState(); + game[i]->SetEffect(EFFECT_GOROUND, speed, DEG_OFFSET, RADIUS, 270 - (pagesize - 2 * i + 1) * DEG_OFFSET + / 2, 1, 0, RADIUS); + game[i]->UpdateEffects(); // rotate one step for liquid scrolling + } + } + else if (speed < 0) // rotate left + { + GuiButton *tmpButton; + listOffset = OFFSETLIMIT(listOffset + 1, gameList.size()); // set the new listOffset + // Save left Button + TollTip and destroy left Image + Image-Data + delete coverImg[0]; + coverImg[0] = NULL; + game[0]->SetImage(NULL); + tmpButton = game[0]; + + // Move all Page-Entries one step left + for (int i = 0; i < (pagesize - 1); i++) + { + coverImg[i] = coverImg[i + 1]; + game[i] = game[i + 1]; + gameIndex[i] = gameIndex[i + 1]; + } + // set saved Button & gameIndex to right + int ii = pagesize - 1; + gameIndex[ii] = OFFSETLIMIT(listOffset + ii, gameList.size()); + coverImg[ii] = new GuiImageAsync(GameCarouselLoadCoverImage, gameList[gameIndex[ii]], + sizeof(struct discHdr), &noCover); + coverImg[ii] ->SetWidescreen(Settings.widescreen); + + game[ii] = tmpButton; + game[ii] ->SetImage(coverImg[ii]); + + for (int i = 0; i < pagesize; i++) + { + game[i]->StopEffect(); + game[i]->ResetState(); + game[i]->SetEffect(EFFECT_GOROUND, speed, DEG_OFFSET, RADIUS, 270 - (pagesize - 2 * i - 3) * DEG_OFFSET + / 2, 1, 0, RADIUS); + game[i]->UpdateEffects(); // rotate one step for liquid scrolling + } + } + + } + if (updateCB) updateCB(this); +} + diff --git a/source/GUI/gui_gamecarousel.h b/source/GUI/gui_gamecarousel.h new file mode 100644 index 0000000..c4d6b00 --- /dev/null +++ b/source/GUI/gui_gamecarousel.h @@ -0,0 +1,55 @@ +#ifndef _GUIGAMECAROUSEL_H_ +#define _GUIGAMECAROUSEL_H_ + +#include +#include "gui_gamebrowser.h" +#include "gui_image_async.h" +#include "usbloader/disc.h" + +class GuiGameCarousel : public GuiGameBrowser +{ + public: + GuiGameCarousel(int w, int h, const char *themePath, int listOffset = 0); + virtual ~GuiGameCarousel(); + int FindMenuItem(int c, int d); + int GetClickedOption(); + int GetSelectedOption(); + void SetSelectedOption(int ind); + void setListOffset(int off); + int getListOffset() const; + void Refresh(); + void ResetState(); + void SetFocus(int f); + void Draw(); + void Update(GuiTrigger * t); + protected: + GuiImageData noCover; + int selectedItem; + int listOffset; + int scrollbaron; + int pagesize; + int speed; + int clickedItem; + + int * gameIndex; + std::vector game; + std::vector coverImg; + + GuiText * gamename; + + GuiButton * btnRight; + GuiButton * btnLeft; + + GuiImage * btnLeftImg; + GuiImage * btnRightImg; + + GuiImageData * imgLeft; + GuiImageData * imgRight; + + GuiTrigger * trigA; + GuiTrigger * trigL; + GuiTrigger * trigR; + GuiTrigger * trigPlus; + GuiTrigger * trigMinus; +}; +#endif diff --git a/source/GUI/gui_gamegrid.cpp b/source/GUI/gui_gamegrid.cpp new file mode 100644 index 0000000..f2aad17 --- /dev/null +++ b/source/GUI/gui_gamegrid.cpp @@ -0,0 +1,845 @@ +/**************************************************************************** + * libwiigui + * + * gui_gameGrid.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" +#include "wpad.h" + +#include +#include "gui_gamegrid.h" +#include "gui_image_async.h" +#include "GUI/LoadCoverImage.h" +#include "usbloader/GameList.h" +#include "settings/GameTitles.h" +#include "settings/CSettings.h" +#include "themes/CTheme.h" +#include "prompts/PromptWindows.h" +#include "language/gettext.h" +#include "utils/tools.h" +#include "menu.h" + +#include +#include +#include + +//#define SCALE 0.8f +//#define DEG_OFFSET 7 +#define RADIUS 780 +//#define IN_SPEED 175 +//#define SHIFT_SPEED 100 +//#define SPEED_STEP 4 +//#define SAFETY 320 +#define goSteps 10 +#include "../main.h" + +static int Skew1[7][8] = { { -14, -66, 14, -34, 14, 34, -14, 66 }, { -10, -44, 10, -26, 10, 26, -10, 44 }, { -6, -22, + 6, -14, 6, 14, -6, 22 }, { 0, -11, 0, -11, 0, 11, 0, 11 }, { -6, -14, 6, -22, 6, 22, -6, 14 }, { -10, -26, 10, + -44, 10, 44, -10, 26 }, { -14, -34, 14, -66, 14, 66, -14, 34 } }; +static int Pos1[7][2][2] = { +// {{16:9 x,y},{ 4:3 x,y}} + { { -230, 74 }, { -320, 74 } }, { { -70, 74 }, { -130, 74 } }, { { 88, 74 }, { 60, 74 } }, { { 239, 74 }, { + 239, 74 } }, { { 390, 74 }, { 420, 74 } }, { { 550, 74 }, { 612, 74 } }, { { 710, 74 }, { 772, 74 } } }; +static int Skew2[18][8] = { { -5, -49, 5, -27, 5, 0, -5, 0 }, { -5, 0, 5, 0, 5, 27, -5, 49 }, + +{ -5, -49, 5, -27, 5, 0, -5, 0 }, { -5, 0, 5, 0, 5, 27, -5, 49 }, + +{ -4, -22, 4, -14, 4, 0, -4, 0 }, { -4, 0, 4, 0, 4, 14, -4, 22 }, + +{ 0, -9, 0, -5, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 5, 0, 9 }, + +{ 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, + +{ 0, -5, 0, -9, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 9, 0, 5 }, + +{ -4, -14, 4, -22, 4, 0, -4, 0 }, { -4, 0, 4, 0, 4, 22, -4, 14 }, + +{ -5, -27, 5, -49, 5, 0, -5, 0 }, { -5, 0, 5, 0, 5, 49, -5, 27 }, + +{ -5, -27, 5, -49, 5, 0, -5, 0 }, { -5, 0, 5, 0, 5, 49, -5, 27 } }; +static int Pos2[18][2][2] = { +// {{16:9 x,y},{ 4:3 x,y}} + { { -91, 50 }, { -166, 50 } }, { { -91, 193 }, { -166, 193 } }, + + { { 3, 50 }, { -54, 50 } }, { { 3, 193 }, { -54, 193 } }, + + { { 97, 50 }, { 58, 50 } }, { { 97, 193 }, { 58, 193 } }, + + { { 187, 50 }, { 166, 50 } }, { { 187, 193 }, { 166, 193 } }, + + { { 272, 50 }, { 272, 50 } }, { { 272, 193 }, { 272, 193 } }, + + { { 358, 50 }, { 378, 50 } }, { { 358, 193 }, { 378, 193 } }, + + { { 449, 50 }, { 487, 50 } }, { { 449, 193 }, { 487, 193 } }, + + { { 545, 50 }, { 599, 50 } }, { { 545, 193 }, { 599, 193 } }, + + { { 641, 50 }, { 700, 50 } }, { { 641, 193 }, { 700, 193 } } }; +static int Skew3[45][8] = { { -38, -110, 15, -42, 15, 65, -38, 32 }, { -38, -75, 15, -48, 15, 45, -38, 72 }, { -38, + -52, 15, -70, 15, 27, -38, 100 }, + +{ -38, -110, 15, -42, 15, 65, -38, 32 }, { -38, -75, 15, -48, 15, 45, -38, 72 }, + { -38, -52, 15, -70, 15, 27, -38, 100 }, + + { -38, -70, 15, -24, 15, 40, -38, 27 }, { -38, -50, 15, -35, 15, 40, -38, 50 }, { -38, -34, 15, -47, 15, 24, + -38, 58 }, + + { -27, -55, 19, -22, 19, 30, -27, 22 }, { -27, -40, 19, -30, 19, 30, -27, 40 }, { -27, -20, 19, -30, 19, 20, + -27, 50 }, + + { -19, -28, 0, -17, 0, 15, -19, 10 }, { -19, -30, 0, -20, 0, 12, -19, 30 }, + { -19, -15, 0, -20, 0, 10, -19, 24 }, + + { -10, -20, 3, -13, 3, 14, -10, 10 }, { -10, -20, 3, -18, 3, 18, -10, 20 }, + { -10, -10, 3, -10, 3, 0, -10, 10 }, + + { -10, -15, 3, -12, 3, 13, -10, 13 }, + { -10, -17, 3, -10, 3, 10, -10, 17 }, + { -10, -10, 3, -15, 3, 10, -10, 10 }, + + { -10, -10, 3, -10, 3, 14, -10, 14 }, + { -10, -10, 3, -10, 3, 10, -10, 10 },//middle + { -10, -10, 3, -10, 3, 10, -10, 10 }, + + { -14, -10, 4, -20, 3, 10, -14, 10 }, { -14, -10, 4, -17, 3, 17, -14, 10 }, + { -14, -10, 4, -10, 3, 10, -14, 10 }, + + { -10, -13, 3, -20, 3, 14, -10, 10 }, { -10, -18, 3, -20, 3, 20, -10, 18 }, + { -10, -10, 3, -10, 3, 20, -10, 5 }, + + { -19, -17, 0, -28, 0, 10, -19, 15 }, { -19, -20, 0, -30, 0, 30, -19, 12 }, + { -19, -20, 0, -15, 0, 30, -19, 10 }, + + { -27, -22, 19, -55, 19, 22, -27, 30 }, { -27, -30, 19, -40, 19, 40, -27, 30 }, { -27, -30, 19, -20, 19, 55, + -27, 20 }, + + { -38, -24, 15, -70, 15, 27, -38, 40 }, { -38, -35, 15, -50, 15, 50, -38, 40 }, { -38, -47, 15, -34, 15, 58, + -38, 24 }, + + { -38, -42, 15, -110, 15, 32, -38, 60 }, { -38, -48, 15, -75, 15, 70, -38, 45 }, { -38, -70, 15, -52, 15, 100, + -38, 27 }, + + { -38, -42, 15, -110, 15, 32, -38, 60 }, { -38, -48, 15, -75, 15, 70, -38, 45 }, { -38, -70, 15, -52, 15, 100, + -38, 27 } }; +static int Pos3[45][2][2] = { +// {{16:9 x,y},{ 4:3 x,y}} + { { -42, 49 }, { -91, 49 } }, { { -42, 153 }, { -91, 153 } }, { { -42, 261 }, { -91, 261 } }, + + { { 13, 58 }, { -29, 58 } }, { { 13, 153 }, { -29, 153 } }, { { 13, 250 }, { -29, 250 } }, + + { { 68, 67 }, { 33, 67 } }, { { 68, 153 }, { 33, 153 } }, { { 68, 239 }, { 33, 239 } }, + + { { 120, 74 }, { 92, 74 } }, { { 120, 153 }, { 92, 153 } }, { { 120, 232 }, { 92, 232 } }, + + { { 170, 78 }, { 149, 78 } }, { { 170, 153 }, { 149, 153 } }, { { 170, 228 }, { 149, 228 } }, + + { { 214, 80 }, { 200, 80 } }, { { 214, 153 }, { 200, 153 } }, { { 214, 226 }, { 200, 226 } }, + + { { 258, 81 }, { 251, 81 } }, { { 258, 153 }, { 251, 153 } }, { { 258, 224 }, { 251, 224 } }, + + { { 302, 81 }, { 302, 81 } }, { { 302, 153 }, { 302, 153 } }, { { 302, 223 }, { 302, 223 } }, + + { { 346, 81 }, { 353, 81 } }, { { 346, 153 }, { 353, 153 } }, { { 346, 223 }, { 353, 223 } }, + + { { 390, 80 }, { 404, 80 } }, { { 390, 153 }, { 404, 153 } }, { { 390, 225 }, { 404, 225 } }, + + { { 434, 77 }, { 457, 77 } }, { { 434, 153 }, { 457, 153 } }, { { 434, 227 }, { 457, 227 } }, + + { { 484, 73 }, { 512, 73 } }, { { 484, 153 }, { 512, 153 } }, { { 484, 231 }, { 512, 231 } }, + + { { 537, 67 }, { 572, 67 } }, { { 537, 153 }, { 572, 153 } }, { { 537, 239 }, { 572, 239 } }, + + { { 591, 58 }, { 633, 58 } }, { { 591, 153 }, { 633, 153 } }, { { 591, 250 }, { 633, 250 } }, + + { { 660, 58 }, { 660, 58 } }, { { 660, 153 }, { 660, 153 } }, { { 660, 250 }, { 660, 250 } } + +}; +#define VALUE4ROWS(rows, val1, val2, val3) (rows==3 ? val3 : (rows==2 ? val2 : val1)) +#define ROWS2PAGESIZE(rows) (rows==3 ? 45 : (rows==2 ? 18 : 7)) +static inline int OFFSETLIMIT(int Offset, int rows, int gameCnt) +{ + gameCnt += (rows - (gameCnt % rows)) % rows; // add count of skiped Entries at end if List + while (Offset > gameCnt) + Offset -= gameCnt; + while (Offset < 0) + Offset += gameCnt; + return Offset; +} + +// Help-Function to Calc GameIndex +static int GetGameIndex(int pageEntry, int rows, int listOffset, int gameCnt) +{ + int skip = (rows - (gameCnt % rows)) % rows; // count of skiped Entries at end if List + int pagesize = ROWS2PAGESIZE( rows ); + + if (gameCnt < (pagesize - 3 * rows)) + { + int listStart = (pagesize - gameCnt) >> 1; // align list on the center + listStart = listStart - (listStart % rows); // align listStart to the top row + if (pageEntry < listStart || pageEntry >= listStart + gameCnt) return -1; + return pageEntry - listStart; + } + else + { + listOffset = listOffset - (listOffset % rows); // align listOffset to the top row + listOffset = listOffset - 3 * rows; // align listOffset to the left full visible column + if (listOffset < 0) listOffset += gameCnt + skip; // set the correct Offset + pageEntry = (listOffset + pageEntry) % (gameCnt + skip); // get offset of pageEntry + if (pageEntry >= gameCnt) return -1; + return pageEntry; + } +} +static GuiImageData *GameGridLoadCoverImage(void * Arg) +{ + return LoadCoverImage((struct discHdr *) Arg, false, false); +} +/** + * Constructor for the GuiGamegrid class. + */ +GuiGameGrid::GuiGameGrid(int w, int h, const char *themePath, int offset) : + noCover(Resources::GetFile("nocoverFlat.png"), Resources::GetFileSize("nocoverFlat.png")) +{ + width = w; + height = h; + listOffset = LIMIT(offset, 0, MAX(0, gameList.size()-1)); + theme_posX = thInt("0 - game grid layout pos x"); + theme_posY = thInt("20 - game grid layout pos y"); + + selectable = true; + + trigA = new GuiTrigger; + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigL = new GuiTrigger; + trigL->SetButtonOnlyTrigger(-1, WPAD_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_LEFT, PAD_BUTTON_LEFT); + trigR = new GuiTrigger; + trigR->SetButtonOnlyTrigger(-1, WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT, PAD_BUTTON_RIGHT); + trig1 = new GuiTrigger; + trig1->SetButtonOnlyTrigger(-1, WPAD_BUTTON_UP | WPAD_CLASSIC_BUTTON_UP, PAD_BUTTON_UP); + trig2 = new GuiTrigger; + trig2->SetButtonOnlyTrigger(-1, WPAD_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_DOWN, PAD_BUTTON_DOWN); + trigPlus = new GuiTrigger; + trigPlus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_PLUS | WPAD_CLASSIC_BUTTON_PLUS, PAD_TRIGGER_R); + trigMinus = new GuiTrigger; + trigMinus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, PAD_TRIGGER_L); + + int btnHeight = (int) lround(sqrt(RADIUS * RADIUS - 90000) - RADIUS - 50); + + // Button Left + btnLeft = new GuiButton(0, 0); + btnLeft->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + btnLeft->SetPosition(20, btnHeight); + btnLeft->SetParent(this); + btnLeft->SetSoundOver(btnSoundOver); + btnLeft->SetTrigger(trigL); + btnLeft->SetTrigger(trigMinus); + + // Button Right + btnRight = new GuiButton(0, 0); + btnRight->SetParent(this); + btnRight->SetAlignment(ALIGN_RIGHT, ALIGN_MIDDLE); + btnRight->SetPosition(-20, btnHeight); + btnRight->SetSoundOver(btnSoundOver); + btnRight->SetTrigger(trigR); + btnRight->SetTrigger(trigPlus); + + // Button RowUp + btnRowUp = new GuiButton(0, 0); + btnRowUp->SetParent(this); + btnRowUp->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + btnRowUp->SetPosition(0, 0); + btnRowUp->SetTrigger(trig2); + + // Button RowDown + btnRowDown = new GuiButton(0, 0); + btnRowDown->SetParent(this); + btnRowDown->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + btnRowDown->SetPosition(0, 0); + btnRowDown->SetTrigger(trig1); + + Reload(Settings.gridRows, listOffset); +} + +/** + * Destructor for the GuiGameGrid class. + */ +GuiGameGrid::~GuiGameGrid() +{ + + delete btnRight; + delete btnLeft; + delete btnRowUp; + delete btnRowDown; + + delete trigA; + delete trigL; + delete trigR; + delete trigPlus; + delete trigMinus; + delete trig1; + delete trig2; + + GuiImageAsync::ClearQueue(); + + for (u32 i = 0; i < game.size(); ++i) + delete game[i]; + + for (u32 i = 0; i < coverImg.size(); ++i) + delete coverImg[i]; + + for (u32 i = 0; i < titleTT.size(); ++i) + delete titleTT[i]; + + game.clear(); + coverImg.clear(); + titleTT.clear(); + gameIndex.clear(); +} + +void GuiGameGrid::SetFocus(int f) +{ + LOCK( this ); + + for (u32 i = 0; i < game.size(); i++) + game[i]->ResetState(); + + if (f == 1 && selectedItem >= 0 && selectedItem < (int) game.size()) + game[selectedItem]->SetState(STATE_SELECTED); +} + +void GuiGameGrid::ResetState() +{ + LOCK( this ); + if (state != STATE_DISABLED) + { + state = STATE_DEFAULT; + stateChan = -1; + } + + for (u32 i = 0; i < game.size(); i++) + { + game[i]->ResetState(); + } +} + +int GuiGameGrid::GetClickedOption() +{ + LOCK( this ); + int found = -1; + if (clickedItem >= 0 && clickedItem < (int) game.size()) + { + game[clickedItem]->SetState(STATE_SELECTED); + found = gameIndex[clickedItem]; + clickedItem = -1; + } + return found; +} + +int GuiGameGrid::GetSelectedOption() +{ + LOCK( this ); + int found = -1; + for (u32 i = 0; i < game.size(); i++) + { + if (game[i]->GetState() == STATE_SELECTED) + { + game[i]->SetState(STATE_SELECTED); + found = gameIndex[i]; + break; + } + } + return found; +} + +void GuiGameGrid::SetSelectedOption(int ind) +{ + LOCK(this); + selectedItem = LIMIT(ind, 0, MIN(pagesize, MAX(0, gameList.size()-1))); +} + +/** + * Draw the button on screen + */ +void GuiGameGrid::Draw() +{ + LOCK( this ); + if (!this->IsVisible() || !gameList.size() || !game.size()) return; + + if (goLeft > 0) + { + goLeft--; + int wsi = Settings.widescreen ? 0 : 1; + float f2 = ((float) goLeft) / goSteps; + float f1 = 1.0 - f2; + int (*Pos)[2][2] = VALUE4ROWS( rows, Pos1, Pos2, Pos3 ); + int (*Skew)[8] = VALUE4ROWS( rows, Skew1, Skew2, Skew3 ); + + for (int i = 0; i < pagesize - rows; i++) + { + game[i]->SetPosition(Pos[i][wsi][0] * f1 + Pos[i + rows][wsi][0] * f2 + theme_posX, Pos[i][wsi][1] + * f1 + Pos[i + rows][wsi][1] * f2 + theme_posY); + + game[i]->SetSkew(Skew[i][0] * f1 + Skew[i + rows][0] * f2, Skew[i][1] * f1 + Skew[i + rows][1] * f2, + Skew[i][2] * f1 + Skew[i + rows][2] * f2, Skew[i][3] * f1 + Skew[i + rows][3] * f2, Skew[i][4] * f1 + + Skew[i + rows][4] * f2, Skew[i][5] * f1 + Skew[i + rows][5] * f2, Skew[i][6] * f1 + + Skew[i + rows][6] * f2, Skew[i][7] * f1 + Skew[i + rows][7] * f2); + } + } + else if (goRight > 0) + { + goRight--; + int wsi = Settings.widescreen ? 0 : 1; + float f2 = ((float) goRight) / goSteps; + float f1 = 1.0 - f2; + int (*Pos)[2][2] = VALUE4ROWS( rows, Pos1, Pos2, Pos3 ); + int (*Skew)[8] = VALUE4ROWS( rows, Skew1, Skew2, Skew3 ); + for (int i = rows; i < pagesize; i++) + { + game[i]->SetPosition(Pos[i][wsi][0] * f1 + Pos[i - rows][wsi][0] * f2 + theme_posX, Pos[i][wsi][1] + * f1 + Pos[i - rows][wsi][1] * f2 + theme_posY); + + game[i]->SetSkew(Skew[i][0] * f1 + Skew[i - rows][0] * f2, Skew[i][1] * f1 + Skew[i - rows][1] * f2, + Skew[i][2] * f1 + Skew[i - rows][2] * f2, Skew[i][3] * f1 + Skew[i - rows][3] * f2, Skew[i][4] * f1 + + Skew[i - rows][4] * f2, Skew[i][5] * f1 + Skew[i - rows][5] * f2, Skew[i][6] * f1 + + Skew[i - rows][6] * f2, Skew[i][7] * f1 + Skew[i - rows][7] * f2); + } + } + + for (int i = 0; i < pagesize; i++) + game[i]->Draw(); + if (gameList.size() > pagesize - 2 * rows) + { + btnRight->Draw(); + btnLeft->Draw(); + } + + btnRowUp->Draw(); + btnRowDown->Draw(); + + if (Settings.tooltips == ON) + for (int i = 0; i < pagesize; i++) + game[i]->DrawTooltip(); + + this->UpdateEffects(); +} + +/** + * Change the number of rows + */ +void GuiGameGrid::ChangeRows(int n) +{ + if (n != rows) Reload(n, -1); +} + +void GuiGameGrid::Update(GuiTrigger * t) +{ + if (state == STATE_DISABLED || !t || !gameList.size() || !game.size()) return; + + LOCK( this ); + if (!(game[0]->GetEffect() || game[0]->GetEffectOnOver())) + { + for (int i = 0; i < pagesize; i++) + game[i]->SetEffectGrow(); + } + + btnRight->Update(t); + btnLeft->Update(t); + btnRowUp->Update(t); + btnRowDown->Update(t); + + selectedItem = -1; + clickedItem = -1; + for (int i = 0; i < pagesize; i++) + { + game[i]->Update(t); + if (game[i]->GetState() == STATE_SELECTED) + { + selectedItem = i; + } + if (game[i]->GetState() == STATE_CLICKED) + { + clickedItem = i; + } + + } + // navigation + if (gameList.size() >= (pagesize - 3 * rows) && goLeft == 0 && goRight == 0) + { + // Left/Right Navigation + + if (btnLeft->GetState() == STATE_CLICKED) + { + u32 buttons = t->wpad.btns_h; + u32 buttonsPAD = t->pad.btns_h; + if (!((buttons & WPAD_BUTTON_A) || (buttons & WPAD_BUTTON_MINUS) || + (buttons & WPAD_CLASSIC_BUTTON_A) || (buttons & WPAD_CLASSIC_BUTTON_MINUS) || + (buttonsPAD & PAD_BUTTON_A) || (buttonsPAD & PAD_TRIGGER_L) || t->Left())) + { + btnLeft->ResetState(); + return; + } + + if (Settings.xflip == XFLIP_SYSMENU || Settings.xflip == XFLIP_YES || Settings.xflip == XFLIP_DISK3D) + goRight = goSteps; + else goLeft = goSteps; + } + else if (btnRight->GetState() == STATE_CLICKED) + { + u32 buttons = t->wpad.btns_h; + u32 buttonsPAD = t->pad.btns_h; + if (!((buttons & WPAD_BUTTON_A) || (buttons & WPAD_BUTTON_PLUS) || + (buttons & WPAD_CLASSIC_BUTTON_A) || (buttons & WPAD_CLASSIC_BUTTON_PLUS) || + (buttonsPAD & PAD_BUTTON_A) || (buttonsPAD & PAD_TRIGGER_R) || t->Right())) + { + btnRight->ResetState(); + return; + } + if (Settings.xflip == XFLIP_SYSMENU || Settings.xflip == XFLIP_YES || Settings.xflip == XFLIP_DISK3D) + goLeft = goSteps; + else goRight = goSteps; + } + + if (goLeft == goSteps) + { + GuiButton *tmpButton[rows]; + GuiTooltip *tmpTooltip[rows]; + listOffset = OFFSETLIMIT(listOffset + rows, rows, gameList.size()); // set the new listOffset + // Save left Tooltip & Button and destroy left Image + Image-Data + for (int i = 0; i < rows; i++) + { + delete coverImg[i]; + coverImg[i] = NULL; + game[i]->SetImage(NULL); + tmpTooltip[i] = titleTT[i]; + tmpButton[i] = game[i]; + } + // Move all Page-Entries one step left + for (int i = 0; i < (pagesize - rows); i++) + { + titleTT[i] = titleTT[i + rows]; + coverImg[i] = coverImg[i + rows]; + game[i] = game[i + rows]; + gameIndex[i] = gameIndex[i + rows]; + } + // set saved Tooltip, Button & gameIndex to right + int wsi = Settings.widescreen ? 0 : 1; + int (*Pos)[2][2] = VALUE4ROWS( rows, Pos1, Pos2, Pos3 ); + int (*Skew)[8] = VALUE4ROWS( rows, Skew1, Skew2, Skew3 ); + + for (int i = 0; i < rows; i++) + { + int ii = i + pagesize - rows; + gameIndex[ii] = GetGameIndex(ii, rows, listOffset, gameList.size()); + titleTT[ii] = tmpTooltip[i]; + coverImg[ii] = NULL; + if (gameIndex[ii] != -1) + { + coverImg[ii] = new GuiImageAsync(GameGridLoadCoverImage, gameList[gameIndex[ii]], + sizeof(struct discHdr), &noCover); + if (coverImg[ii]) + { + coverImg[ii] ->SetWidescreen(Settings.widescreen); + coverImg[ii] ->SetScale(VALUE4ROWS( rows, 1.0, 0.6, 0.26 )); + coverImg[ii] ->SetPosition(0, VALUE4ROWS( rows, 0, -50, -80 )); + } + titleTT[ii] ->SetText(GameTitles.GetTitle(gameList[gameIndex[ii]])); + } + else + { + titleTT[ii] ->SetText(NULL); + } + + game[ii] = tmpButton[i]; + game[ii] ->SetImage(coverImg[ii]); + game[ii] ->SetPosition(Pos[ii][wsi][0], Pos[ii][wsi][1]); + game[ii] ->SetSkew(&Skew[ii][0]); + game[ii] ->RemoveToolTip(); + if (gameIndex[ii] != -1) + { + game[ii] ->SetClickable(true); + game[ii] ->SetVisible(true); + } + else + { + game[ii] ->SetVisible(false); + game[ii] ->SetClickable(false); + game[ii] ->RemoveSoundOver(); + } + } + // Set Tooltip-Position + int ttoffset_x = Settings.widescreen ? VALUE4ROWS( rows, 70, 35, 0 ) : VALUE4ROWS( rows, 150, 55, 25 ); + int ttoffset_y = -VALUE4ROWS( rows, 224, 133, 68 ) / 4; + for (int i = 0; i < pagesize; i++) + { + switch ((i * 3) / pagesize) + { + case 0: + game[i]->SetToolTip(titleTT[i], ttoffset_x, ttoffset_y, ALIGN_LEFT, ALIGN_MIDDLE); + break; + case 1: + game[i]->SetToolTip(titleTT[i], 0, ttoffset_y, ALIGN_CENTER, ALIGN_MIDDLE); + break; + case 2: + game[i]->SetToolTip(titleTT[i], -ttoffset_x, ttoffset_y, ALIGN_RIGHT, ALIGN_MIDDLE); + break; + default: + break; + } + } + } + else if (goRight == goSteps) + { + GuiButton *tmpButton[rows]; + GuiTooltip *tmpTooltip[rows]; + listOffset = OFFSETLIMIT(listOffset - rows, rows, gameList.size()); // set the new listOffset + // Save right Button & Tooltip and destroy right Image-Data + for (int i = 0; i < rows; i++) + { + int ii = i + pagesize - rows; + delete coverImg[ii]; + coverImg[ii] = NULL; + game[ii]->SetImage(NULL); + tmpTooltip[i] = titleTT[ii]; + tmpButton[i] = game[ii]; + } + // Move all Page-Entries one step right + for (int i = pagesize - 1; i >= rows; i--) + { + titleTT[i] = titleTT[i - rows]; + coverImg[i] = coverImg[i - rows]; + game[i] = game[i - rows]; + gameIndex[i] = gameIndex[i - rows]; + } + // set saved Image, Button & gameIndex to left + int wsi = Settings.widescreen ? 0 : 1; + int (*Pos)[2][2] = VALUE4ROWS( rows, Pos1, Pos2, Pos3 ); + int (*Skew)[8] = VALUE4ROWS( rows, Skew1, Skew2, Skew3 ); + + for (int i = 0; i < rows; i++) + { + gameIndex[i] = GetGameIndex(i, rows, listOffset, gameList.size()); + titleTT[i] = tmpTooltip[i]; + coverImg[i] = NULL; + if (gameIndex[i] != -1) + { + coverImg[i] = new GuiImageAsync(GameGridLoadCoverImage, gameList[gameIndex[i]], + sizeof(struct discHdr), &noCover); + if (coverImg[i]) + { + coverImg[i] ->SetWidescreen(Settings.widescreen); + coverImg[i] ->SetScale(VALUE4ROWS( rows, 1.0, 0.6, 0.26 )); + coverImg[i] ->SetPosition(0, VALUE4ROWS( rows, 0, -50, -80 )); + } + titleTT[i] ->SetText(GameTitles.GetTitle(gameList[gameIndex[i]])); + } + else + { + titleTT[i] ->SetText(NULL); + } + game[i] = tmpButton[i]; + game[i] ->SetImage(coverImg[i]); + game[i] ->SetPosition(Pos[i][wsi][0], Pos[i][wsi][1]); + game[i] ->SetSkew(&Skew[i][0]); + game[i] ->RemoveToolTip(); + if (gameIndex[i] != -1) + { + game[i] ->SetClickable(true); + game[i] ->SetVisible(true); + } + else + { + game[i] ->SetVisible(false); + game[i] ->SetClickable(false); + game[i] ->RemoveSoundOver(); + } + } + // Set Tooltip-Position + int ttoffset_x = Settings.widescreen ? VALUE4ROWS( rows, 70, 35, 0 ) : VALUE4ROWS( rows, 150, 55, 25 ); + int ttoffset_y = -VALUE4ROWS( rows, 224, 133, 68 ) / 4; + for (int i = 0; i < pagesize; i++) + { + switch ((i * 3) / pagesize) + { + case 0: + game[i]->SetToolTip(titleTT[i], ttoffset_x, ttoffset_y, ALIGN_LEFT, ALIGN_MIDDLE); + break; + case 1: + game[i]->SetToolTip(titleTT[i], 0, ttoffset_y, ALIGN_CENTER, ALIGN_MIDDLE); + break; + case 2: + game[i]->SetToolTip(titleTT[i], -ttoffset_x, ttoffset_y, ALIGN_RIGHT, ALIGN_MIDDLE); + break; + default: + break; + } + } + } + } + + if ((btnRowUp->GetState() == STATE_CLICKED)) + { + if ((rows == 1) && (gameList.size() >= 18)) + this->ChangeRows(2); + else if ((rows == 2) && (gameList.size() >= 45)) + this->ChangeRows(3); + btnRowUp->ResetState(); + return; + } + + if ((btnRowDown->GetState() == STATE_CLICKED)) + { + if (rows == 3) + this->ChangeRows(2); + else if (rows == 2) + this->ChangeRows(1); + + btnRowDown->ResetState(); + return; + } + + if (updateCB) + updateCB(this); +} + +void GuiGameGrid::Reload(int Rows, int ListOffset) +{ + LOCK( this ); + + //Prevent to wait before all images are loaded before we can delete them + GuiImageAsync::ClearQueue(); + + // CleanUp + for (u32 i = 0; i < game.size(); ++i) + delete game[i]; + + for (u32 i = 0; i < coverImg.size(); ++i) + delete coverImg[i]; + + for (u32 i = 0; i < titleTT.size(); ++i) + delete titleTT[i]; + + game.clear(); + coverImg.clear(); + titleTT.clear(); + gameIndex.clear(); + + goLeft = 0; + goRight = 0; + + rows = Rows > 3 ? 3 : (Rows < 1 ? 1 : Rows); + if ((gameList.size() < 45) && (rows == 3)) rows = 2; + if ((gameList.size() < 18) && (rows == 2)) rows = 1; + + if (ListOffset >= 0) // if ListOffset < 0 then no change + listOffset = ListOffset; + listOffset = OFFSETLIMIT(listOffset, rows, gameList.size()); + + selectedItem = -1; + clickedItem = -1; + + pagesize = ROWS2PAGESIZE( rows ); + + if(gameList.size() == 0) + { + pagesize = 0; + return; + } + + // Page-Stuff + gameIndex.resize(pagesize); + titleTT.resize(pagesize); + coverImg.resize(pagesize); + game.resize(pagesize); + + int wsi = Settings.widescreen ? 0 : 1; + int (*Pos)[2][2] = VALUE4ROWS( rows, Pos1, Pos2, Pos3 ); + int (*Skew)[8] = VALUE4ROWS( rows, Skew1, Skew2, Skew3 ); + + int ttoffset_x = Settings.widescreen ? VALUE4ROWS( rows, 70, 35, 0 ) : VALUE4ROWS( rows, 150, 55, 25 ); + int ttoffset_y = -VALUE4ROWS( rows, 224, 133, 68 ) / 4; + + for (int i = 0; i < pagesize; i++) + { + //------------------------ + // Index + //------------------------ + gameIndex[i] = GetGameIndex(i, rows, listOffset, gameList.size()); + + //------------------------ + // Tooltip + //------------------------ + if (gameIndex[i] != -1) + titleTT[i] = new GuiTooltip(GameTitles.GetTitle(gameList[gameIndex[i]]), thInt("255 - tooltip alpha")); + else + titleTT[i] = new GuiTooltip(NULL, thInt("255 - tooltip alpha")); + + //------------------------ + // ImageData + //------------------------ + // if( gameIndex[i] != -1 ) + // cover[i] = LoadCoverImage(&gameList[gameIndex[i]], false /*bool Prefere3D*/); + // else + // cover[i] = new GuiImageData(NULL); + + //------------------------ + // Image + //------------------------ + coverImg[i] = NULL; + if (gameIndex[i] != -1) + { + coverImg[i] = new GuiImageAsync(GameGridLoadCoverImage, gameList[gameIndex[i]], sizeof(struct discHdr), &noCover); + if (coverImg[i]) + { + coverImg[i]->SetWidescreen(Settings.widescreen); + // if ( rows == 2 ) coverImg[i]->SetScale(.6); //these are the numbers for 2 rows + // else if ( rows == 3 ) coverImg[i]->SetScale(.26); //these are the numbers for 3 rows + coverImg[i]->SetScale(VALUE4ROWS( rows, 1.0, 0.6, 0.26 )); + coverImg[i]->SetPosition(0, VALUE4ROWS( rows, 0, -50, -80 )); + } + } + + //------------------------ + // GameButton + //------------------------ + game[i] = new GuiButton(VALUE4ROWS( rows, 160, 75, 35 ), VALUE4ROWS( rows, 224, 133, 68 )); + game[i]->SetParent(this); + game[i]->SetImage(coverImg[i]); + game[i]->SetAlignment(ALIGN_TOP, ALIGN_LEFT); + game[i]->SetPosition(Pos[i][wsi][0] + theme_posX, Pos[i][wsi][1] + theme_posY); + game[i]->SetSkew(&Skew[i][0]); + game[i]->SetTrigger(trigA); + game[i]->SetSoundOver(btnSoundOver); + game[i]->SetSoundClick(btnSoundClick); + game[i]->SetRumble(false); + switch ((i * 3) / pagesize) + { + case 0: + game[i]->SetToolTip(titleTT[i], ttoffset_x, ttoffset_y, ALIGN_LEFT, ALIGN_MIDDLE); + break; + case 1: + game[i]->SetToolTip(titleTT[i], 0, ttoffset_y, ALIGN_CENTER, ALIGN_MIDDLE); + break; + case 2: + game[i]->SetToolTip(titleTT[i], -ttoffset_x, ttoffset_y, ALIGN_RIGHT, ALIGN_MIDDLE); + break; + default: + break; + } + if (gameIndex[i] >= 0) + { + game[i]->SetClickable(true); + game[i]->SetVisible(true); + } + else + { + game[i]->SetVisible(false); + game[i]->SetClickable(false); + // game[i]->RemoveSoundOver(); + } + } + Settings.gridRows = rows; +} + diff --git a/source/GUI/gui_gamegrid.h b/source/GUI/gui_gamegrid.h new file mode 100644 index 0000000..64f904a --- /dev/null +++ b/source/GUI/gui_gamegrid.h @@ -0,0 +1,62 @@ +#ifndef _GUIGAMEGRID_H_ +#define _GUIGAMEGRID_H_ + +#include +#include "gui_gamebrowser.h" +#include "gui_image_async.h" +#include "usbloader/disc.h" + +class GuiGameGrid : public GuiGameBrowser +{ + public: + GuiGameGrid(int w, int h, const char *themePath, int selectedGame = 0); + virtual ~GuiGameGrid(); + int FindMenuItem(int c, int d); + int GetClickedOption(); + int GetSelectedOption(); + void SetSelectedOption(int ind); + void setListOffset(int off) { listOffset = off; Reload(rows, listOffset); } + int getListOffset() const { return listOffset; } + void ResetState(); + void SetFocus(int f); + void Draw(); + void Update(GuiTrigger * t); + void Reload(int Rows, int ListOffset); + void ChangeRows(int n); + protected: + GuiImageData noCover; + int selectedItem; + int listOffset; + int pagesize; + int clickedItem; + int rows; + int goLeft; + int goRight; + int theme_posX; + int theme_posY; + + std::vector gameIndex; + std::vector game; + std::vector titleTT; + std::vector coverImg; + + GuiButton * btnRight; + GuiButton * btnLeft; + GuiButton * btnRowUp; + GuiButton * btnRowDown; + + GuiImage * btnLeftImg; + GuiImage * btnRightImg; + + GuiImageData * imgLeft; + GuiImageData * imgRight; + + GuiTrigger * trigA; + GuiTrigger * trigL; + GuiTrigger * trigR; + GuiTrigger * trigPlus; + GuiTrigger * trigMinus; + GuiTrigger * trig1; + GuiTrigger * trig2; +}; +#endif diff --git a/source/GUI/gui_gamelist.cpp b/source/GUI/gui_gamelist.cpp new file mode 100644 index 0000000..0cb2c1b --- /dev/null +++ b/source/GUI/gui_gamelist.cpp @@ -0,0 +1,296 @@ +/**************************************************************************** + * libwiigui + * + * gui_gamebrowser.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" +#include "wpad.h" + +#include +#include "gui_gamelist.h" +#include "settings/CSettings.h" +#include "main.h" +#include "settings/newtitles.h" +#include "settings/GameTitles.h" +#include "usbloader/GameList.h" +#include "themes/CTheme.h" +#include "utils/tools.h" +#include "menu.h" + +#include +#include + +#define GAMESELECTSIZE 30 + +/** + * Constructor for the GuiGameList class. + */ +GuiGameList::GuiGameList(int w, int h, int offset) + : scrollBar(h-10) +{ + width = w; + height = h; + pagesize = thInt("9 - game list browser page size"); + selectable = true; + listOffset = LIMIT(offset, 0, MAX(0, gameList.size()-pagesize)); + selectedItem = 0; + + trigA = new GuiTrigger; + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + bgGames = Resources::GetImageData("bg_options.png"); + newGames = Resources::GetImageData("new.png"); + + scrollBar.SetParent(this); + scrollBar.SetAlignment(thAlign("right - game browser scrollbar align hor"), thAlign("top - game browser scrollbar align ver")); + scrollBar.SetPosition(thInt("0 - game browser scrollbar pos x"), thInt("5 - game browser scrollbar pos y")); + scrollBar.SetButtonScroll(WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B); + scrollBar.SetPageSize(pagesize); + scrollBar.SetSelectedItem(selectedItem); + scrollBar.SetSelectedIndex(listOffset); + scrollBar.SetEntrieCount(gameList.size()); + scrollBar.listChanged.connect(this, &GuiGameList::onListChange); + + bgGameImg = new GuiImage(bgGames); + bgGameImg->SetParent(this); + bgGameImg->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + + bgGamesEntry = Resources::GetImageData("bg_options_entry.png"); + + maxTextWidth = bgGameImg->GetWidth() - scrollBar.GetWidth() - 38; + + game = new GuiButton *[pagesize]; + gameTxt = new GuiText *[pagesize]; + gameTxtOver = new GuiText *[pagesize]; + gameBg = new GuiImage *[pagesize]; + newImg = new GuiImage *[pagesize]; + + for (int i = 0; i < pagesize; ++i) + { + gameTxt[i] = new GuiText((char *) NULL, 20, thColor("r=0 g=0 b=0 a=255 - game browser list text color")); + gameTxt[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + gameTxt[i]->SetPosition(24, 0); + gameTxt[i]->SetMaxWidth(maxTextWidth, DOTTED); + + gameTxtOver[i] = new GuiText((char *) NULL, 20, thColor("r=0 g=0 b=0 a=255 - game browser list text color over")); + gameTxtOver[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + gameTxtOver[i]->SetPosition(24, 0); + gameTxtOver[i]->SetMaxWidth(maxTextWidth, SCROLL_HORIZONTAL); + + gameBg[i] = new GuiImage(bgGamesEntry); + + newImg[i] = new GuiImage(newGames); + newImg[i]->SetAlignment(ALIGN_RIGHT, ALIGN_MIDDLE); + newImg[i]->SetVisible(false); + + game[i] = new GuiButton(width - scrollBar.GetWidth(), GAMESELECTSIZE); + game[i]->SetParent(this); + game[i]->SetLabel(gameTxt[i]); + game[i]->SetLabelOver(gameTxtOver[i]); + game[i]->SetIcon(newImg[i]); + game[i]->SetImageOver(gameBg[i]); + game[i]->SetPosition(5, GAMESELECTSIZE * i + 4); + game[i]->SetRumble(false); + game[i]->SetTrigger(trigA); + game[i]->SetSoundClick(btnSoundClick); + game[i]->SetVisible(false); + game[i]->SetState(STATE_DISABLED); + } + UpdateListEntries(); +} + +/** + * Destructor for the GuiGameList class. + */ +GuiGameList::~GuiGameList() +{ + delete bgGameImg; + delete bgGames; + delete bgGamesEntry; + delete newGames; + + delete trigA; + + for (int i = 0; i < pagesize; ++i) + { + delete gameTxt[i]; + delete gameTxtOver[i]; + delete gameBg[i]; + delete game[i]; + delete newImg[i]; + } + delete[] game; + delete[] gameTxt; + delete[] gameTxtOver; + delete[] gameBg; +} + +void GuiGameList::SetFocus(int f) +{ + LOCK( this ); + if (!gameList.size()) return; + + for (int i = 0; i < pagesize; ++i) + game[i]->ResetState(); + + if (f == 1) game[selectedItem]->SetState(STATE_SELECTED); +} + +void GuiGameList::ResetState() +{ + LOCK( this ); + if (state != STATE_DISABLED) + { + state = STATE_DEFAULT; + stateChan = -1; + } + + for (int i = 0; i < pagesize; ++i) + { + game[i]->ResetState(); + } +} + +int GuiGameList::GetClickedOption() +{ + int found = -1; + for (int i = 0; i < pagesize; ++i) + { + if (game[i]->GetState() == STATE_CLICKED) + { + game[i]->SetState(STATE_SELECTED); + found = listOffset + i; + break; + } + } + return found; +} + +void GuiGameList::onListChange(int SelItem, int SelInd) +{ + selectedItem = SelItem; + listOffset = SelInd; + UpdateListEntries(); +} + +void GuiGameList::setListOffset(int off) +{ + LOCK(this); + listOffset = LIMIT(off, 0, MAX(0, gameList.size()-pagesize)); +} + +void GuiGameList::SetSelectedOption(int ind) +{ + LOCK(this); + selectedItem = LIMIT(ind, 0, MIN(pagesize, MAX(0, gameList.size()-1))); +} + +/** + * Draw the button on screen + */ +void GuiGameList::Draw() +{ + LOCK( this ); + if (!this->IsVisible() || !gameList.size()) return; + + bgGameImg->Draw(); + + for (int i = 0, next = listOffset; i < pagesize; ++i, ++next) + { + if (next < gameList.size()) + game[i]->Draw(); + } + + scrollBar.Draw(); + + this->UpdateEffects(); +} + +void GuiGameList::UpdateListEntries() +{ + for (int i = 0, next = listOffset; i < pagesize; ++i, ++next) + { + if (next < gameList.size()) + { + if (game[i]->GetState() == STATE_DISABLED) + { + game[i]->SetVisible(true); + game[i]->SetState(STATE_DEFAULT); + } + gameTxt[i]->SetText(GameTitles.GetTitle(gameList[next])); + gameTxt[i]->SetPosition(24, 0); + gameTxtOver[i]->SetText(GameTitles.GetTitle(gameList[next])); + gameTxtOver[i]->SetPosition(24, 0); + + if (Settings.marknewtitles) + { + bool isNew = NewTitles::Instance()->IsNew(gameList[next]->id); + if (isNew) + { + gameTxt[i]->SetMaxWidth(maxTextWidth - (newGames->GetWidth() + 1), DOTTED); + gameTxtOver[i]->SetMaxWidth(maxTextWidth - (newGames->GetWidth() + 1), SCROLL_HORIZONTAL); + } + else + { + gameTxt[i]->SetMaxWidth(maxTextWidth, DOTTED); + gameTxtOver[i]->SetMaxWidth(maxTextWidth, SCROLL_HORIZONTAL); + } + newImg[i]->SetVisible(isNew); + } + } + else + { + game[i]->SetVisible(false); + game[i]->SetState(STATE_DISABLED); + } + } +} + +void GuiGameList::Update(GuiTrigger * t) +{ + LOCK( this ); + if (state == STATE_DISABLED || !t || !gameList.size()) return; + + static int pressedChan = -1; + + if((t->wpad.btns_d & (WPAD_BUTTON_B | WPAD_BUTTON_DOWN | WPAD_BUTTON_UP | WPAD_BUTTON_LEFT | WPAD_BUTTON_RIGHT | + WPAD_CLASSIC_BUTTON_B | WPAD_CLASSIC_BUTTON_UP | WPAD_CLASSIC_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_RIGHT)) || + (t->pad.btns_d & (PAD_BUTTON_UP | PAD_BUTTON_DOWN))) + pressedChan = t->chan; + + // update the location of the scroll box based on the position in the option list + scrollBar.Update(t); + + if(pressedChan == -1 || (!t->wpad.btns_h && !t->pad.btns_h)) + { + for (int i = 0, next = listOffset; i < pagesize; ++i, ++next) + { + if (next >= gameList.size()) + break; + + if (i != selectedItem && game[i]->GetState() == STATE_SELECTED) + game[i]->ResetState(); + else if (i == selectedItem && game[i]->GetState() == STATE_DEFAULT) + game[selectedItem]->SetState(STATE_SELECTED, -1); + + game[i]->Update(t); + + if (game[i]->GetState() == STATE_SELECTED) + selectedItem = i; + } + } + + if(pressedChan == t->chan && !t->wpad.btns_d && !t->wpad.btns_h) + pressedChan = -1; + + scrollBar.SetPageSize(pagesize); + scrollBar.SetSelectedItem(selectedItem); + scrollBar.SetSelectedIndex(listOffset); + scrollBar.SetEntrieCount(gameList.size()); + + if (updateCB) updateCB(this); +} + diff --git a/source/GUI/gui_gamelist.h b/source/GUI/gui_gamelist.h new file mode 100644 index 0000000..2fbf74a --- /dev/null +++ b/source/GUI/gui_gamelist.h @@ -0,0 +1,46 @@ +#ifndef _GUIGAMELIST_H_ +#define _GUIGAMELIST_H_ + +#include "gui_gamebrowser.h" +#include "gui_scrollbar.hpp" +#include "usbloader/disc.h" + +class GuiGameList : public GuiGameBrowser, public sigslot::has_slots<> +{ + public: + GuiGameList(int w, int h, int listOffset = 0); + virtual ~GuiGameList(); + int GetClickedOption(); + int GetSelectedOption() { return listOffset+selectedItem; } + void SetSelectedOption(int ind); + void setListOffset(int off); + int getListOffset() const { return listOffset; } + void ResetState(); + void SetFocus(int f); + void Draw(); + void Update(GuiTrigger * t); + protected: + void onListChange(int SelItem, int SelInd); + void UpdateListEntries(); + int selectedItem; + int listOffset; + int pagesize; + int maxTextWidth; + + GuiButton ** game; + GuiText ** gameTxt; + GuiText ** gameTxtOver; + GuiImage ** gameBg; + GuiImage ** newImg; + + GuiImage * bgGameImg; + + GuiImageData * bgGames; + GuiImageData * bgGamesEntry; + GuiImageData * newGames; + + GuiTrigger * trigA; + + GuiScrollbar scrollBar; +}; +#endif diff --git a/source/GUI/gui_image.cpp b/source/GUI/gui_image.cpp new file mode 100644 index 0000000..fb0e191 --- /dev/null +++ b/source/GUI/gui_image.cpp @@ -0,0 +1,481 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_image.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" +#include "settings/CSettings.h" +/** + * Constructor for the GuiImage class. + */ +GuiImage::GuiImage() +{ + image = NULL; + width = 0; + height = 0; + imageangle = 0; + tileHorizontal = -1; + tileVertical = -1; + stripe = 0; + widescreen = 0; + xx1 = 0; + yy1 = 0; + xx2 = 0; + yy2 = 0; + xx3 = 0; + yy3 = 0; + xx4 = 0; + yy4 = 0; + imgType = IMAGE_DATA; +} + +GuiImage::GuiImage(GuiImageData * img) +{ + if (img) + { + image = img->GetImage(); + width = img->GetWidth(); + height = img->GetHeight(); + } + else + { + image = NULL; + width = 0; + height = 0; + } + imageangle = 0; + tileHorizontal = -1; + tileVertical = -1; + stripe = 0; + widescreen = 0; + parentangle = true; + xx1 = 0; + yy1 = 0; + xx2 = 0; + yy2 = 0; + xx3 = 0; + yy3 = 0; + xx4 = 0; + yy4 = 0; + imgType = IMAGE_DATA; +} + +GuiImage::GuiImage(u8 * img, int w, int h) +{ + image = img; + width = w; + height = h; + imageangle = 0; + tileHorizontal = -1; + tileVertical = -1; + stripe = 0; + widescreen = 0; + parentangle = true; + xx1 = 0; + yy1 = 0; + xx2 = 0; + yy2 = 0; + xx3 = 0; + yy3 = 0; + xx4 = 0; + yy4 = 0; + imgType = IMAGE_TEXTURE; +} + +GuiImage::GuiImage(int w, int h, GXColor c) +{ + image = (u8 *) memalign(32, w * h * 4); + width = w; + height = h; + imageangle = 0; + tileHorizontal = -1; + tileVertical = -1; + stripe = 0; + widescreen = 0; + parentangle = true; + xx1 = 0; + yy1 = 0; + xx2 = 0; + yy2 = 0; + xx3 = 0; + yy3 = 0; + xx4 = 0; + yy4 = 0; + imgType = IMAGE_COLOR; + + if (!image) return; + + int x, y; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + this->SetPixel(x, y, c); + } + } + int len = w * h * 4; + if (len % 32) len += (32 - len % 32); + DCFlushRange(image, len); +} + +GuiImage::GuiImage(GuiImage &srcimage) : + GuiElement() +{ + width = srcimage.GetWidth(); + height = srcimage.GetHeight(); + int len = width * height * 4; + if (len % 32) len += (32 - len % 32); + image = (u8 *) memalign(32, len); + memcpy(image, srcimage.GetImage(), len); + DCFlushRange(image, len); + imageangle = srcimage.GetAngle(); + tileHorizontal = -1; + tileVertical = -1; + stripe = 0; + widescreen = 0; + parentangle = true; + xx1 = 0; + yy1 = 0; + xx2 = 0; + yy2 = 0; + xx3 = 0; + yy3 = 0; + xx4 = 0; + yy4 = 0; + imgType = IMAGE_COPY; +} + +GuiImage::GuiImage(GuiImage *srcimage) : + GuiElement() +{ + width = srcimage->GetWidth(); + height = srcimage->GetHeight(); + int len = width * height * 4; + if (len % 32) len += (32 - len % 32); + image = (u8 *) memalign(32, len); + memcpy(image, srcimage->GetImage(), len); + DCFlushRange(image, len); + imageangle = srcimage->GetAngle(); + tileHorizontal = -1; + tileVertical = -1; + stripe = 0; + widescreen = 0; + parentangle = true; + xx1 = 0; + yy1 = 0; + xx2 = 0; + yy2 = 0; + xx3 = 0; + yy3 = 0; + xx4 = 0; + yy4 = 0; + imgType = IMAGE_COPY; +} + +GuiImage &GuiImage::operator=(GuiImage & srcimage) +{ + if ((imgType == IMAGE_COLOR || imgType == IMAGE_COPY) && image) + { + free(image); + image = NULL; + } + + width = srcimage.GetWidth(); + height = srcimage.GetHeight(); + int len = width * height * 4; + if (len % 32) len += (32 - len % 32); + image = (u8 *) memalign(32, len); + memcpy(image, srcimage.GetImage(), len); + DCFlushRange(image, len); + imageangle = srcimage.GetAngle(); + tileHorizontal = -1; + tileVertical = -1; + stripe = 0; + widescreen = 0; + parentangle = true; + xx1 = 0; + yy1 = 0; + xx2 = 0; + yy2 = 0; + xx3 = 0; + yy3 = 0; + xx4 = 0; + yy4 = 0; + imgType = IMAGE_COPY; + return *this; +} + +/** + * Destructor for the GuiImage class. + */ +GuiImage::~GuiImage() +{ + if ((imgType == IMAGE_COLOR || imgType == IMAGE_COPY) && image) + { + free(image); + image = NULL; + } +} + +u8 * GuiImage::GetImage() +{ + return image; +} + +void GuiImage::SetImage(GuiImageData * img) +{ + LOCK( this ); + if ((imgType == IMAGE_COLOR || imgType == IMAGE_COPY) && image) + { + free(image); + image = NULL; + } + + image = NULL; + width = 0; + height = 0; + imgType = IMAGE_DATA; + + if(img) + { + image = img->GetImage(); + width = img->GetWidth(); + height = img->GetHeight(); + } +} + +void GuiImage::SetImage(u8 * img, int w, int h) +{ + LOCK( this ); + if ((imgType == IMAGE_COLOR || imgType == IMAGE_COPY) && image) + { + free(image); + image = NULL; + } + image = img; + width = w; + height = h; + imgType = IMAGE_TEXTURE; +} + +void GuiImage::SetAngle(float a) +{ + LOCK( this ); + imageangle = a; +} +float GuiImage::GetAngle() +{ + return imageangle; +} + +void GuiImage::SetTileHorizontal(int t) +{ + LOCK( this ); + tileHorizontal = t; +} + +void GuiImage::SetTileVertical(int t) +{ + LOCK( this ); + tileVertical = t; +} + +void GuiImage::SetWidescreen(bool w) +{ + LOCK( this ); + widescreen = w; +} +void GuiImage::SetParentAngle(bool a) +{ + LOCK( this ); + parentangle = a; +} + +GXColor GuiImage::GetPixel(int x, int y) +{ + if (!image || this->GetWidth() <= 0 || x < 0 || y < 0) return ( GXColor ) + { 0, 0, 0, 0}; + + u32 offset = (((y >> 2) << 4) * this->GetWidth()) + ((x >> 2) << 6) + (((y % 4 << 2) + x % 4) << 1); + GXColor color; + color.a = *(image + offset); + color.r = *(image + offset + 1); + color.g = *(image + offset + 32); + color.b = *(image + offset + 33); + return color; +} + +void GuiImage::SetPixel(int x, int y, GXColor color) +{ + LOCK( this ); + if (!image || this->GetWidth() <= 0 || x < 0 || y < 0) return; + + u32 offset = (((y >> 2) << 4) * this->GetWidth()) + ((x >> 2) << 6) + (((y % 4 << 2) + x % 4) << 1); + *(image + offset) = color.a; + *(image + offset + 1) = color.r; + *(image + offset + 32) = color.g; + *(image + offset + 33) = color.b; +} + +void GuiImage::SetGrayscale(void) +{ + LOCK( this ); + GXColor color; + u32 offset, gray; + + for (int x = 0; x < width; x++) + { + for (int y = 0; y < height; y++) + { + offset = (((y >> 2) << 4) * width) + ((x >> 2) << 6) + (((y % 4 << 2) + x % 4) << 1); + color.r = *(image + offset + 1); + color.g = *(image + offset + 32); + color.b = *(image + offset + 33); + + gray = (77 * color.r + 150 * color.g + 28 * color.b) / 255; + + *(image + offset + 1) = gray; + *(image + offset + 32) = gray; + *(image + offset + 33) = gray; + } + } + + int len = width * height * 4; + if (len % 32) len += (32 - len % 32); + DCFlushRange(image, len); +} + +void GuiImage::SetStripe(int s) +{ + LOCK( this ); + stripe = s; +} + +void GuiImage::SetSkew(int XX1, int YY1, int XX2, int YY2, int XX3, int YY3, int XX4, int YY4) +{ + + xx1 = XX1; + yy1 = YY1; + xx2 = XX2; + yy2 = YY2; + xx3 = XX3; + yy3 = YY3; + xx4 = XX4; + yy4 = YY4; +} +void GuiImage::SetSkew(int *skew) +{ + + xx1 = *skew++; + yy1 = *skew++; + xx2 = *skew++; + yy2 = *skew++; + xx3 = *skew++; + yy3 = *skew++; + xx4 = *skew++; + yy4 = *skew; +} + +void GuiImage::ColorStripe(int shift) +{ + LOCK( this ); + int x, y; + GXColor color; + int alt = 0; + + for (y = 0; y < this->GetHeight(); y++) + { + if (y % 3 == 0) alt ^= 1; + + for (x = 0; x < this->GetWidth(); x++) + { + color = GetPixel(x, y); + + if (alt) + { + if (color.r < 255 - shift) + color.r += shift; + else color.r = 255; + if (color.g < 255 - shift) + color.g += shift; + else color.g = 255; + if (color.b < 255 - shift) + color.b += shift; + else color.b = 255; + + color.a = 255; + } + else + { + if (color.r > shift) + color.r -= shift; + else color.r = 0; + if (color.g > shift) + color.g -= shift; + else color.g = 0; + if (color.b > shift) + color.b -= shift; + else color.b = 0; + + color.a = 255; + } + SetPixel(x, y, color); + } + } + + int len = width * height * 4; + if (len % 32) len += (32 - len % 32); + DCFlushRange(image, len); +} + +/** + * Draw the button on screen + */ + +void GuiImage::Draw() +{ + LOCK( this ); + if (!image || !this->IsVisible() || tileHorizontal == 0) return; + + float currScale = this->GetScale(); + int currLeft = this->GetLeft(); + + float currAngleDyn = this->GetAngleDyn(); + + if (currAngleDyn && parentangle) imageangle = currAngleDyn; + + if (tileHorizontal > 0) + { + for (int i = 0; i < tileHorizontal; i++) + Menu_DrawImg(currLeft + width * i, this->GetTop(), zoffset, width, height, image, imageangle, + widescreen ? currScale * Settings.WSFactor : currScale, currScale, this->GetAlpha(), xx1, + yy1, xx2, yy2, xx3, yy3, xx4, yy4); + } + else if(tileVertical > 0) + { + for (int i = 0; i < tileVertical; i++) + Menu_DrawImg(currLeft, this->GetTop() + height * i, zoffset, width, height, image, imageangle, + widescreen ? currScale * Settings.WSFactor : currScale, currScale, this->GetAlpha(), xx1, + yy1, xx2, yy2, xx3, yy3, xx4, yy4); + } + else + { + // temporary (maybe), used to correct offset for scaled images + if (scale != 1) currLeft = currLeft - width / 2 + (width * scale) / 2; + + Menu_DrawImg(currLeft, this->GetTop(), zoffset, width, height, image, imageangle, widescreen ? currScale * Settings.WSFactor + : currScale, currScale, this->GetAlpha(), xx1, yy1, xx2, yy2, xx3, yy3, xx4, yy4); + } + + if (stripe > 0) for (int y = 0; y < this->GetHeight(); y += 6) + Menu_DrawRectangle(currLeft, this->GetTop() + y, this->GetWidth(), 3, ( GXColor ) + { 0, 0, 0, stripe}, 1); + + this->UpdateEffects(); +} diff --git a/source/GUI/gui_image_async.cpp b/source/GUI/gui_image_async.cpp new file mode 100644 index 0000000..8345d78 --- /dev/null +++ b/source/GUI/gui_image_async.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** + * USB Loader GX + * + * gui_imagea_sync.cpp + ***************************************************************************/ +#include +#include "gui_image_async.h" + +std::vector GuiImageAsync::List; +lwp_t GuiImageAsync::Thread = LWP_THREAD_NULL; +mutex_t GuiImageAsync::ListLock = LWP_THREAD_NULL; +GuiImageAsync * GuiImageAsync::InUse = NULL; +u32 GuiImageAsync::ThreadCount = 0; +bool GuiImageAsync::ThreadSleep = true; +bool GuiImageAsync::CloseThread = false; + +static inline void * memdup(const void* src, size_t len) +{ + if(!src) return NULL; + + void *dst = malloc(len); + if (dst) memcpy(dst, src, len); + return dst; +} + +static GuiImageData * StdImageLoaderCallback(void *arg) +{ + return new GuiImageData((char *) arg); +} + +GuiImageAsync::GuiImageAsync(const char *Filename, GuiImageData * PreloadImg) : + GuiImage(PreloadImg), imgData(NULL), callback(StdImageLoaderCallback), arg(strdup(Filename)) +{ + ThreadInit(); + ThreadAddImage(this); +} + +GuiImageAsync::GuiImageAsync(ImageLoaderCallback Callback, const void * Arg, int ArgLen, GuiImageData * PreloadImg) : + GuiImage(PreloadImg), imgData(NULL), callback(Callback), arg(memdup(Arg, ArgLen)) +{ + ThreadInit(); + ThreadAddImage(this); +} + +GuiImageAsync::~GuiImageAsync() +{ + ThreadRemoveImage(this); + ThreadExit(); + while(InUse == this) usleep(100); + if (imgData) delete imgData; + if (arg) free(arg); +} + +void GuiImageAsync::ThreadAddImage(GuiImageAsync *Image) +{ + LWP_MutexLock(ListLock); + List.push_back(Image); + LWP_MutexUnlock(ListLock); + ThreadSleep = false; + LWP_ResumeThread(Thread); +} + +void GuiImageAsync::ThreadRemoveImage(GuiImageAsync *Image) +{ + for(u32 i = 0; i < List.size(); ++i) + { + if(List[i] == Image) + { + LWP_MutexLock(ListLock); + List.erase(List.begin()+i); + LWP_MutexUnlock(ListLock); + break; + } + } +} + +void GuiImageAsync::ClearQueue() +{ + LWP_MutexLock(ListLock); + List.clear(); + LWP_MutexUnlock(ListLock); +} + +void * GuiImageAsync::GuiImageAsyncThread(void *arg) +{ + while(!CloseThread) + { + if(ThreadSleep) + LWP_SuspendThread(Thread); + + while(!List.empty() && !CloseThread) + { + LWP_MutexLock(ListLock); + InUse = List.front(); + List.erase(List.begin()); + LWP_MutexUnlock(ListLock); + + if (!InUse) + continue; + + InUse->imgData = InUse->callback(InUse->arg); + + if (InUse->imgData && InUse->imgData->GetImage()) + { + InUse->width = InUse->imgData->GetWidth(); + InUse->height = InUse->imgData->GetHeight(); + InUse->image = InUse->imgData->GetImage(); + } + + InUse = NULL; + } + + ThreadSleep = true; + } + + return NULL; +} + +u32 GuiImageAsync::ThreadInit() +{ + if (Thread == LWP_THREAD_NULL) + { + LWP_MutexInit(&ListLock, false); + LWP_CreateThread(&Thread, GuiImageAsyncThread, NULL, NULL, 32768, 70); + } + return ++ThreadCount; +} + +u32 GuiImageAsync::ThreadExit() +{ + //! We don't need to always shutdown and startup the thread, especially + //! since this is a nested startup/shutdown from the gui thread. + //! It's fine with being put to suspended only. + /* + if (--ThreadCount == 0) + { + CloseThread = true; + LWP_ResumeThread(Thread); + LWP_JoinThread(Thread, NULL); + LWP_MutexUnlock(ListLock); + LWP_MutexDestroy(ListLock); + Thread = LWP_THREAD_NULL; + ListLock = LWP_MUTEX_NULL; + ListLock = LWP_MUTEX_NULL; + } + */ + return --ThreadCount; +} + diff --git a/source/GUI/gui_image_async.h b/source/GUI/gui_image_async.h new file mode 100644 index 0000000..4fde76e --- /dev/null +++ b/source/GUI/gui_image_async.h @@ -0,0 +1,37 @@ +#ifndef _GUIIMAGEASYNC_H_ +#define _GUIIMAGEASYNC_H_ + +#include +#include "gui.h" + +typedef GuiImageData * (*ImageLoaderCallback)(void *arg); + +class GuiImageAsync: public GuiImage +{ + public: + GuiImageAsync(const char *Filename, GuiImageData * PreloadImg); + GuiImageAsync(ImageLoaderCallback Callback, const void *Arg, int ArgLen, GuiImageData * PreloadImg); + virtual ~GuiImageAsync(); + + static void ClearQueue(); + private: + GuiImageData *imgData; + ImageLoaderCallback callback; + void *arg; + + static void * GuiImageAsyncThread(void *arg); + static void ThreadAddImage(GuiImageAsync* Image); + static void ThreadRemoveImage(GuiImageAsync* Image); + static u32 ThreadInit(); + static u32 ThreadExit(); + + static std::vector List; + static lwp_t Thread; + static mutex_t ListLock; + static GuiImageAsync * InUse; + static u32 ThreadCount; + static bool ThreadSleep; + static bool CloseThread; +}; + +#endif /*_GUIIMAGEASYNC_H_*/ diff --git a/source/GUI/gui_imagedata.cpp b/source/GUI/gui_imagedata.cpp new file mode 100644 index 0000000..d80f273 --- /dev/null +++ b/source/GUI/gui_imagedata.cpp @@ -0,0 +1,195 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include "gui.h" +#include "ImageOperations/TextureConverter.h" +#include "ImageOperations/TplImage.h" +#include "FileOperations/fileops.h" +#include "utils/ResourceManager.h" + +#define ALIGN32(x) (((x) + 31) & ~31) + +/** + * Constructor for the GuiImageData class. + */ +GuiImageData::GuiImageData(const char * filepath) +{ + data = NULL; + width = 0; + height = 0; + format = GX_TF_RGBA8; + + u8 *buffer = NULL; + u32 size = 0; + + if(LoadFileToMem(filepath, &buffer, &size) < 0) + return; + + LoadImage(buffer, size); + + if(buffer) + free(buffer); +} + +GuiImageData::GuiImageData(const u8 * img, int imgSize, bool cache) +{ + data = NULL; + width = 0; + height = 0; + format = GX_TF_RGBA8; + + if(cache) + { + ImageData * Image = ResourceManager::GetImageData(img); + if(Image != NULL && Image->data != NULL) + { + data = Image->data; + width = Image->width; + height = Image->height; + format = Image->format; + return; + } + } + + LoadImage(img, imgSize); + + if(data && cache) + { + ImageData NewImage; + NewImage.data = data; + NewImage.width = width; + NewImage.height = height; + NewImage.format = format; + ResourceManager::AddImageData(img, NewImage); + } +} + +/** + * Destructor for the GuiImageData class. + */ +GuiImageData::~GuiImageData() +{ + if(data) + ResourceManager::Remove(data); +} + +void GuiImageData::LoadImage(const u8 * img, int imgSize) +{ + if(!img) + return; + + else if (imgSize < 8) + { + return; + } + else if (img[0] == 0x89 && img[1] == 'P' && img[2] == 'N' && img[3] == 'G') + { + // IMAGE_PNG + LoadPNG(img, imgSize); + } + else if (img[0] == 0xFF && img[1] == 0xD8) + { + // IMAGE_JPEG + LoadJpeg(img, imgSize); + } + else if (img[0] == 'B' && img[1] == 'M') + { + // IMAGE_BMP + LoadBMP(img, imgSize); + } + else if (img[0] == 'G' && img[1] == 'I' && img[2] == 'F') + { + // IMAGE_GIF + LoadGIF(img, imgSize); + } + else if (img[0] == 0x00 && img[1] == 0x20 && img[2] == 0xAF && img[3] == 0x30) + { + // IMAGE_TPL + LoadTPL(img, imgSize); + } +} + +void GuiImageData::LoadPNG(const u8 *img, int imgSize) +{ + gdImagePtr gdImg = gdImageCreateFromPngPtr(imgSize, (u8*) img); + if(gdImg == 0) + return; + + data = GDImageToRGBA8(&gdImg, &width, &height); + gdImageDestroy(gdImg); +} + +void GuiImageData::LoadJpeg(const u8 *img, int imgSize) +{ + gdImagePtr gdImg = gdImageCreateFromJpegPtr(imgSize, (u8*) img); + if(gdImg == 0) + return; + + data = GDImageToRGBA8(&gdImg, &width, &height); + gdImageDestroy(gdImg); +} + +void GuiImageData::LoadGIF(const u8 *img, int imgSize) +{ + gdImagePtr gdImg = gdImageCreateFromGifPtr(imgSize, (u8*) img); + if(gdImg == 0) + return; + + data = GDImageToRGBA8(&gdImg, &width, &height); + gdImageDestroy(gdImg); +} + +void GuiImageData::LoadBMP(const u8 *img, int imgSize) +{ + gdImagePtr gdImg = gdImageCreateFromBmpPtr(imgSize, (u8*) img); + if(gdImg == 0) + return; + + data = GDImageToRGBA8(&gdImg, &width, &height); + gdImageDestroy(gdImg); +} + +void GuiImageData::LoadTPL(const u8 *img, int imgSize) +{ + TplImage TplFile(img, imgSize); + + width = TplFile.GetWidth(0); + height = TplFile.GetHeight(0); + format = (u8) TplFile.GetFormat(0); + + const u8 * ImgPtr = TplFile.GetTextureBuffer(0); + + if(ImgPtr) + { + int len = ALIGN32(TplFile.GetTextureSize(0)); + + data = (u8 *) memalign(32, len); + if(!data) + return; + + memcpy(data, ImgPtr, len); + DCFlushRange(data, len); + } +} diff --git a/source/GUI/gui_imagedata.h b/source/GUI/gui_imagedata.h new file mode 100644 index 0000000..597f62a --- /dev/null +++ b/source/GUI/gui_imagedata.h @@ -0,0 +1,69 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef GUI_IMAGEDATA_H_ +#define GUI_IMAGEDATA_H_ + +#include +#include + +class GuiImageData +{ + public: + //!Constructor + //!\param img Image data + //!\param imgSize The image size + //!\param cache True if the resource manager should cache that address + GuiImageData(const u8 * img, int imgSize, bool cache = true); + //!Overload + GuiImageData(const char * filepath); + //!Destructor + ~GuiImageData(); + //!Gets a pointer to the image data + //!\return pointer to image data + u8 * GetImage() { return data; }; + //!Gets the image width + //!\return image width + int GetWidth() { return width; }; + //!Gets the image height + //!\return image height + int GetHeight() { return height; }; + //!Gets the texture format + u8 GetTextureFormat() { return format; }; + protected: + void LoadImage(const u8 * img, int imgSize); + void LoadPNG(const u8 *img, int imgSize); + void LoadBMP(const u8 *img, int imgSize); + void LoadJpeg(const u8 *img, int imgSize); + void LoadGIF(const u8 *img, int imgSize); + void LoadTPL(const u8 *img, int imgSize); + + u8 * data; //!< Image data + int height; //!< Height of image + int width; //!< Width of image + u8 format; //!< Texture format +}; + +#endif diff --git a/source/GUI/gui_keyboard.cpp b/source/GUI/gui_keyboard.cpp new file mode 100644 index 0000000..08a64b4 --- /dev/null +++ b/source/GUI/gui_keyboard.cpp @@ -0,0 +1,594 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_keyboard.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" +#include "../main.h" +#include "../settings/CSettings.h" +#include +#include +#include "themes/CTheme.h" +#include "menu.h" +/** + * Constructor for the GuiKeyboard class. + */ +//const Key thekeys; +GuiKeyboard::GuiKeyboard(char * t, u32 max, int minimum, int lang) +{ + width = 540; + height = 400; + shift = 0; + caps = 0; + alt = 0; + alt2 = 0; + min = minimum; + int mode = lang; + textVisible = true; + selectable = true; + alignmentHor = ALIGN_CENTER; + alignmentVert = ALIGN_MIDDLE; + kbtextmaxlen = max > sizeof(kbtextstr) ? sizeof(kbtextstr) : max; // limit max up to sizeof(kbtextstr) + memset(kbtextstr, 0, sizeof(kbtextstr)); + strncpy(kbtextstr, t, kbtextmaxlen); // strncpy is needed to fill the rest with \0 + kbtextstr[sizeof(kbtextstr) - 1] = 0; // terminate with \0 + //QWERTY// + if (mode == 0) + { + Key thekeys[4][11] = { + { + { '1', '!', '\0', '\0' }, + { '2', '@', '\0', '\0' }, + { '3', '#', '\0', '\0' }, + { '4', '$', '\0', '\0' }, + { '5', '%', '\0', '\0' }, + { '6', '^', '\0', '\0' }, + { '7', '&', '\0', '\0' }, + { '8', '*', '\0', '\0' }, + { '9', '(', '\0', '\0' }, + { '0', ')', '\0', '\0' }, + { '\0', '\0', '\0', '\0' } + }, + { + { 'q', 'Q', '\0', '\0' }, + { 'w', 'W', '\0', '\0' }, + { 'e', 'E', '\0', '\0' }, + { 'r', 'R', '\0', '\0' }, + { 't', 'T', '\0', '\0' }, + { 'y', 'Y', '\0', '\0' }, + { 'u', 'U', '\0', '\0' }, + { 'i', 'I', '\0', '\0' }, + { 'o', 'O', '\0', '\0' }, + { 'p', 'P', '\0', '\0' }, + { '-', '_', '\0', '\0' } + }, + { + { 'a', 'A', '\0', '\0' }, + { 's', 'S', '\0', '\0' }, + { 'd', 'D', '\0', '\0' }, + { 'f', 'F', '\0', '\0' }, + { 'g', 'G', '\0', '\0' }, + { 'h', 'H', '\0', '\0' }, + { 'j', 'J', '\0', '\0' }, + { 'k', 'K', '\0', '\0' }, + { 'l', 'L', '\0', '\0' }, + { ':', ';', '\0', '\0' }, + { '\'', '"', '\0', '\0' } + }, + { + { 'z', 'Z', '\0', '\0' }, + { 'x', 'X', '\0', '\0' }, + { 'c', 'C', '\0', '\0' }, + { 'v', 'V', '\0', '\0' }, + { 'b', 'B', '\0', '\0' }, + { 'n', 'N', '\0', '\0' }, + { 'm', 'M', '\0', '\0' }, + { ',', '<', '\0', '\0' }, + { '.', '>', '\0', '\0' }, + { '/', '?', '\0', '\0' }, + { '\0', '\0', '\0', '\0' } + } + }; + + memcpy(keys, thekeys, sizeof(thekeys)); + } + //DVORAK// + if (mode == 1) + { + Key thekeys[4][11] = { + { + { '1', '!', '\0', '\0' }, + { '2', '@', '\0', '\0' }, + { '3', '#', '\0', '\0' }, + { '4', '$', '\0', '\0' }, + { '5', '%', '\0', '\0' }, + { '6', '^', '\0', '\0' }, + { '7', '&', '\0', '\0' }, + { '8', '*', '\0', '\0' }, + { '9', '(', '\0', '\0' }, + { '0', ')', '\0', '\0' }, + { '\0', '\0', '\0', '\0' } + }, + { + { '\'', '"', '\0', '\0' }, + { ',', '<', '\0', '\0' }, + { '.', '>', '\0', '\0' }, + { 'p', 'P', '\0', '\0' }, + { 'y', 'Y', '\0', '\0' }, + { 'f', 'F', '\0', '\0' }, + { 'g', 'G', '\0', '\0' }, + { 'c', 'C', '\0', '\0' }, + { 'r', 'R', '\0', '\0' }, + { 'l', 'L', '\0', '\0' }, + { '/', '?', '\0', '\0' } + }, + { + { 'a', 'A', 'm', '\0' }, + { 'o', 'O', 'm', '\0' }, + { 'e', 'E', 'm', '\0' }, + { 'u', 'U', 'm', '\0' }, + { 'i', 'I', 'm', '\0' }, + { 'd', 'D', 'm', '\0' }, + { 'h', 'H', 'm', '\0' }, + { 't', 'T', 'm', '\0' }, + { 'n', 'N', 'm', '\0' }, + { 's', 'S', 'm', '\0' }, + { '-', '_', 'm', '\0' } + }, + { + { ';', ':', '\0', '\0' }, + { 'q', 'Q', '\0', '\0' }, + { 'j', 'J', '\0', '\0' }, + { 'k', 'K', '\0', '\0' }, + { 'x', 'X', '\0', '\0' }, + { 'b', 'B', '\0', '\0' }, + { 'm', 'M', '\0', '\0' }, + { 'w', 'W', '\0', '\0' }, + { 'v', 'V', '\0', '\0' }, + { 'z', 'Z', '\0', '\0' }, + { '\0', '\0', '\0', '\0' } + } + }; + memcpy(keys, thekeys, sizeof(thekeys)); + } + //QWETRZ// + if (mode == 2) + { + Key thekeys[4][11] = { { { '1', '!', '^', '' }, { '2', '"', '', '' }, { '3', '#', '', '' }, { '4', '$', + '', '' }, { '5', '%', '', '' }, { '6', '&', '', '' }, { '7', '/', '', '' }, { '8', '(', '[', + '' }, { '9', ')', ']', '' }, { '0', '=', '', '' }, { '', '?', '\'', '' } }, { { 'q', 'Q', '@', + '' }, { 'w', 'W', '\0', '' }, { 'e', 'E', '', '' }, { 'r', 'R', '\0', '' }, + { 't', 'T', '\0', '' }, { 'z', 'Z', '\0', '' }, { 'u', 'U', '\0', '' }, { 'i', 'I', '\0', '' }, { + 'o', 'O', '\0', '' }, { 'p', 'P', '\0', '' }, { '', '', '\0', '' } }, { { 'a', 'A', '\0', + '' }, { 's', 'S', '\0', '' }, { 'd', 'D', '\0', '' }, { 'f', 'F', '\0', '' }, + { 'g', 'G', '\0', '' }, { 'h', 'H', '\0', '' }, { 'j', 'J', '\0', '' }, { 'k', 'K', '\0', '' }, { + 'l', 'L', '\0', '' }, { '', '', '\0', '' }, { '', '', '\0', '' } }, { { '<', '>', '|', + '' }, { 'y', 'Y', '\0', '' }, { 'x', 'X', '\0', '' }, { 'c', 'C', '', '' }, + { 'v', 'V', '', '' }, { 'b', 'B', '\0', '' }, { 'n', 'N', '\0', '' }, { 'm', 'M', '', '' }, { + ',', ';', '\0', '' }, { '.', ':', '\0', '\0' }, { '-', '_', '\0', '\0' } } }; + memcpy(keys, thekeys, sizeof(thekeys)); + } + //AZERTY// + if (mode == 3) + { + Key thekeys[4][11] = { { { '1', '&', '', '' }, { '2', '~', '', '' }, { '3', '"', '#', '' }, { '4', '`', + '', '' }, { '5', '(', '[', '' }, { '6', '-', '|', '' }, { '7', '', '', '' }, { '8', '_', '\'', + '' }, { '9', '+', '^', '' }, { '0', '=', '@', '' }, { '', ')', ']', '' } }, { + { 'a', 'A', '', '' }, { 'z', 'Z', '', '' }, { 'e', 'E', '', '' }, { 'r', 'R', '', '' }, { 't', + 'T', '', '' }, { 'y', 'Y', '', '' }, { 'u', 'U', '', '' }, { 'i', 'I', '', '' }, { 'o', + 'O', '', '' }, { 'p', 'P', '', '' }, { '$', '', '', '' } }, { { 'q', 'Q', '', '' }, { + 's', 'S', '', '' }, { 'd', 'D', '\0', '' }, { 'f', 'F', '', '' }, { 'g', 'G', '\0', '' }, { 'h', + 'H', '\0', '' }, { 'j', 'J', '\0', '' }, { 'k', 'K', '\0', '' }, { 'l', 'L', '\0', '' }, { 'm', + 'M', '\0', '' }, { '*', '%', '', '' } }, { { '<', '>', '\0', '' }, { 'w', 'W', '\0', '' }, { 'x', + 'X', '\0', '' }, { 'c', 'C', '', '' }, { 'v', 'V', '', '' }, { 'b', 'B', '', '' }, { 'n', 'N', + '\0', '' }, { '?', ',', '?', '' }, { '.', ';', '.', '' }, { '/', ':', '/', '' }, { '', '!', '!', + '' } } }; + memcpy(keys, thekeys, sizeof(thekeys)); + } + //QWERTY 2// + if (mode == 4) + { + Key thekeys[4][11] = { { { '1', '!', '|', '' }, { '2', '"', '@', '' }, { '3', '', '#', '' }, { '4', '$', + '', '' }, { '5', '%', '~', '' }, { '6', '&', '', '' }, { '7', '/', '\'', '' }, { '8', '(', '[', + '' }, { '9', ')', ']', '' }, { '0', '=', '', '' }, { '', '?', '', '' } }, { { 'q', 'Q', '\0', + '' }, { 'w', 'W', '\0', '' }, { 'e', 'E', '', '' }, { 'r', 'R', '', '' }, { 't', 'T', '', '' }, + { 'y', 'Y', '', '' }, { 'u', 'U', '', '' }, { 'i', 'I', '', '' }, { 'o', 'O', '', '' }, { 'p', + 'P', '', '' }, { '+', '*', '\0', '' } }, { { 'a', 'A', '^', '' }, { 's', 'S', '', '' }, { + 'd', 'D', '', '' }, { 'f', 'F', '', '' }, { 'g', 'G', '', '' }, { 'h', 'H', '', '' }, { 'j', + 'J', '', '' }, { 'k', 'K', '', '' }, { 'l', 'L', '', '\0' }, { '', '', '+', '\0' }, { '', '', + '', '\0' } }, { { '<', '>', '\0', '' }, { 'z', 'Z', '\0', '' }, { 'x', 'X', '\0', '' }, { 'c', 'C', + '', '' }, { 'v', 'V', '\0', '' }, { 'b', 'B', '', '' }, { 'n', 'N', '\0', '' }, { 'm', 'M', '\0', + '' }, { ',', ';', '\0', '' }, { '.', ':', '\0', '\0' }, { '-', '_', '\0', '\0' } } }; + memcpy(keys, thekeys, sizeof(thekeys)); + } + + keyTextbox = Resources::GetImageData("keyboard_textbox.png"); + keyTextboxImg = new GuiImage(keyTextbox); + keyTextboxImg->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + keyTextboxImg->SetPosition(0, 40);//(0,0); + this->Append(keyTextboxImg); + + kbText = new GuiText(kbtextstr, 20, thColor("r=0 g=0 b=0 a=255 - keyboard text color")); + kbText->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + kbText->SetPosition(0, 53);//(0, 13); + this->Append(kbText); + + key = Resources::GetImageData("keyboard_key.png"); + keyOver = Resources::GetImageData("keyboard_key_over.png"); + keyMedium = Resources::GetImageData("keyboard_mediumkey_over.png"); + keyLarge = Resources::GetImageData("keyboard_largekey_over.png"); + + trigA = new GuiTrigger; + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigB = new GuiTrigger; + trigB->SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + int eurocheck = 0; + if (mode > 1) + { + eurocheck = -20; + } + + keyBackImg = new GuiImage(keyMedium); + keyBackOverImg = new GuiImage(keyMedium); + if (mode == 3) + { + keyBackText = new GuiText("Retour", 20, thColor("r=0 g=0 b=0 a=255 - keyboard key text color")); + } + else + { + keyBackText = new GuiText("Back", 20, thColor("r=0 g=0 b=0 a=255 - keyboard key text color")); + } + //keyBack = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight()); + keyBack = new GuiButton(keyBackImg, keyBackOverImg, 0, 3, 11 * 42 + 40 + eurocheck, 0 * 42 + 120, trigA, + btnSoundOver, btnSoundClick, 1); + //keyBack->SetImage(keyBackImg); + //keyBack->SetImageOver(keyBackOverImg); + keyBack->SetLabel(keyBackText); + //keyBack->SetSoundOver(btnSoundOver); + //keyBack->SetSoundClick(btnSoundClick); + //keyBack->SetTrigger(trigA); + keyBack->SetTrigger(trigB); + if (mode > 1) + { + keyBack->SetPosition(11 * 42 + 40 + eurocheck, 0 * 42 + 120); + } + else + { + keyBack->SetPosition(10 * 42 + 40 + eurocheck, 0 * 42 + 120); + }//(10*42+40, 0*42+80); + //keyBack->SetEffectGrow(); + this->Append(keyBack); + + keyClearImg = new GuiImage(keyMedium); + keyClearOverImg = new GuiImage(keyMedium); + if (mode == 3) + { + keyClearText = new GuiText("Effacer", 20, thColor("r=0 g=0 b=0 a=255 - keyboard key text color")); + } + else + { + keyClearText = new GuiText("Clear", 20, thColor("r=0 g=0 b=0 a=255 - keyboard key text color")); + } + keyClear = new GuiButton(keyClearImg, keyClearOverImg, 0, 3, (10 * 42 + 40) + eurocheck, 4 * 42 + 120, trigA, + btnSoundOver, btnSoundClick, 1); + //keyClear = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight()); + //keyClear->SetImage(keyClearImg); + //keyClear->SetImageOver(keyClearOverImg); + keyClear->SetLabel(keyClearText); + //keyClear->SetSoundOver(btnSoundOver); + //keyClear->SetSoundClick(btnSoundClick); + //keyClear->SetTrigger(trigA); + //keyClear->SetPosition((10*42+40)+eurocheck, 4*42+120);//(10*42+40, 0*42+80); + //keyClear->SetEffectGrow(); + this->Append(keyClear); + + keyAltImg = new GuiImage(keyMedium); + keyAltOverImg = new GuiImage(keyMedium); + keyAltText = new GuiText("Alt Gr", 20, thColor("r=0 g=0 b=0 a=255 - keyboard key text color")); + keyAlt = new GuiButton(keyAltImg, keyAltOverImg, 0, 3, 84 + eurocheck, 4 * 42 + 120, trigA, btnSoundOver, + btnSoundClick, 1); + //keyAlt = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight()); + //keyAlt->SetImage(keyAltImg); + //keyAlt->SetImageOver(keyAltOverImg); + keyAlt->SetLabel(keyAltText); + //keyAlt->SetSoundOver(btnSoundOver); + //keyAlt->SetSoundClick(btnSoundClick); + //keyAlt->SetTrigger(trigA); + //keyAlt->SetPosition(84+eurocheck, 4*42+120);//(10*42+40, 4*42+120); + //keyAlt->SetEffectGrow(); + if (mode > 1) + { + this->Append(keyAlt); + } + + keyAlt2Img = new GuiImage(keyMedium); + keyAlt2OverImg = new GuiImage(keyMedium); + keyAlt2Text = new GuiText("Accent", 20, thColor("r=0 g=0 b=0 a=255 - keyboard key text color")); + keyAlt2 = new GuiButton(keyAlt2Img, keyAlt2OverImg, 0, 3, (8 * 42 + 40) + eurocheck, 4 * 42 + 120, trigA, + btnSoundOver, btnSoundClick, 1); + //keyAlt2 = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight()); + //keyAlt2->SetImage(keyAlt2Img); + //keyAlt2->SetImageOver(keyAlt2OverImg); + keyAlt2->SetLabel(keyAlt2Text); + //keyAlt2->SetSoundOver(btnSoundOver); + //keyAlt2->SetSoundClick(btnSoundClick); + //keyAlt2->SetTrigger(trigA); + //keyAlt2->SetPosition((8*42+40)+eurocheck, 4*42+120);//(10*42+40, 4*42+120); + //keyAlt2->SetEffectGrow(); + if (mode > 1) + { + this->Append(keyAlt2); + } + + keyCapsImg = new GuiImage(keyMedium); + keyCapsOverImg = new GuiImage(keyMedium); + keyCapsText = new GuiText("Caps", 20, thColor("r=0 g=0 b=0 a=255 - keyboard key text color")); + keyCaps = new GuiButton(keyCapsImg, keyCapsOverImg, 0, 3, 0 + eurocheck, 2 * 42 + 120, trigA, btnSoundOver, + btnSoundClick, 1); + //keyCaps = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight()); + //keyCaps->SetImage(keyCapsImg); + //keyCaps->SetImageOver(keyCapsOverImg); + keyCaps->SetLabel(keyCapsText); + //keyCaps->SetSoundOver(btnSoundOver); + //keyCaps->SetSoundClick(btnSoundClick); + //keyCaps->SetTrigger(trigA); + //keyCaps->SetPosition(0+eurocheck, 2*42+120);//(0, 2*42+80); + //keyCaps->SetEffectGrow(); + this->Append(keyCaps); + + keyShiftImg = new GuiImage(keyMedium); + keyShiftOverImg = new GuiImage(keyMedium); + keyShiftText = new GuiText("Shift", 20, thColor("r=0 g=0 b=0 a=255 - keyboard key text color")); + keyShift = new GuiButton(keyShiftImg, keyShiftOverImg, 0, 3, 21 + eurocheck, 3 * 42 + 120, trigA, btnSoundOver, + btnSoundClick, 1); + //keyShift = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight()); + //keyShift->SetImage(keyShiftImg); + //keyShift->SetImageOver(keyShiftOverImg); + keyShift->SetLabel(keyShiftText); + //keyShift->SetSoundOver(btnSoundOver); + //keyShift->SetSoundClick(btnSoundClick); + //keyShift->SetTrigger(trigA); + //keyShift->SetPosition(21+eurocheck, 3*42+120);//(21, 3*42+80); + //keyShift->SetEffectGrow(); + this->Append(keyShift); + + keySpaceImg = new GuiImage(keyLarge); + keySpaceOverImg = new GuiImage(keyLarge); + keySpace = new GuiButton(keySpaceImg, keySpaceOverImg, 2, 3, 0 + eurocheck, 4 * 42 + 120, trigA, btnSoundOver, + btnSoundClick, 1); + //keySpace = new GuiButton(keyLarge->GetWidth(), keyLarge->GetHeight()); + //keySpace->SetImage(keySpaceImg); + //keySpace->SetImageOver(keySpaceOverImg); + //keySpace->SetSoundOver(btnSoundOver); + //keySpace->SetSoundClick(btnSoundClick); + //keySpace->SetTrigger(trigA); + //keySpace->SetPosition(0+eurocheck, 4*42+120);//(0, 4*42+80); + //keySpace->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + //keySpace->SetEffectGrow(); + this->Append(keySpace); + + char txt[2] = { 0, 0 }; + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 11; j++) + { + if (keys[i][j].ch != '\0') + { + keyImg[i][j] = new GuiImage(key); + keyImgOver[i][j] = new GuiImage(keyOver); + txt[0] = keys[i][j].ch; + keyTxt[i][j] = new GuiText(txt, 20, thColor("r=0 g=0 b=0 a=255 - keyboard key text color")); + keyTxt[i][j]->SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + keyTxt[i][j]->SetPosition(0, -10); + keyBtn[i][j] = new GuiButton(keyImg[i][j], keyImgOver[i][j], 0, 3, (j * 42 + 21 * i + 40) + eurocheck, + i * 42 + 120, trigA, btnSoundOver, btnSoundClick, 1); + //keyBtn[i][j] = new GuiButton(key->GetWidth(), key->GetHeight()); + //keyBtn[i][j]->SetImage(keyImg[i][j]); + //keyBtn[i][j]->SetImageOver(keyImgOver[i][j]); + //keyBtn[i][j]->SetSoundOver(btnSoundOver); + //keyBtn[i][j]->SetSoundClick(btnSoundClick); + //keyBtn[i][j]->SetTrigger(trigA); + keyBtn[i][j]->SetLabel(keyTxt[i][j]); + //keyBtn[i][j]->SetPosition((j*42+21*i+40)+eurocheck, i*42+120);//SetPosition(j*42+21*i+40, i*42+80); + //keyBtn[i][j]->SetEffectGrow(); + this->Append(keyBtn[i][j]); + } + } + } +} + +/** + * Destructor for the GuiKeyboard class. + */ +GuiKeyboard::~GuiKeyboard() +{ + delete kbText; + delete keyTextbox; + delete keyTextboxImg; + delete keyCapsText; + delete keyCapsImg; + delete keyCapsOverImg; + delete keyCaps; + delete keyShiftText; + delete keyShiftImg; + delete keyShiftOverImg; + delete keyShift; + if (keyAlt) + { + delete keyAlt; + } + if (keyAlt2) + { + delete keyAlt2; + } + delete keyBackText; + delete keyBackImg; + delete keyBackOverImg; + delete keyBack; + delete keySpaceImg; + delete keySpaceOverImg; + delete keySpace; + delete key; + delete keyOver; + delete keyMedium; + delete keyLarge; + delete trigA; + delete trigB; + + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 11; j++) + { + if (keys[i][j].ch != '\0') + { + delete keyImg[i][j]; + delete keyImgOver[i][j]; + delete keyTxt[i][j]; + delete keyBtn[i][j]; + } + } + } +} + +void GuiKeyboard::SetDisplayText(const char *text) +{ + if(!text || textVisible) + { + kbText->SetText(text); + } + else + { + std::string asterix(strlen(text), '*'); + kbText->SetText(asterix.c_str()); + } +} + +void GuiKeyboard::Update(GuiTrigger * t) +{ + LOCK( this ); + if (_elements.size() == 0 || (state == STATE_DISABLED && parentElement)) return; + + for (u8 i = 0; i < _elements.size(); i++) + { + try + { + _elements.at(i)->Update(t); + } + catch (const std::exception& e) + { + } + } + + bool changedShiftKey = false; + + if (keySpace->GetState() == STATE_CLICKED) + { + if (strlen(kbtextstr) < kbtextmaxlen - 1) // -1 --> kbtextmaxlen means with terminating '\0' + { + kbtextstr[strlen(kbtextstr)] = ' '; + SetDisplayText(kbtextstr); + } + keySpace->SetState(STATE_SELECTED, t->chan); + } + else if (keyBack->GetState() == STATE_CLICKED) + { + if (strlen(kbtextstr) > min) + { + kbtextstr[strlen(kbtextstr) - 1] = 0; + SetDisplayText(kbtextstr); + } + keyBack->SetState(STATE_SELECTED, t->chan); + } + else if (keyClear->GetState() == STATE_CLICKED) + { + while (strlen(kbtextstr) > min) + { + kbtextstr[strlen(kbtextstr) - 1] = 0; + } + SetDisplayText(kbtextstr); + keyClear->SetState(STATE_SELECTED, t->chan); + } + else if (keyShift->GetState() == STATE_CLICKED) + { + changedShiftKey = true; + shift ^= 1; + if (alt) alt ^= 1; + if (alt2) alt2 ^= 1; + keyShift->SetState(STATE_SELECTED, t->chan); + } + else if (keyAlt->GetState() == STATE_CLICKED) + { + changedShiftKey = true; + alt ^= 1; + if (shift) shift ^= 1; + if (alt2) alt2 ^= 1; + keyAlt->SetState(STATE_SELECTED, t->chan); + } + else if (keyAlt2->GetState() == STATE_CLICKED) + { + changedShiftKey = true; + alt2 ^= 1; + if (shift) shift ^= 1; + if (alt) alt ^= 1; + keyAlt2->SetState(STATE_SELECTED, t->chan); + } + else if (keyCaps->GetState() == STATE_CLICKED) + { + changedShiftKey = true; + caps ^= 1; + keyCaps->SetState(STATE_SELECTED, t->chan); + } + + bool update = false; + + char txt[2] = { 0, 0 }; + + do + { + update = false; + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 11; j++) + { + if (keys[i][j].ch != '\0') + { + if (shift || caps) + txt[0] = keys[i][j].chShift; + else if (alt) + txt[0] = keys[i][j].chalt; + else if (alt2) + txt[0] = keys[i][j].chalt2; + else txt[0] = keys[i][j].ch; + + if (changedShiftKey) // change text only if needed + keyTxt[i][j]->SetText(txt); + + if (keyBtn[i][j]->GetState() == STATE_CLICKED) + { + if (strlen(kbtextstr) < kbtextmaxlen - 1) // -1 --> kbtextmaxlen means with term. '\0' + { + kbtextstr[strlen(kbtextstr)] = txt[0]; + SetDisplayText(kbtextstr); + } + keyBtn[i][j]->SetState(STATE_SELECTED, t->chan); + + if (shift || alt || alt2) + { + if (shift) shift ^= 1; + if (alt) alt ^= 1; + if (alt2) alt2 ^= 1; + update = true; + changedShiftKey = true; + } + } + } + } + } + } while (update); +} diff --git a/source/GUI/gui_numpad.cpp b/source/GUI/gui_numpad.cpp new file mode 100644 index 0000000..f295f3a --- /dev/null +++ b/source/GUI/gui_numpad.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** + * Copyright (C) 2009 r-win + * Copyright (C) 2012 Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "gui_numpad.h" +#include "main.h" +#include "language/gettext.h" +#include "settings/CSettings.h" +#include "themes/CTheme.h" +/** + * Constructor for the GuiNumpad class. + */ + +GuiNumpad::GuiNumpad(char * t, u32 max) +{ + width = 400; + height = 370; + selectable = true; + alignmentHor = ALIGN_CENTER; + alignmentVert = ALIGN_MIDDLE; + kbtextmaxlen = max > sizeof(kbtextstr) ? sizeof(kbtextstr) : max; // limit max up to sizeof(kbtextstr) + strncpy(kbtextstr, t, kbtextmaxlen); // strncpy is needed to fill the rest with \0 + kbtextstr[sizeof(kbtextstr) - 1] = 0; // terminate with \0 + + char thekeys[12] = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '0', '.'}; + memcpy(keys, thekeys, sizeof(thekeys)); + + keyTextbox = Resources::GetImageData("keyboard_textbox.png"); + keyTextboxImg = new GuiImage(keyTextbox); + keyTextboxImg->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + keyTextboxImg->SetPosition(0, 0); + this->Append(keyTextboxImg); + + kbText = new GuiText(kbtextstr, 20, ( GXColor ) thColor("r=0 g=0 b=0 a=255 - numpad text color")); + kbText->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + kbText->SetPosition(0, 10); + this->Append(kbText); + + keyMedium = Resources::GetImageData("keyboard_mediumkey_over.png"); + + trigA = new GuiTrigger; + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigB = new GuiTrigger; + trigB->SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + keyBackImg = new GuiImage(keyMedium); + keyBackText = new GuiText(tr("Back"), 20, (GXColor) thColor("r=0 g=0 b=0 a=255 - numpad key text color")); + + keyBack = new GuiButton(keyBackImg, keyBackImg, ALIGN_CENTER, ALIGN_MIDDLE, 90, 90, trigA, btnSoundOver, btnSoundClick, 1); + keyBack->SetLabel(keyBackText); + keyBack->SetTrigger(trigB); + this->Append(keyBack); + + keyClearImg = new GuiImage(keyMedium); + keyClearText = new GuiText(tr("Clear"), 20, ( GXColor ) thColor("r=0 g=0 b=0 a=255 - numpad key text color")); + keyClear = new GuiButton(keyClearImg, keyClearImg, ALIGN_CENTER, ALIGN_MIDDLE, -90, 90, trigA, btnSoundOver, btnSoundClick, 1); + keyClear->SetLabel(keyClearText); + this->Append(keyClear); + + char txt[2] = { 0, 0 }; + for (int i = 0; i < NUMPAD_BUTTONS; i++) + { + int col = i % 3; + int row = i / 3; + + txt[0] = keys[i]; + keyImg[i] = new GuiImage(keyMedium); + keyTxt[i] = new GuiText(txt, 20, (GXColor) thColor("r=0 g=0 b=0 a=255 - numpad key text color")); + keyTxt[i]->SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + keyTxt[i]->SetPosition(0, -10); + keyBtn[i] = new GuiButton(keyImg[i], keyImg[i], ALIGN_CENTER, ALIGN_MIDDLE, -90 + 90 * col, -110 + 50 + * row, trigA, btnSoundOver, btnSoundClick, 1); + keyBtn[i]->SetLabel(keyTxt[i]); + + this->Append(keyBtn[i]); + } +} + +/** + * Destructor for the GuiKeyboard class. + */ +GuiNumpad::~GuiNumpad() +{ + delete kbText; + delete keyTextbox; + delete keyTextboxImg; + delete keyBackText; + delete keyBackImg; + delete keyBack; + delete keyClearText; + delete keyClearImg; + delete keyClear; + delete keyMedium; + delete trigA; + delete trigB; + + for (int i = 0; i < NUMPAD_BUTTONS; i++) + { + delete keyImg[i]; + delete keyTxt[i]; + delete keyBtn[i]; + } +} + +void GuiNumpad::Update(GuiTrigger * t) +{ + GuiWindow::Update(t); + + LOCK( this ); + + if (keyBack->GetState() == STATE_CLICKED) + { + if (strlen(kbtextstr) > 0) + { + kbtextstr[strlen(kbtextstr) - 1] = 0; + kbText->SetText(kbtextstr); + } + keyBack->SetState(STATE_SELECTED, t->chan); + } + else if (keyClear->GetState() == STATE_CLICKED) + { + memset(kbtextstr, 0, sizeof(kbtextstr)); + kbText->SetText(kbtextstr); + keyClear->SetState(STATE_SELECTED, t->chan); + } + + for (int i = 0; i < NUMPAD_BUTTONS; i++) + { + if (keyBtn[i]->GetState() == STATE_CLICKED) + { + if (strlen(kbtextstr) < kbtextmaxlen - 1) // -1 --> kbtextmaxlen means with term. '\0' + { + int len = strlen(kbtextstr); + kbtextstr[len] = keys[i]; + kbtextstr[len+1] = 0; + kbText->SetText(kbtextstr); + } + keyBtn[i]->SetState(STATE_SELECTED, t->chan); + } + } +} diff --git a/source/GUI/gui_numpad.h b/source/GUI/gui_numpad.h new file mode 100644 index 0000000..e8d03bb --- /dev/null +++ b/source/GUI/gui_numpad.h @@ -0,0 +1,66 @@ +/**************************************************************************** + * Copyright (C) 2009 r-win + * Copyright (C) 2012 Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GUI_NUMPAD_H_ +#define GUI_NUMPAD_H_ + +#include "gui.h" + +#define NUMPAD_BUTTONS 12 + +//!On-screen keyboard +class GuiNumpad: public GuiWindow +{ + public: + GuiNumpad(char * t, u32 max); + virtual ~GuiNumpad(); + const char *GetText() const { return kbtextstr; } + void Update(GuiTrigger * t); + protected: + u32 kbtextmaxlen; + char keys[NUMPAD_BUTTONS]; + char kbtextstr[256]; + GuiText * kbText; + + GuiText * keyBackText; + GuiImage * keyBackImg; + GuiButton * keyBack; + + GuiText * keyClearText; + GuiImage * keyClearImg; + GuiButton * keyClear; + + GuiButton * keyBtn[NUMPAD_BUTTONS]; + GuiImage * keyImg[NUMPAD_BUTTONS]; + GuiText * keyTxt[NUMPAD_BUTTONS]; + + GuiImage * keyTextboxImg; + + GuiImageData * keyTextbox; + GuiImageData * keyMedium; + + GuiTrigger * trigA; + GuiTrigger * trigB; +}; + +#endif diff --git a/source/GUI/gui_optionbrowser.cpp b/source/GUI/gui_optionbrowser.cpp new file mode 100644 index 0000000..70501cd --- /dev/null +++ b/source/GUI/gui_optionbrowser.cpp @@ -0,0 +1,276 @@ +/**************************************************************************** + * libwiigui + * + * gui_customoptionbrowser.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" +#include "../wpad.h" +#include "../main.h" +#include "../gecko.h" +#include "../settings/CSettings.h" +#include "gui_optionbrowser.h" +#include "themes/CTheme.h" +#include "utils/tools.h" +#include "menu.h" + +#include + +#define GAMESELECTSIZE 30 + +/** +GuiOptionBrowser * Constructor for the GuiOptionBrowser class. + */ +GuiOptionBrowser::GuiOptionBrowser(int w, int h, OptionList * l, const char * custombg) + : scrollBar(h-10) +{ + width = w; + height = h; + options = l; + selectable = true; + selectedItem = 0; + oldSelectedItem = -1; + coL2 = 50; + listOffset = 0; + + trigA = new GuiTrigger; + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + bgOptions = Resources::GetImageData(custombg); + + bgOptionsImg = new GuiImage(bgOptions); + bgOptionsImg->SetParent(this); + bgOptionsImg->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + + bgOptionsEntry = Resources::GetImageData("bg_options_entry.png"); + + scrollBar.SetParent(this); + scrollBar.SetAlignment(thAlign("right - options browser scrollbar align hor"), thAlign("top - options browser scrollbar align ver")); + scrollBar.SetPosition(thInt("0 - options browser scrollbar pos x"), thInt("5 - options browser scrollbar pos y")); + scrollBar.listChanged.connect(this, &GuiOptionBrowser::onListChange); + + optionBtn.resize(PAGESIZE); + optionBg.resize(PAGESIZE); + optionTxt.resize(PAGESIZE); + optionVal.resize(PAGESIZE); + + for (int i = 0; i < PAGESIZE; i++) + { + optionTxt[i] = new GuiText((wchar_t *) NULL, 20, thColor("r=0 g=0 b=0 a=255 - settings text color")); + optionTxt[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + optionTxt[i]->SetPosition(24, 0); + optionTxt[i]->SetMaxWidth(bgOptionsImg->GetWidth()-scrollBar.GetWidth()-40, DOTTED); + + optionBg[i] = new GuiImage(bgOptionsEntry); + + optionVal[i] = new GuiText((wchar_t *) NULL, 20, thColor("r=0 g=0 b=0 a=255 - settings text color")); + optionVal[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + + optionBtn[i] = new GuiButton(width - scrollBar.GetWidth(), GAMESELECTSIZE); + optionBtn[i]->SetParent(this); + optionBtn[i]->SetLabel(optionTxt[i], 0); + optionBtn[i]->SetLabel(optionVal[i], 1); + optionBtn[i]->SetImageOver(optionBg[i]); + optionBtn[i]->SetPosition(10, GAMESELECTSIZE * i + 4); + optionBtn[i]->SetRumble(false); + optionBtn[i]->SetTrigger(trigA); + optionBtn[i]->SetSoundClick(btnSoundClick); + } +} + +/** + * Destructor for the GuiOptionBrowser class. + */ +GuiOptionBrowser::~GuiOptionBrowser() +{ + delete bgOptionsImg; + delete bgOptions; + delete bgOptionsEntry; + + delete trigA; + + for (int i = 0; i < PAGESIZE; i++) + { + delete optionTxt[i]; + delete optionVal[i]; + delete optionBg[i]; + delete optionBtn[i]; + } +} + +void GuiOptionBrowser::ResetState() +{ + if (state != STATE_DISABLED) + { + state = STATE_DEFAULT; + stateChan = -1; + } + + for (u32 i = 0; i < optionBtn.size(); i++) + { + optionBtn[i]->ResetState(); + } +} + +int GuiOptionBrowser::GetClickedOption() +{ + for (u32 i = 0; i < optionBtn.size(); i++) + { + if (optionBtn[i]->GetState() == STATE_CLICKED) + { + optionBtn[i]->SetState(STATE_SELECTED); + return listOffset + i; + } + } + + return -1; +} + +int GuiOptionBrowser::GetSelectedOption() +{ + for (u32 i = 0; i < optionBtn.size(); i++) + { + if (optionBtn[i]->GetState() == STATE_SELECTED) + { + return listOffset + i; + } + } + return -1; +} + +void GuiOptionBrowser::SetOffset(int optionnumber) +{ + listOffset = optionnumber; + selectedItem = optionnumber; +} + +void GuiOptionBrowser::onListChange(int SelItem, int SelInd) +{ + selectedItem = SelItem; + listOffset = SelInd; + UpdateListEntries(); +} + +/** + * Draw the button on screen + */ +void GuiOptionBrowser::Draw() +{ + if (!this->IsVisible()) return; + + bgOptionsImg->Draw(); + + for (u32 i = 0; i < optionBtn.size(); i++) + { + if (listOffset + i < (u32) options->GetLength()) + { + optionBtn[i]->Draw(); + } + } + + scrollBar.Draw(); + + this->UpdateEffects(); +} + +void GuiOptionBrowser::UpdateListEntries() +{ + LOCK(this); + if (listOffset < 0) + listOffset = 0; + + int maxNameWidth = 0; + for (u32 i = 0; i < optionBtn.size(); i++) + { + if (listOffset + i < (u32) options->GetLength()) + { + if (optionBtn[i]->GetState() == STATE_DISABLED) + { + optionBtn[i]->SetVisible(true); + optionBtn[i]->SetState(STATE_DEFAULT); + } + + optionTxt[i]->SetText(options->GetName(listOffset+i)); + if (maxNameWidth < optionTxt[i]->GetTextWidth()) maxNameWidth = optionTxt[i]->GetTextWidth(); + optionVal[i]->SetText(options->GetValue(listOffset+i)); + } + else + { + optionBtn[i]->SetVisible(false); + optionBtn[i]->SetState(STATE_DISABLED); + } + } + + if (coL2 < (24 + maxNameWidth + 16)) + coL2 = 24 + maxNameWidth + 16; + + for (u32 i = 0; i < optionBtn.size(); i++) + { + if (optionBtn[i]->GetState() != STATE_DISABLED) + { + optionVal[i]->SetPosition(coL2, 0); + optionVal[i]->SetMaxWidth(bgOptionsImg->GetWidth() - (coL2 + scrollBar.GetWidth()+10), DOTTED); + } + } + + oldSelectedItem = -1; +} + +void GuiOptionBrowser::Update(GuiTrigger * t) +{ + if (state == STATE_DISABLED || !t) return; + + int listSize = optionBtn.size(); + static int pressedChan = -1; + + if((t->wpad.btns_d & (WPAD_BUTTON_B | WPAD_BUTTON_DOWN | WPAD_BUTTON_UP | WPAD_BUTTON_LEFT | WPAD_BUTTON_RIGHT | + WPAD_CLASSIC_BUTTON_B | WPAD_CLASSIC_BUTTON_UP | WPAD_CLASSIC_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_RIGHT)) || + (t->pad.btns_d & (PAD_BUTTON_UP | PAD_BUTTON_DOWN))) + pressedChan = t->chan; + + // update the location of the scroll box based on the position in the option list + scrollBar.Update(t); + + if(pressedChan == -1 || (!t->wpad.btns_h && !t->pad.btns_h)) + { + for(int i = 0; i < listSize; i++) + { + if (i != selectedItem && optionBtn[i]->GetState() == STATE_SELECTED) + { + optionBtn[i]->ResetState(); + } + else if (i == selectedItem && optionBtn[i]->GetState() == STATE_DEFAULT) + { + optionBtn[selectedItem]->SetState(STATE_SELECTED); + } + + optionBtn[i]->Update(t); + + if (optionBtn[i]->GetState() == STATE_SELECTED) + selectedItem = i; + } + } + + if(pressedChan == t->chan && !t->wpad.btns_d && !t->wpad.btns_h) + pressedChan = -1; + + if(selectedItem != oldSelectedItem) + { + if(oldSelectedItem >= 0 && oldSelectedItem < listSize) + optionVal[oldSelectedItem]->SetMaxWidth(bgOptionsImg->GetWidth() - (coL2 + scrollBar.GetWidth()+10), DOTTED); + if(selectedItem >= 0 && selectedItem < listSize) + optionVal[selectedItem]->SetMaxWidth(bgOptionsImg->GetWidth() - (coL2 + scrollBar.GetWidth()+10), SCROLL_HORIZONTAL); + + oldSelectedItem = selectedItem; + } + + scrollBar.SetPageSize(listSize); + scrollBar.SetSelectedItem(selectedItem); + scrollBar.SetSelectedIndex(listOffset); + scrollBar.SetEntrieCount(options->GetLength()); + + if (options->IsChanged()) + UpdateListEntries(); +} diff --git a/source/GUI/gui_optionbrowser.h b/source/GUI/gui_optionbrowser.h new file mode 100644 index 0000000..bd2eb47 --- /dev/null +++ b/source/GUI/gui_optionbrowser.h @@ -0,0 +1,44 @@ +#ifndef GUI_OPTIONBROWSER_H_ +#define GUI_OPTIONBROWSER_H_ + +#include "gui.h" +#include "gui_scrollbar.hpp" +#include + +//!Display a list of menu options +class GuiOptionBrowser: public GuiElement, public sigslot::has_slots<> +{ + public: + GuiOptionBrowser(int w, int h, OptionList * l, const char * background); + virtual ~GuiOptionBrowser(); + int GetClickedOption(); + int GetSelectedOption(); + void SetOffset(int optionnumber); + void ResetState(); + void Draw(); + void Update(GuiTrigger * t); + protected: + void onListChange(int SelItem, int SelInd); + void UpdateListEntries(); + + int oldSelectedItem; + int selectedItem; + int listOffset; + int coL2; + + OptionList * options; + std::vector optionBtn; + std::vector optionTxt; + std::vector optionVal; + std::vector optionBg; + + GuiImage * bgOptionsImg; + + GuiImageData * bgOptions; + GuiImageData * bgOptionsEntry; + + GuiTrigger * trigA; + GuiScrollbar scrollBar; +}; + +#endif diff --git a/source/GUI/gui_plus.cpp b/source/GUI/gui_plus.cpp new file mode 100644 index 0000000..5ef717a --- /dev/null +++ b/source/GUI/gui_plus.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** + * Copyright (C) 2012 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "gui_plus.hpp" + +void GuiPlus::Draw() +{ + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); + + f32 x1 = GetLeft() + width*0.15f; + f32 x2 = GetLeft() + width*0.5f; + f32 x3 = GetLeft() + width - width*0.15f; + f32 y1 = GetTop() + height*0.15f; + f32 y2 = GetTop() + height*0.5f; + f32 y3 = GetTop() + height - height*0.15f; + + int alpha = GetAlpha(); + + GX_Begin(GX_LINES, GX_VTXFMT0, 4); + GX_Position3f32(x2, y1, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_Position3f32(x2, y3, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_Position3f32(x1, y2, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_Position3f32(x3, y2, 0.0f); + GX_Color4u8(color.r, color.g, color.b, alpha); + GX_End(); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); +} diff --git a/source/GUI/gui_plus.hpp b/source/GUI/gui_plus.hpp new file mode 100644 index 0000000..97a6eb5 --- /dev/null +++ b/source/GUI/gui_plus.hpp @@ -0,0 +1,43 @@ +/**************************************************************************** + * Copyright (C) 2012 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GUIPLUS_HPP_ +#define GUIPLUS_HPP_ + +#include "GUI/gui.h" + +class GuiPlus : public GuiElement +{ + public: + GuiPlus() : Linewidth(2.0f) { color = (GXColor) {0, 0, 0, 255}; GX_SetLineWidth((u8) (Linewidth*6.0f), 0); } + //! Max line width is 42.5 pixel + void SetLinewidth(float w) { LOCK(this); Linewidth = w; GX_SetLineWidth((u8) (Linewidth*6.0f), 0); } + void SetColor(const GXColor c) { LOCK(this); color = c; } + void SetSize(int w, int h) { LOCK(this); width = w; height = h; } + void Draw(); + protected: + GXColor color; + float Linewidth; +}; + +#endif diff --git a/source/GUI/gui_scrollbar.cpp b/source/GUI/gui_scrollbar.cpp new file mode 100644 index 0000000..7af3164 --- /dev/null +++ b/source/GUI/gui_scrollbar.cpp @@ -0,0 +1,501 @@ +/*************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "themes/Resources.h" +#include "menu/menus.h" +#include "gui_scrollbar.hpp" +#include "utils/tools.h" + +GuiScrollbar::GuiScrollbar(int h, u8 m) +{ + SelItem = 0; + SelInd = 0; + RowSize = 0; + PageSize = 0; + EntrieCount = 0; + ScrollSpeed = 15; + ButtonScroll = 0; + ButtonScrollSpeed = 20; + ScrollState = 0; + pressedChan = -1; + AllowDPad = true; + MovePointer = false; + Mode = m; + listChanged.connect(this, &GuiScrollbar::setScrollboxPosition); + + scrollbarTop = Resources::GetImageData("scrollBarTop.png"); + scrollbarBottom = Resources::GetImageData("scrollBarBottom.png"); + scrollbarTile = Resources::GetImageData("scrollBarTile.png"); + arrowDown = Resources::GetImageData("scrollbar_arrowdown.png"); + arrowDownOver = Resources::GetImageData("scrollbar_arrowdown.png"); + arrowUp = Resources::GetImageData("scrollbar_arrowup.png"); + arrowUpOver = Resources::GetImageData("scrollbar_arrowup.png"); + scrollbarBox = Resources::GetImageData("scrollbar_box.png"); + scrollbarBoxOver = Resources::GetImageData("scrollbar_box.png"); + oneButtonScrollImgData = Resources::GetImageData("oneButtonScroll.png"); + + height = h; + width = MAX(scrollbarBox->GetWidth(), scrollbarTile->GetWidth()); + + MinHeight = arrowUp->GetHeight(); + MaxHeight = height-scrollbarBox->GetHeight()-arrowDown->GetHeight(); + + trigHeldA = new GuiTrigger; + trigHeldA->SetHeldTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + int Tiles = (height-scrollbarTop->GetHeight()-scrollbarBottom->GetHeight())/4; + int PositionY = 0; + ButtonPositionX = 0; + + oneButtonScrollImg = new GuiImage(oneButtonScrollImgData); + + scrollbarTopImg = new GuiImage(scrollbarTop); + scrollbarTopImg->SetParent(this); + scrollbarTopImg->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + scrollbarTopImg->SetPosition(0, PositionY); + PositionY += scrollbarTop->GetHeight(); + + scrollbarTileImg = new GuiImage(scrollbarTile); + scrollbarTileImg->SetParent(this); + scrollbarTileImg->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + scrollbarTileImg->SetPosition(0, PositionY); + scrollbarTileImg->SetTileVertical(Tiles); + PositionY += Tiles*scrollbarTile->GetHeight(); + + scrollbarBottomImg = new GuiImage(scrollbarBottom); + scrollbarBottomImg->SetParent(this); + scrollbarBottomImg->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + scrollbarBottomImg->SetPosition(0, PositionY); + + arrowDownImg = new GuiImage(arrowDown); + arrowDownOverImg = new GuiImage(arrowDownOver); + arrowUpImg = new GuiImage(arrowUp); + arrowUpOverImg = new GuiImage(arrowUpOver); + scrollbarBoxImg = new GuiImage(scrollbarBox); + scrollbarBoxOverImg = new GuiImage(scrollbarBoxOver); + + arrowUpBtn = new GuiButton(arrowUpImg->GetWidth(), arrowUpImg->GetHeight()); + arrowUpBtn->SetParent(this); + arrowUpBtn->SetImage(arrowUpImg); + arrowUpBtn->SetImageOver(arrowUpOverImg); + arrowUpBtn->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + arrowUpBtn->SetPosition(ButtonPositionX, 0); + arrowUpBtn->SetHoldable(true); + arrowUpBtn->SetTrigger(trigHeldA); + arrowUpBtn->SetSoundOver(btnSoundOver); + arrowUpBtn->SetSoundClick(btnSoundClick); + arrowUpBtn->Held.connect(this, &GuiScrollbar::OnUpButtonHold); + + arrowDownBtn = new GuiButton(arrowDownImg->GetWidth(), arrowDownImg->GetHeight()); + arrowDownBtn->SetParent(this); + arrowDownBtn->SetImage(arrowDownImg); + arrowDownBtn->SetImageOver(arrowDownOverImg); + arrowDownBtn->SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + arrowDownBtn->SetPosition(ButtonPositionX, 0); + arrowDownBtn->SetHoldable(true); + arrowDownBtn->SetTrigger(trigHeldA); + arrowDownBtn->SetSoundOver(btnSoundOver); + arrowDownBtn->SetSoundClick(btnSoundClick); + arrowDownBtn->Held.connect(this, &GuiScrollbar::OnDownButtonHold); + + scrollbarBoxBtn = new GuiButton(scrollbarBoxImg->GetWidth(), scrollbarBoxImg->GetHeight()); + scrollbarBoxBtn->SetParent(this); + scrollbarBoxBtn->SetImage(scrollbarBoxImg); + scrollbarBoxBtn->SetImageOver(scrollbarBoxOverImg); + scrollbarBoxBtn->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + scrollbarBoxBtn->SetPosition(ButtonPositionX, MinHeight); + scrollbarBoxBtn->SetMinY(MinHeight); + scrollbarBoxBtn->SetMaxY(MaxHeight); + scrollbarBoxBtn->SetHoldable(true); + scrollbarBoxBtn->SetTrigger(trigHeldA); + scrollbarBoxBtn->Held.connect(this, &GuiScrollbar::OnBoxButtonHold); +} + +GuiScrollbar::~GuiScrollbar() +{ + delete scrollbarTop; + delete scrollbarBottom; + delete scrollbarTile; + delete arrowDown; + delete arrowDownOver; + delete arrowUp; + delete arrowUpOver; + delete scrollbarBox; + delete scrollbarBoxOver; + delete oneButtonScrollImg; + + delete arrowUpBtn; + delete arrowDownBtn; + delete scrollbarBoxBtn; + + delete scrollbarTopImg; + delete scrollbarBottomImg; + delete scrollbarTileImg; + delete arrowDownImg; + delete arrowDownOverImg; + delete arrowUpImg; + delete arrowUpOverImg; + delete scrollbarBoxImg; + delete scrollbarBoxOverImg; + delete oneButtonScrollImgData; + + delete trigHeldA; +} + +void GuiScrollbar::ScrollOneUp() +{ + if(Mode == ICONMODE) + { + if(SelInd+SelItem-RowSize >= 0) + { + SelItem = SelItem-RowSize; + if(SelItem < 0) + { + // move list up by 1 + SelInd = SelInd-RowSize; + SelItem = SelItem+RowSize; + } + } + } + else if(Mode == LISTMODE) + { + if(SelItem == 0 && SelInd > 0) + { + // move list up by 1 + --SelInd; + } + else if(SelInd+SelItem > 0) + { + --SelItem; + } + } +} + +void GuiScrollbar::ScrollOneDown() +{ + if(Mode == ICONMODE) + { + int i = RowSize; + while(SelInd+SelItem+RowSize >= EntrieCount && i > 0 && SelItem > 0 && RowSize < EntrieCount) + { + --i; + --SelItem; + } + if(SelInd+SelItem+RowSize < EntrieCount) + { + SelItem = SelItem+RowSize; + if(SelItem >= PageSize) + { + // move list down by 1 + SelInd += RowSize; + SelItem = SelItem-RowSize; + } + } + } + else if(Mode == LISTMODE) + { + if(SelInd+SelItem + 1 < EntrieCount) + { + if(SelItem == PageSize-1) + { + // move list down by 1 + SelInd++; + } + else + { + SelItem++; + } + } + } +} + +void GuiScrollbar::OnUpButtonHold(GuiButton *sender, int pointer, const POINT &p) +{ + if(ScrollState < ScrollSpeed) + return; + + ScrollOneUp(); + + ScrollState = 0; + listChanged(SelItem, SelInd); +} + +void GuiScrollbar::OnDownButtonHold(GuiButton *sender, int pointer, const POINT &p) +{ + if(ScrollState < ScrollSpeed) + return; + + ScrollOneDown(); + + ScrollState = 0; + listChanged(SelItem, SelInd); +} + +void GuiScrollbar::OnBoxButtonHold(GuiButton *sender, int pointer, const POINT &p) +{ + if(ScrollState < ScrollSpeed) + return; + + if(!userInput[pointer].wpad.ir.valid) + return; + + int y = p.y-this->GetTop()-scrollbarBox->GetHeight()/2; + + int positionWiimote = LIMIT(y-MinHeight, 0, MaxHeight-MinHeight); + + int newSelected = (int) ((float) positionWiimote / (float) (MaxHeight-MinHeight) * (float) (EntrieCount-1)); + + if(Mode == ICONMODE) + { + int rows = (int) floor(((float) (newSelected-SelInd-SelItem)) / ((float) RowSize)); + + while(SelInd+rows*RowSize >= EntrieCount-PageSize+RowSize) + rows--; + + int pageIndex = LIMIT(SelInd+rows*RowSize, 0, EntrieCount-1-RowSize); + + if(newSelected <= 0) + SelItem = 0; + else if(newSelected >= EntrieCount-1) + SelItem = EntrieCount-1-pageIndex; + + SelInd = pageIndex; + } + else if(Mode == LISTMODE) + { + int diff = newSelected-SelInd-SelItem; + + if(newSelected <= 0) + { + SelItem = 0; + SelInd = 0; + } + else if(newSelected >= EntrieCount-1) + { + SelItem = (PageSize-1 < EntrieCount-1) ? PageSize-1 : EntrieCount-1; + SelInd = EntrieCount-PageSize; + } + else if(newSelected < PageSize && SelInd == 0 && diff < 0) + { + SelItem = MAX(SelItem+diff, 0); + } + else if(EntrieCount-newSelected < PageSize && SelInd == EntrieCount-PageSize && diff > 0) + { + SelItem = MIN(SelItem+diff, PageSize-1); + } + else + { + SelInd = LIMIT(SelInd+diff, 0, ((EntrieCount-PageSize < 0) ? 0 : EntrieCount-PageSize)); + } + } + + ScrollState = 0; + listChanged(SelItem, SelInd); +} + +void GuiScrollbar::SetPageSize(int size) +{ + if(PageSize == size) + return; + + PageSize = size; + listChanged(SelItem, SelInd); +} + +void GuiScrollbar::SetRowSize(int size) +{ + if(RowSize == size) + return; + + RowSize = size; + listChanged(SelItem, SelInd); +} + +void GuiScrollbar::SetSelectedItem(int pos) +{ + if(SelItem == pos) + return; + + SelItem = pos; +} + +void GuiScrollbar::SetSelectedIndex(int pos) +{ + if(SelInd == pos) + return; + + SelInd = pos; + listChanged(SelItem, SelInd); +} + +void GuiScrollbar::SetEntrieCount(int cnt) +{ + if(EntrieCount == cnt) + return; + + EntrieCount = cnt; + listChanged(SelItem, SelInd); +} + +void GuiScrollbar::setScrollboxPosition(int SelItem, int SelInd) +{ + if(Mode == ICONMODE) + { + u8 row = (u8) floor((float) SelItem / (float) RowSize); + + int position = MinHeight+(MaxHeight-MinHeight)*(SelInd+row*RowSize)/(EntrieCount-1); + + if(position < MinHeight) + position = MinHeight; + else if(position > MaxHeight || ((SelInd+PageSize >= (EntrieCount-1)) && row > 1)) + position = MaxHeight; + + scrollbarBoxBtn->SetPosition(ButtonPositionX, position); + } + else if(Mode == LISTMODE) + { + int position = MinHeight+(MaxHeight-MinHeight)*(SelInd+SelItem)/(EntrieCount-1); + + if(position < MinHeight) + position = MinHeight; + else if(position > MaxHeight || (SelInd+SelItem >= EntrieCount-1)) + position = MaxHeight; + + scrollbarBoxBtn->SetPosition(ButtonPositionX, position); + } +} + +void GuiScrollbar::CheckDPadControls(GuiTrigger *t) +{ + if(t->Up()) + { + ScrollOneUp(); + listChanged(SelItem, SelInd); + MovePointer = true; + } + else if(t->Down()) + { + ScrollOneDown(); + listChanged(SelItem, SelInd); + MovePointer = true; + } + else if(t->Left() && Mode == LISTMODE) + { + SelInd -= PageSize; + if(SelInd < 0) + { + SelInd = 0; + SelItem = 0; + } + listChanged(SelItem, SelInd); + MovePointer = true; + } + else if(t->Right() && Mode == LISTMODE) + { + SelInd += PageSize; + if(SelInd+PageSize >= EntrieCount) + { + SelInd = MAX(EntrieCount-PageSize, 0); + SelItem = LIMIT(PageSize-1, 0, EntrieCount-1); + } + listChanged(SelItem, SelInd); + MovePointer = true; + } + + if(MovePointer) + { + int selHeight = (arrowDownBtn->GetTop()+arrowDownBtn->GetHeight()-arrowUpBtn->GetTop())/PageSize; + int position = arrowUpBtn->GetTop()+(selHeight*SelItem)+(selHeight/2); + for (int i = 3; i >= 0; i--) + pointer[i]->SetPosition(scrollbarBoxBtn->GetLeft()-22, position, 0); + MovePointer = false; + } +} + +void GuiScrollbar::ScrollByButton(GuiTrigger *t) +{ + static int pressedPosition = -1; + + if(!t->wpad.ir.valid || ScrollState < ButtonScrollSpeed-ButtonScrollSpeed*fabs(pressedPosition-t->wpad.ir.y)/250.f) + return; + + if(pressedChan == -1 && (t->wpad.btns_d & ButtonScroll) && + parentElement && parentElement->IsInside(t->wpad.ir.x, t->wpad.ir.y)) + { + pressedPosition = t->wpad.ir.y; + pressedChan = t->chan; + oneButtonScrollImg->SetPosition(t->wpad.ir.x-oneButtonScrollImg->GetWidth()/2, t->wpad.ir.y-oneButtonScrollImg->GetHeight()/2); + } + + if(pressedChan == t->chan && (t->wpad.btns_h & ButtonScroll) ) + { + if(pressedPosition-oneButtonScrollImg->GetHeight()/2 > t->wpad.ir.y) + ScrollOneUp(); + else if(pressedPosition+oneButtonScrollImg->GetHeight()/2 < t->wpad.ir.y) + ScrollOneDown(); + + ScrollState = 0; + listChanged(SelItem, SelInd); + } + + if(pressedChan == t->chan && !t->wpad.btns_d && !t->wpad.btns_h) + { + pressedChan = -1; + pressedPosition = -1; + } +} + +void GuiScrollbar::Draw() +{ + if(PageSize <= EntrieCount) + { + scrollbarTileImg->Draw(); + scrollbarTopImg->Draw(); + scrollbarBottomImg->Draw(); + arrowUpBtn->Draw(); + arrowDownBtn->Draw(); + scrollbarBoxBtn->Draw(); + } + + if(pressedChan >= 0 && userInput[pressedChan].wpad.ir.valid) + oneButtonScrollImg->Draw(); + + UpdateEffects(); +} + +void GuiScrollbar::Update(GuiTrigger * t) +{ + if(PageSize <= EntrieCount) + { + arrowUpBtn->Update(t); + arrowDownBtn->Update(t); + scrollbarBoxBtn->Update(t); + } + + if(AllowDPad) + CheckDPadControls(t); + if(ButtonScroll) + ScrollByButton(t); + + ++ScrollState; +} diff --git a/source/GUI/gui_scrollbar.hpp b/source/GUI/gui_scrollbar.hpp new file mode 100644 index 0000000..620b756 --- /dev/null +++ b/source/GUI/gui_scrollbar.hpp @@ -0,0 +1,110 @@ +/*************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GUISCROLLBAR_HPP_ +#define GUISCROLLBAR_HPP_ + +#include "gui.h" + +class GuiScrollbar : public GuiElement, public sigslot::has_slots<> +{ + public: + GuiScrollbar(int height, u8 mode = LISTMODE); + virtual ~GuiScrollbar(); + void SetDPadControl(bool a) { AllowDPad = a; } + void SetButtonScroll(u32 button) { ButtonScroll = button; } + void ScrollOneUp(); + void ScrollOneDown(); + int GetSelectedItem() { return SelItem; }; + int GetSelectedIndex() { return SelInd; }; + void SetScrollSpeed(u16 speed) { ScrollSpeed = speed; }; + void SetButtonScrollSpeed(u16 speed) { ButtonScrollSpeed = speed; }; + void Draw(); + void Update(GuiTrigger * t); + enum + { + ICONMODE = 0, + LISTMODE, + }; + //! Signals + sigslot::signal2 listChanged; + //! Slots + void SetPageSize(int size); + void SetRowSize(int size); + void SetSelectedItem(int pos); + void SetSelectedIndex(int pos); + void SetEntrieCount(int cnt); + protected: + void setScrollboxPosition(int SelItem, int SelInd); + void OnUpButtonHold(GuiButton *sender, int pointer, const POINT &p); + void OnDownButtonHold(GuiButton *sender, int pointer, const POINT &p); + void OnBoxButtonHold(GuiButton *sender, int pointer, const POINT &p); + void CheckDPadControls(GuiTrigger *t); + void ScrollByButton(GuiTrigger *t); + + u8 Mode; + u32 ScrollState; + u16 ScrollSpeed; + u16 ButtonScrollSpeed; + u32 ButtonScroll; + bool AllowDPad; + bool MovePointer; + + int MinHeight; + int MaxHeight; + int SelItem; + int SelInd; + int RowSize; + int PageSize; + int EntrieCount; + int ButtonPositionX; + int pressedChan; + bool listchanged; + + GuiButton * arrowUpBtn; + GuiButton * arrowDownBtn; + GuiButton * scrollbarBoxBtn; + GuiImage * scrollbarTopImg; + GuiImage * scrollbarBottomImg; + GuiImage * scrollbarTileImg; + GuiImage * arrowDownImg; + GuiImage * arrowDownOverImg; + GuiImage * arrowUpImg; + GuiImage * arrowUpOverImg; + GuiImage * scrollbarBoxImg; + GuiImage * scrollbarBoxOverImg; + GuiImage * oneButtonScrollImg; + GuiImageData * scrollbarTop; + GuiImageData * scrollbarBottom; + GuiImageData * scrollbarTile; + GuiImageData * arrowDown; + GuiImageData * arrowDownOver; + GuiImageData * arrowUp; + GuiImageData * arrowUpOver; + GuiImageData * scrollbarBox; + GuiImageData * scrollbarBoxOver; + GuiImageData * oneButtonScrollImgData; + GuiTrigger * trigHeldA; +}; + +#endif diff --git a/source/GUI/gui_searchbar.cpp b/source/GUI/gui_searchbar.cpp new file mode 100644 index 0000000..ca48b0f --- /dev/null +++ b/source/GUI/gui_searchbar.cpp @@ -0,0 +1,267 @@ +#include +#include "gui.h" +#include "gui_searchbar.h" + +#include "../wpad.h" +#include "../main.h" +#include "../settings/CSettings.h" +#include "../settings/GameTitles.h" +#include "../themes/CTheme.h" +#include "../usbloader/GameList.h" + +extern GuiWindow * mainWindow; + +class cSearchButton +{ + public: + cSearchButton(wchar_t *Char, GuiImageData *keyImageData, GuiImageData *keyOverImageData, int x, int y, + GuiTrigger* trig, GuiSound* sndOver, GuiSound* sndClick) : + wchar(*Char), image(keyImageData), imageOver(keyOverImageData), text((char *) NULL, 20, ( GXColor ) + { 0, 0, 0, 0xff}), button(&image, &imageOver, ALIGN_LEFT, ALIGN_TOP, x, y, trig, sndOver, sndClick, 1) + { + text.SetText(Char); + button.SetLabel(&text); + } + wchar_t wchar; + GuiImage image; + GuiImage imageOver; + GuiText text; + GuiButton button; + private: + +}; + +static wchar_t lastSearchChar = 0; +std::set GuiSearchBar::SearchChars; + +GuiSearchBar::GuiSearchBar() : + inSide(0), text((char *) NULL, 22, ( GXColor ) {0, 0, 0, 255}), buttons(0), + keyImageData(Resources::GetFile("keyboard_key.png"), Resources::GetFileSize("keyboard_key.png")), + keyOverImageData(Resources::GetFile("keyboard_key_over.png"), Resources::GetFileSize("keyboard_key_over.png")) +{ + trig.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + + cnt = SearchChars.size(); + buttons = new cSearchButton*[cnt]; + + wchar_t charstr[2] = { 0, 0 }; + int lines = (cnt + 9) / 10; + int buttonsPerLine = (cnt + lines - 1) / lines; + width = 10 + buttonsPerLine * 42 + 10; + int i = 0, x_start = 10, x = 0, y_start = 10 + 42, y = 0; + if (width < 320) + { + x_start += (320 - width) >> 1; + width = 320; + } + for (std::set::iterator it=SearchChars.begin() ; it != SearchChars.end(); it++, i++, x++) + { + if (x >= buttonsPerLine) x = 0; + if (x == 0) y++; + charstr[0] = *it; + buttons[i] = new cSearchButton(charstr, &keyImageData, &keyOverImageData, x_start + x * 42, y_start - 42 + y + * 42, &trig, btnSoundOver, btnSoundClick); + this->Append(&(buttons[i]->button)); + } + height = 10 + 42 + y * 42 + 10; + + charstr[0] = Settings.SearchMode == SEARCH_BEGINNING ? L'=' : L'*'; + searchModeBtn = new cSearchButton(charstr, &keyImageData, &keyOverImageData, 10, 10, &trig, btnSoundOver, btnSoundClick); + this->Append(&searchModeBtn->button); + + text.SetText(gameList.GetCurrentFilter()); + text.SetPosition(55, 15); + text.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + text.SetWidescreen(Settings.widescreen); + text.SetMaxWidth(width - (55 + 2 * 42 + 10), SCROLL_HORIZONTAL); + this->Append(&text); + + imgBacspaceBtn = Resources::GetImageData("keyboard_backspace_over.png"); + BacspaceBtnImg_Over = new GuiImage(imgBacspaceBtn); + BacspaceBtnImg = new GuiImage(BacspaceBtnImg_Over); + BacspaceBtnImg->SetGrayscale(); + BacspaceBtn = new GuiButton(BacspaceBtnImg, BacspaceBtnImg_Over, ALIGN_RIGHT, ALIGN_TOP, -52, 10, &trig, btnSoundOver, btnSoundClick, 1); + this->Append(BacspaceBtn); + + imgClearBtn = Resources::GetImageData("keyboard_clear_over.png"); + ClearBtnImg_Over = new GuiImage(imgClearBtn); + ClearBtnImg = new GuiImage(ClearBtnImg_Over); + ClearBtnImg->SetGrayscale(); + ClearBtn = new GuiButton(ClearBtnImg, ClearBtnImg_Over, ALIGN_RIGHT, ALIGN_TOP, -10, 10, &trig, btnSoundOver, btnSoundClick, 1); + this->Append(ClearBtn); + + CloseBtn = new GuiButton(0, 0); + CloseBtn->SetTrigger(&trigB); + this->Append(CloseBtn); + + // SetPosition(100,100); + +} +GuiSearchBar::~GuiSearchBar() +{ + if (buttons) + { + for (int i = 0; i < cnt; i++) + delete buttons[i]; + delete[] buttons; + } + delete ClearBtn; + delete ClearBtnImg; + delete ClearBtnImg_Over; + delete imgClearBtn; + + delete CloseBtn; + delete searchModeBtn; + + delete BacspaceBtn; + delete BacspaceBtnImg; + delete BacspaceBtnImg_Over; + delete imgBacspaceBtn; + if (inSide) mainWindow->SetState(STATE_DEFAULT); +} +void GuiSearchBar::Draw() +{ + Menu_DrawRectangle(this->GetLeft(), this->GetTop(), width, height, ( GXColor ) {0, 0, 0, 0xa0}, 1); + Menu_DrawRectangle(this->GetLeft() + 55, this->GetTop() + 15, width - (55 + 2 * 42 + 10), 22, ( GXColor ) {255, 255, 255, 255}, 1); + GuiWindow::Draw(); +} +void GuiSearchBar::Update(GuiTrigger * t) +{ + LOCK( this ); + if (_elements.size() == 0 || (state == STATE_DISABLED && parentElement)) return; + // cursor + if (t->wpad.ir.valid && state != STATE_DISABLED) + { + if (this->IsInside(t->wpad.ir.x, t->wpad.ir.y)) + { + if (inSide == 0) + { + mainWindow->SetState(STATE_DISABLED); + this->SetState(STATE_DEFAULT); + } + inSide |= 1 << t->chan; + } + else if (inSide) + { + inSide &= ~(1 << t->chan); + if (inSide == 0) mainWindow->SetState(STATE_DEFAULT); + } + } + GuiWindow::Update(t); +} +wchar_t GuiSearchBar::GetClicked() +{ + lastSearchChar = 0; + + if (buttons) + { + for (int i = 0; i < cnt; i++) + { + if (buttons[i]->button.GetState() == STATE_CLICKED) + { + buttons[i]->button.ResetState(); + lastSearchChar = buttons[i]->wchar; + } + } + } + + if (BacspaceBtn->GetState() == STATE_CLICKED) lastSearchChar = 8; + else if (ClearBtn->GetState() == STATE_CLICKED) lastSearchChar = 7; + else if (CloseBtn->GetState() == STATE_CLICKED) lastSearchChar = 27; + else if (searchModeBtn->button.GetState() == STATE_CLICKED) lastSearchChar = 6; + + return lastSearchChar; +} + +void GuiSearchBar::FilterList(std::vector &List, wString &GameFilter) +{ + bool endOfGameName = false; // endOfGameName is disabled by default + + SearchChars.clear(); + + for (u32 i = 0; i < List.size(); ++i) + { + struct discHdr *header = List.at(i); + + wchar_t *gameName = charToWideChar(GameTitles.GetTitle(header)); + if (!gameName) + { + List.erase(List.begin()+i); + i--; + continue; + } + + if(Settings.SearchMode == SEARCH_BEGINNING) + { + if (GameFilter.size() > 0 && wcsncasecmp(gameName, GameFilter.c_str(), GameFilter.size()) != 0) + { + delete [] gameName; + List.erase(List.begin()+i); + i--; + continue; + } + + if ( wcslen(gameName) > GameFilter.size() + && SearchChars.find(towupper(gameName[GameFilter.size()])) == SearchChars.end() + && SearchChars.find(towlower(gameName[GameFilter.size()])) == SearchChars.end()) + { + SearchChars.insert(gameName[GameFilter.size()]); + } + else if (wcslen(gameName) == GameFilter.size()) // The end of the game name was reached + endOfGameName = true; + } + else if(Settings.SearchMode == SEARCH_CONTENT) + { + if(GameFilter.size() > 0) + { + if (wcscasestr(gameName, GameFilter.c_str()) == 0) + { + delete [] gameName; + List.erase(List.begin()+i); + i--; + continue; + } + + const wchar_t *found = gameName; + while((found = wcscasestr(found, GameFilter.c_str())) != 0) + { + found += GameFilter.size(); + wchar_t ch = towupper(*found); + if(ch) + SearchChars.insert(ch); + else // The end of the game name was reached + endOfGameName = true; + } + } + else + { + for(const wchar_t *wPtr = gameName; *wPtr != 0; wPtr++) + { + wchar_t ch = towupper(*wPtr); + if(ch > L'@') + SearchChars.insert(ch); + } + } + } + + delete [] gameName; + } + + if(List.size() < 2) + SearchChars.clear(); + + // If the last character was not backslash try autocomplete + if(SearchChars.size() == 1 && GameFilter.size() > 0 && lastSearchChar != 8 && !endOfGameName) + { + GameFilter += *SearchChars.begin(); + FilterList(List, GameFilter); + } +} + +/* + private: + SearchButtons *buttons; + }*/ + diff --git a/source/GUI/gui_searchbar.h b/source/GUI/gui_searchbar.h new file mode 100644 index 0000000..296e820 --- /dev/null +++ b/source/GUI/gui_searchbar.h @@ -0,0 +1,51 @@ +#ifndef GUI_SEARCHBAR_H_ +#define GUI_SEARCHBAR_H_ + +#include +#include +#include "gui.h" +#include "usbloader/disc.h" +#include "wstring.hpp" + +class cSearchButton; + +class GuiSearchBar: public GuiWindow +{ + public: + GuiSearchBar(); + virtual ~GuiSearchBar(); + void Draw(); + void Update(GuiTrigger * t); + wchar_t GetClicked(); + + static void FilterList(std::vector &List, wString &GameFilter); + private: + static std::set SearchChars; + + u16 inSide; + + GuiText text; + + GuiImageData* imgBacspaceBtn; + GuiImage* BacspaceBtnImg; + GuiImage* BacspaceBtnImg_Over; + GuiButton* BacspaceBtn; + + GuiImageData* imgClearBtn; + GuiImage* ClearBtnImg; + GuiImage* ClearBtnImg_Over; + GuiButton* ClearBtn; + + GuiButton* CloseBtn; + + cSearchButton *searchModeBtn; + cSearchButton **buttons; + int cnt; + GuiImageData keyImageData; + GuiImageData keyOverImageData; + GuiTrigger trig; + GuiTrigger trigB; + +}; + +#endif diff --git a/source/GUI/gui_text.cpp b/source/GUI/gui_text.cpp new file mode 100644 index 0000000..bd5e406 --- /dev/null +++ b/source/GUI/gui_text.cpp @@ -0,0 +1,587 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_text.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" +#include "wstring.hpp" +#include "settings/CSettings.h" +#include "utils/tools.h" + +#define MAX_LINES_TO_DRAW 9 + +static int presetSize = 18; +static int presetMaxWidth = 0; +static int presetAlignmentHor = 0; +static int presetAlignmentVert = 0; +static u16 presetStyle = 0; +static GXColor presetColor = (GXColor) {255, 255, 255, 255}; + +#define TEXT_SCROLL_DELAY 5 +#define TEXT_SCROLL_INITIAL_DELAY 8 + +/** + * Constructor for the GuiText class. + */ + +GuiText::GuiText(const char * t, int s, GXColor c) +{ + text = NULL; + size = (int) (s * Settings.FontScaleFactor); + currentSize = size; + color = c; + alpha = c.a; + style = FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE; + maxWidth = 0; + wrapMode = 0; + passChar = 0; + font = NULL; + linestodraw = MAX_LINES_TO_DRAW; + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; + + alignmentHor = ALIGN_CENTER; + alignmentVert = ALIGN_MIDDLE; + + if (t) + { + text = charToWideChar(t); + if (!text) return; + + textWidth = fontSystem->getWidth(text, currentSize); + } +} + +GuiText::GuiText(const wchar_t * t, int s, GXColor c) +{ + text = NULL; + size = (int) (s * Settings.FontScaleFactor); + currentSize = size; + color = c; + alpha = c.a; + style = FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE; + maxWidth = 0; + wrapMode = 0; + passChar = 0; + font = NULL; + linestodraw = MAX_LINES_TO_DRAW; + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; + + alignmentHor = ALIGN_CENTER; + alignmentVert = ALIGN_MIDDLE; + + if (t) + { + text = new (std::nothrow) wchar_t[wcslen(t) + 1]; + if (!text) return; + + wcscpy(text, t); + + textWidth = fontSystem->getWidth(text, currentSize); + } +} + +/** + * Constructor for the GuiText class, uses presets + */ +GuiText::GuiText(const char * t) +{ + text = NULL; + size = (int) (presetSize * Settings.FontScaleFactor); + currentSize = size; + color = presetColor; + alpha = presetColor.a; + style = presetStyle; + maxWidth = presetMaxWidth; + wrapMode = 0; + passChar = 0; + font = NULL; + linestodraw = MAX_LINES_TO_DRAW; + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; + + alignmentHor = presetAlignmentHor; + alignmentVert = presetAlignmentVert; + + if (t) + { + text = charToWideChar(t); + if (!text) return; + + textWidth = fontSystem->getWidth(text, currentSize); + } +} + +/** + * Destructor for the GuiText class. + */ +GuiText::~GuiText() +{ + if (text) delete[] text; + text = NULL; + + if (font) + { + delete font; + font = NULL; + } + + ClearDynamicText(); +} + +void GuiText::SetText(const char * t) +{ + LOCK( this ); + + if (text) delete[] text; + text = NULL; + + ClearDynamicText(); + + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + + if (t) + { + text = charToWideChar(t); + if (!text) return; + + if (passChar != 0) + { + for (u8 i = 0; i < wcslen(text); i++) + text[i] = passChar; + } + + textWidth = fontSystem->getWidth(text, currentSize); + } +} + +void GuiText::SetTextf(const char *format, ...) +{ + if (!format) SetText((char *) NULL); + + char *tmp = 0; + va_list va; + va_start( va, format ); + if ((vasprintf(&tmp, format, va) >= 0) && tmp) + { + SetText(tmp); + } + va_end( va ); + + if (tmp) free(tmp); +} + +void GuiText::SetText(const wchar_t * t) +{ + LOCK( this ); + + if (text) + delete [] text; + text = NULL; + + ClearDynamicText(); + + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + + if (t) + { + text = new (std::nothrow) wchar_t[wcslen(t) + 1]; + if (!text) return; + + wcscpy(text, t); + + if (passChar != 0) + { + for (u8 i = 0; i < wcslen(text); i++) + text[i] = passChar; + } + + textWidth = fontSystem->getWidth(text, currentSize); + } +} + +void GuiText::ClearDynamicText() +{ + for (u32 i = 0; i < textDyn.size(); i++) + { + if (textDyn[i]) + delete [] textDyn[i]; + } + textDyn.clear(); +} + +void GuiText::SetPresets(int sz, GXColor c, int w, u16 s, int h, int v) +{ + presetSize = sz; + presetColor = c; + presetStyle = s; + presetMaxWidth = w; + presetAlignmentHor = h; + presetAlignmentVert = v; +} + +void GuiText::SetFontSize(int s) +{ + LOCK( this ); + + size = s; +} + +void GuiText::SetMaxWidth(int width, int w) +{ + //! no need to reset timer on false set + if(wrapMode == w && maxWidth == width) + return; + + LOCK( this ); + + maxWidth = width; + wrapMode = w; + + if (w == SCROLL_HORIZONTAL) + { + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + textScrollDelay = TEXT_SCROLL_DELAY; + } + + ClearDynamicText(); +} + +void GuiText::SetPassChar(wchar_t p) +{ + LOCK( this ); + passChar = p; +} + +void GuiText::SetColor(GXColor c) +{ + LOCK( this ); + color = c; + alpha = c.a; +} + +void GuiText::SetStyle(u16 s) +{ + LOCK( this ); + style = s; +} + +void GuiText::SetAlignment(int hor, int vert) +{ + LOCK( this ); + style = 0; + + switch (hor) + { + case ALIGN_LEFT: + style |= FTGX_JUSTIFY_LEFT; + break; + case ALIGN_RIGHT: + style |= FTGX_JUSTIFY_RIGHT; + break; + default: + style |= FTGX_JUSTIFY_CENTER; + break; + } + switch (vert) + { + case ALIGN_TOP: + style |= FTGX_ALIGN_TOP; + break; + case ALIGN_BOTTOM: + style |= FTGX_ALIGN_BOTTOM; + break; + default: + style |= FTGX_ALIGN_MIDDLE; + break; + } + + alignmentHor = hor; + alignmentVert = vert; +} + +void GuiText::SetLinesToDraw(int l) +{ + linestodraw = l; +} + +int GuiText::GetTextWidth() +{ + if (!text) return 0; + + return fontSystem->getWidth(text, currentSize); +} + +int GuiText::GetTextWidth(int ind) +{ + if (ind < 0 || ind >= (int) textDyn.size()) return this->GetTextWidth(); + + return fontSystem->getWidth(textDyn[ind], currentSize); +} + +int GuiText::GetTextMaxWidth() +{ + return maxWidth; +} + +const wchar_t * GuiText::GetDynText(int ind) +{ + if (ind < 0 || ind >= (int) textDyn.size()) return text; + + return textDyn[ind]; +} + +const wchar_t * GuiText::GetText() +{ + return text; +} + +/** + * Change font + */ +bool GuiText::SetFont(const u8 *fontbuffer, const u32 filesize) +{ + if (!fontbuffer || !filesize) return false; + LOCK( this ); + if (font) + { + delete font; + font = NULL; + } + font = new FreeTypeGX(fontbuffer, filesize); + textWidth = font->getWidth(text, currentSize); + + return true; +} + +void GuiText::MakeDottedText() +{ + int pos = textDyn.size(); + textDyn.resize(pos + 1); + + int i = 0, currentWidth = 0; + textDyn[pos] = new wchar_t[maxWidth]; + + while (text[i]) + { + currentWidth += (font ? font : fontSystem)->getCharWidth(text[i], currentSize, i > 0 ? text[i - 1] : 0); + if (currentWidth >= maxWidth && i > 2) + { + textDyn[pos][i - 2] = '.'; + textDyn[pos][i - 1] = '.'; + textDyn[pos][i] = '.'; + i++; + break; + } + + textDyn[pos][i] = text[i]; + + i++; + } + textDyn[pos][i] = 0; +} + +void GuiText::ScrollText() +{ + if (textDyn.size() == 0) + { + int pos = textDyn.size(); + int i = 0, currentWidth = 0; + textDyn.resize(pos + 1); + + textDyn[pos] = new wchar_t[maxWidth]; + + while (text[i] && currentWidth < maxWidth) + { + textDyn[pos][i] = text[i]; + + currentWidth += (font ? font : fontSystem)->getCharWidth(text[i], currentSize, i > 0 ? text[i - 1] : 0); + + ++i; + } + textDyn[pos][i] = 0; + + return; + } + + if (frameCount % textScrollDelay != 0) + { + return; + } + + if (textScrollInitialDelay) + { + --textScrollInitialDelay; + return; + } + + int stringlen = wcslen(text); + + ++textScrollPos; + if (textScrollPos > stringlen) + { + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + } + + int ch = textScrollPos; + int pos = textDyn.size() - 1; + + if (!textDyn[pos]) new wchar_t[maxWidth]; + + int i = 0, currentWidth = 0; + + while (currentWidth < maxWidth) + { + if (ch > stringlen - 1) + { + textDyn[pos][i++] = ' '; + currentWidth += (font ? font : fontSystem)->getCharWidth(L' ', currentSize, ch > 0 ? text[ch - 1] : 0); + textDyn[pos][i++] = ' '; + currentWidth += (font ? font : fontSystem)->getCharWidth(L' ', currentSize, L' '); + textDyn[pos][i++] = ' '; + currentWidth += (font ? font : fontSystem)->getCharWidth(L' ', currentSize, L' '); + ch = 0; + + if(currentWidth >= maxWidth) + break; + } + + textDyn[pos][i] = text[ch]; + currentWidth += (font ? font : fontSystem)->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch - 1] : 0); + ++ch; + ++i; + } + textDyn[pos][i] = 0; +} + +void GuiText::WrapText() +{ + if (textDyn.size() > 0) return; + + int i = 0; + int ch = 0; + int linenum = 0; + int lastSpace = -1; + int lastSpaceIndex = -1; + int currentWidth = 0; + + while (text[ch] && linenum < linestodraw) + { + if (linenum >= (int) textDyn.size()) + { + textDyn.resize(linenum + 1); + textDyn[linenum] = new wchar_t[maxWidth]; + } + + textDyn[linenum][i] = text[ch]; + textDyn[linenum][i + 1] = 0; + + currentWidth += (font ? font : fontSystem)->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch - 1] : 0x0000); + + if (currentWidth >= maxWidth) + { + if (lastSpace >= 0) + { + textDyn[linenum][lastSpaceIndex] = 0; // discard space, and everything after + ch = lastSpace; // go backwards to the last space + lastSpace = -1; // we have used this space + lastSpaceIndex = -1; + } + + if (linenum + 1 == linestodraw && text[ch + 1] != 0x0000) + { + textDyn[linenum][i - 2] = '.'; + textDyn[linenum][i - 1] = '.'; + textDyn[linenum][i] = '.'; + textDyn[linenum][i + 1] = 0; + } + + currentWidth = 0; + ++linenum; + i = -1; + } + if (text[ch] == ' ' && i >= 0) + { + lastSpace = ch; + lastSpaceIndex = i; + } + ++ch; + ++i; + } +} + +/** + * Draw the text on screen + */ +void GuiText::Draw() +{ + if (!text || (*text == 0)) return; + + if (!IsVisible()) return; + + GX_LoadProjectionMtx(FSProjection2D, GX_ORTHOGRAPHIC); + GX_LoadPosMtxImm(FSModelView2D, GX_PNMTX0); + + GXColor c = color; + c.a = GetAlpha(); + + int newSize = (int) (size * GetScale()); + + if (newSize != currentSize) + { + currentSize = LIMIT(newSize, 1, 100); + + if (text) textWidth = (font ? font : fontSystem)->getWidth(text, currentSize); + } + + if (maxWidth > 0 && maxWidth <= textWidth) + { + if (wrapMode == DOTTED) // text dotted + { + if (textDyn.size() == 0) + MakeDottedText(); + + if (textDyn.size() > 0) + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop(), 0, textDyn[textDyn.size() - 1], currentSize, c, style); + } + + else if (wrapMode == SCROLL_HORIZONTAL) + { + ScrollText(); + + if (textDyn.size() > 0) + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop(), 0, textDyn[textDyn.size() - 1], currentSize, c, style); + } + else if (wrapMode == WRAP) + { + int lineheight = currentSize + 6; + int voffset = 0; + if (alignmentVert == ALIGN_MIDDLE) voffset = -(lineheight * textDyn.size()) / 2 + lineheight / 2; + + if (textDyn.size() == 0) WrapText(); + + for (u32 i = 0; i < textDyn.size(); i++) + { + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop() + voffset + i * lineheight, 0, textDyn[i], currentSize, c, style); + } + } + } + else + { + (font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop(), 0, text, currentSize, c, style, textWidth); + } + this->UpdateEffects(); +} diff --git a/source/GUI/gui_tooltip.cpp b/source/GUI/gui_tooltip.cpp new file mode 100644 index 0000000..51c8eec --- /dev/null +++ b/source/GUI/gui_tooltip.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_tooltip.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" +#include "themes/CTheme.h" +/** + * Constructor for the GuiTooltip class. + */ +GuiTooltip::GuiTooltip(const char *t, int Alpha/*=255*/) +{ + tooltipLeft = Resources::GetImageData("tooltip_left.png"); + tooltipTile = Resources::GetImageData("tooltip_tile.png"); + tooltipRight = Resources::GetImageData("tooltip_right.png"); + leftImage = new GuiImage(tooltipLeft); + tileImage = new GuiImage(tooltipTile); + rightImage = new GuiImage(tooltipRight); + text = NULL; + height = leftImage->GetHeight(); + leftImage->SetParent(this); + tileImage->SetParent(this); + rightImage->SetParent(this); + leftImage->SetParentAngle(false); + tileImage->SetParentAngle(false); + rightImage->SetParentAngle(false); + SetText(t); + SetAlpha(Alpha); +} + +/* + * Destructor for the GuiTooltip class. + */ +GuiTooltip::~GuiTooltip() +{ + if (text) delete text; + + delete tooltipLeft; + delete tooltipTile; + delete tooltipRight; + delete leftImage; + delete tileImage; + delete rightImage; +} + +float GuiTooltip::GetScale() +{ + float s = scale * scaleDyn; + + return s; +} + +/* !Sets the text of the GuiTooltip element + * !\param t Text + */ +void GuiTooltip::SetText(const char * t) +{ + LOCK( this ); + if (text) + { + delete text; + text = NULL; + } + int tile_cnt = 0; + if (t && (text = new GuiText(t, 22, ( GXColor ) + { 0, 0, 0, 255}))) + { + text->SetParent(this); + tile_cnt = (text->GetTextWidth() - 12) / tileImage->GetWidth(); + if (tile_cnt < 0) tile_cnt = 0; + } + tileImage->SetPosition(leftImage->GetWidth(), 0); + tileImage->SetTileHorizontal(tile_cnt); + rightImage->SetPosition(leftImage->GetWidth() + tile_cnt * tileImage->GetWidth(), 0); + width = leftImage->GetWidth() + tile_cnt * tileImage->GetWidth() + rightImage->GetWidth(); +} + +void GuiTooltip::SetWidescreen(bool ) +{ +} +/* + * Draw the Tooltip on screen + */ +void GuiTooltip::Draw() +{ + LOCK( this ); + if (!this->IsVisible()) return; + + leftImage->Draw(); + tileImage->Draw(); + rightImage->Draw(); + if (text) text->Draw(); + + this->UpdateEffects(); +} diff --git a/source/GUI/gui_trigger.cpp b/source/GUI/gui_trigger.cpp new file mode 100644 index 0000000..f4d46ab --- /dev/null +++ b/source/GUI/gui_trigger.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_trigger.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" + +static int scrollDelay = 0; + +/** + * Constructor for the GuiTrigger class. + */ +GuiTrigger::GuiTrigger() +{ + chan = -1; + memset(&wpad, 0, sizeof(WPADData)); + memset(&pad, 0, sizeof(PADData)); +} + +/** + * Destructor for the GuiTrigger class. + */ +GuiTrigger::~GuiTrigger() +{ +} + +/** + * Sets a simple trigger. Requires: + * - Element is selected + * - Trigger button is pressed + */ +void GuiTrigger::SetSimpleTrigger(s32 ch, u32 wiibtns, u16 gcbtns) +{ + type = TRIGGER_SIMPLE; + chan = ch; + wpad.btns_d = wiibtns; + pad.btns_d = gcbtns; +} + +/** + * Sets a held trigger. Requires: + * - Element is selected + * - Trigger button is pressed and held + */ +void GuiTrigger::SetHeldTrigger(s32 ch, u32 wiibtns, u16 gcbtns) +{ + type = TRIGGER_HELD; + chan = ch; + wpad.btns_h = wiibtns; + pad.btns_h = gcbtns; +} + +/** + * Sets a button trigger. Requires: + * - Trigger button is pressed + */ +void GuiTrigger::SetButtonOnlyTrigger(s32 ch, u32 wiibtns, u16 gcbtns) +{ + type = TRIGGER_BUTTON_ONLY; + chan = ch; + wpad.btns_d = wiibtns; + pad.btns_d = gcbtns; +} + +/**************************************************************************** + * WPAD_Stick + * + * Get X/Y value from Wii Joystick (classic, nunchuk) input + ***************************************************************************/ + +s8 GuiTrigger::WPAD_Stick(u8 right, int axis) +{ + float mag = 0.0; + float ang = 0.0; + + switch ( wpad.exp.type ) + { + default: + case WPAD_EXP_NUNCHUK: + case WPAD_EXP_GUITARHERO3: + { + if ( right == 0 ) + { + mag = wpad.exp.nunchuk.js.mag; + ang = wpad.exp.nunchuk.js.ang; + } + break; + } + case WPAD_EXP_CLASSIC: + { + if ( right == 0 ) + { + mag = wpad.exp.classic.ljs.mag; + ang = wpad.exp.classic.ljs.ang; + } + else + { + mag = wpad.exp.classic.rjs.mag; + ang = wpad.exp.classic.rjs.ang; + } + break; + } + } + + /* calculate x/y value (angle need to be converted into radian) */ + if ( mag > 1.0 ) + mag = 1.0; + else if ( mag < -1.0 ) + mag = -1.0; + + float val; + + if ( axis == 0 ) // x-axis + val = (float) (mag * sin( (PI * ang) / 180.0f )); + else // y-axis + val = (float) (mag * cos( (PI * ang) / 180.0f )); + + return ( s8 )( val * 128.0f ); +} + +bool GuiTrigger::Left() +{ + u32 wiibtn = WPAD_BUTTON_LEFT; + if(wpad.exp.type == WPAD_EXP_CLASSIC) + wiibtn |= WPAD_CLASSIC_BUTTON_LEFT; + + if( ((wpad.btns_d | wpad.btns_h) & wiibtn) + || ((pad.btns_d | pad.btns_h) & PAD_BUTTON_LEFT)) + { + if( (wpad.btns_d & wiibtn) + || (pad.btns_d & PAD_BUTTON_LEFT)) + { + scrollDelay = SCROLL_INITIAL_DELAY; // reset scroll delay. + return true; + } + else if (--scrollDelay <= 0) + { + scrollDelay = SCROLL_LOOP_DELAY; + return true; + } + } + return false; +} + +bool GuiTrigger::Right() +{ + u32 wiibtn = WPAD_BUTTON_RIGHT; + if(wpad.exp.type == WPAD_EXP_CLASSIC) + wiibtn |= WPAD_CLASSIC_BUTTON_RIGHT; + + if( ((wpad.btns_d | wpad.btns_h) & wiibtn) + || ((pad.btns_d | pad.btns_h) & PAD_BUTTON_RIGHT)) + { + if( (wpad.btns_d & wiibtn) + || (pad.btns_d & PAD_BUTTON_RIGHT)) + { + scrollDelay = SCROLL_INITIAL_DELAY; // reset scroll delay. + return true; + } + else if (--scrollDelay <= 0) + { + scrollDelay = SCROLL_LOOP_DELAY; + return true; + } + } + return false; +} + +bool GuiTrigger::Up() +{ + u32 wiibtn = WPAD_BUTTON_UP; + if(wpad.exp.type == WPAD_EXP_CLASSIC) + wiibtn |= WPAD_CLASSIC_BUTTON_UP; + + if( ((wpad.btns_d | wpad.btns_h) & wiibtn) + || ((pad.btns_d | pad.btns_h) & PAD_BUTTON_UP)) + { + if( (wpad.btns_d & wiibtn) + || (pad.btns_d & PAD_BUTTON_UP)) + { + scrollDelay = SCROLL_INITIAL_DELAY; // reset scroll delay. + return true; + } + else if (--scrollDelay <= 0) + { + scrollDelay = SCROLL_LOOP_DELAY; + return true; + } + } + return false; +} + +bool GuiTrigger::Down() +{ + u32 wiibtn = WPAD_BUTTON_DOWN; + if(wpad.exp.type == WPAD_EXP_CLASSIC) + wiibtn |= WPAD_CLASSIC_BUTTON_DOWN; + + if( ((wpad.btns_d | wpad.btns_h) & wiibtn) + || ((pad.btns_d | pad.btns_h) & PAD_BUTTON_DOWN)) + { + if( (wpad.btns_d & wiibtn) + || (pad.btns_d & PAD_BUTTON_DOWN)) + { + scrollDelay = SCROLL_INITIAL_DELAY; // reset scroll delay. + return true; + } + else if (--scrollDelay <= 0) + { + scrollDelay = SCROLL_LOOP_DELAY; + return true; + } + } + return false; +} diff --git a/source/GUI/gui_window.cpp b/source/GUI/gui_window.cpp new file mode 100644 index 0000000..0aa753f --- /dev/null +++ b/source/GUI/gui_window.cpp @@ -0,0 +1,329 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_window.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include "gui.h" + +GuiWindow::GuiWindow() +{ + width = 0; + height = 0; + forceDim = false; + allowDim = true; +} + +GuiWindow::GuiWindow(int w, int h) +{ + width = w; + height = h; + forceDim = false; + allowDim = true; +} + +GuiWindow::~GuiWindow() +{ +} + +void GuiWindow::Append(GuiElement* e) +{ + LOCK( this ); + if (e == NULL) return; + + Remove(e); + _elements.push_back(e); + e->SetParent(this); +} + +void GuiWindow::Insert(GuiElement* e, u32 index) +{ + LOCK( this ); + if (e == NULL || index > (_elements.size() - 1)) return; + + Remove(e); + _elements.insert(_elements.begin() + index, e); + e->SetParent(this); +} + +void GuiWindow::Remove(GuiElement* e) +{ + LOCK( this ); + if (e == NULL) return; + + for (u8 i = 0; i < _elements.size(); i++) + { + if (e == _elements.at(i)) + { + _elements.erase(_elements.begin() + i); + break; + } + } +} + +void GuiWindow::RemoveAll() +{ + LOCK( this ); + _elements.clear(); +} + +GuiElement* GuiWindow::GetGuiElementAt(u32 index) const +{ + if (index >= _elements.size()) return NULL; + return _elements.at(index); +} + +u32 GuiWindow::GetSize() +{ + return _elements.size(); +} + +void GuiWindow::Draw() +{ + LOCK( this ); + if (_elements.size() == 0 || !this->IsVisible()) return; + + for (u8 i = 0; i < _elements.size(); i++) + { + try + { + _elements.at(i)->Draw(); + } + catch (const std::exception& e) + { + } + } + + this->UpdateEffects(); + + if ((parentElement && state == STATE_DISABLED && allowDim) || forceDim) + Menu_DrawRectangle(0, 0, screenwidth, screenheight, (GXColor) {0, 0, 0, 0x70}, 1); +} +void GuiWindow::DrawTooltip() +{ + LOCK( this ); + if (_elements.size() == 0 || !this->IsVisible()) return; + + for (u8 i = 0; i < _elements.size(); i++) + { + try + { + _elements.at(i)->DrawTooltip(); + } + catch (const std::exception& e) + { + } + } +} +void GuiWindow::ResetState() +{ + LOCK( this ); + if (state != STATE_DISABLED) state = STATE_DEFAULT; + + for (u8 i = 0; i < _elements.size(); i++) + { + try + { + _elements.at(i)->ResetState(); + } + catch (const std::exception& e) + { + } + } +} + +void GuiWindow::SetState(int s) +{ + LOCK( this ); + state = s; + + for (u8 i = 0; i < _elements.size(); i++) + { + try + { + _elements.at(i)->SetState(s); + } + catch (const std::exception& e) + { + } + } +} + +void GuiWindow::SetVisible(bool v) +{ + LOCK( this ); + visible = v; + + for (u8 i = 0; i < _elements.size(); i++) + { + try + { + _elements.at(i)->SetVisible(v); + } + catch (const std::exception& e) + { + } + } +} + +int GuiWindow::GetSelected() +{ + // find selected element + int found = -1; + for (u8 i = 0; i < _elements.size(); i++) + { + try + { + if (_elements.at(i)->GetState() == STATE_SELECTED) + { + found = i; + break; + } + } + catch (const std::exception& e) + { + } + } + return found; +} + +// set element to left/right as selected +// there's probably a more clever way to do this, but this way works +void GuiWindow::MoveSelectionHor(int dir) +{ + LOCK( this ); + int found = -1; + u16 left = 0; + u16 top = 0; + u8 i = 0; + + int selected = this->GetSelected(); + + if (selected >= 0) + { + left = _elements.at(selected)->GetLeft(); + top = _elements.at(selected)->GetTop(); + } + + // look for a button on the same row, to the left/right + for (i = 0; i < _elements.size(); i++) + { + try + { + if (_elements.at(i)->IsSelectable()) + { + if (_elements.at(i)->GetLeft() * dir > left * dir && _elements.at(i)->GetTop() == top) + { + if (found == -1) + found = i; + else if (_elements.at(i)->GetLeft() * dir < _elements.at(found)->GetLeft() * dir) found = i; // this is a better match + } + } + } + catch (const std::exception& e) + { + } + } + if (found >= 0) goto matchfound; + + // match still not found, let's try the first button in the next row + for (i = 0; i < _elements.size(); i++) + { + try + { + if (_elements.at(i)->IsSelectable()) + { + if (_elements.at(i)->GetTop() * dir > top * dir) + { + if (found == -1) + found = i; + else if (_elements.at(i)->GetTop() * dir < _elements.at(found)->GetTop() * dir) + found = i; // this is a better match + else if (_elements.at(i)->GetTop() * dir == _elements.at(found)->GetTop() * dir + && _elements.at(i)->GetLeft() * dir < _elements.at(found)->GetLeft() * dir) found = i; // this is a better match + } + } + } + catch (const std::exception& e) + { + } + } + + // match found + matchfound: if (found >= 0) + { + _elements.at(found)->SetState(STATE_SELECTED); + if (selected >= 0) _elements.at(selected)->ResetState(); + } +} + +void GuiWindow::MoveSelectionVert(int dir) +{ + LOCK( this ); + int found = -1; + u16 left = 0; + u16 top = 0; + u8 i = 0; + + int selected = this->GetSelected(); + + if (selected >= 0) + { + left = _elements.at(selected)->GetLeft(); + top = _elements.at(selected)->GetTop(); + } + + // look for a button above/below, with the least horizontal difference + for (i = 0; i < _elements.size(); i++) + { + try + { + if (_elements.at(i)->IsSelectable()) + { + if (_elements.at(i)->GetTop() * dir > top * dir) + { + if (found == -1) + found = i; + else if (_elements.at(i)->GetTop() * dir < _elements.at(found)->GetTop() * dir) + found = i; // this is a better match + else if (_elements.at(i)->GetTop() * dir == _elements.at(found)->GetTop() * dir && abs( + _elements.at(i)->GetLeft() - left) < abs(_elements.at(found)->GetLeft() - left)) found = i; + } + } + } + catch (const std::exception& e) + { + } + } + if (found >= 0) goto matchfound; + + // match found + matchfound: if (found >= 0) + { + _elements.at(found)->SetState(STATE_SELECTED); + if (selected >= 0) _elements.at(selected)->ResetState(); + } +} + +void GuiWindow::Update(GuiTrigger * t) +{ + LOCK( this ); + if (_elements.size() == 0 || (state == STATE_DISABLED && parentElement)) return; + + for (u8 i = 0; i < _elements.size(); i++) + { + try + { + _elements.at(i)->Update(t); + } + catch (const std::exception& e) + { + } + } + + if (updateCB) updateCB(this); +} diff --git a/source/GUI/sigslot.h b/source/GUI/sigslot.h new file mode 100644 index 0000000..990beb6 --- /dev/null +++ b/source/GUI/sigslot.h @@ -0,0 +1,2748 @@ +// sigslot.h: Signal/Slot classes +// +// Written by Sarah Thompson (sarah@telergy.com) 2002. +// +// License: Public domain. You are free to use this code however you like, with the proviso that +// the author takes on no responsibility or liability for any use. +// +// QUICK DOCUMENTATION +// +// (see also the full documentation at http://sigslot.sourceforge.net/) +// +// #define switches +// SIGSLOT_PURE_ISO - Define this to force ISO C++ compliance. This also disables +// all of the thread safety support on platforms where it is +// available. +// +// SIGSLOT_USE_POSIX_THREADS - Force use of Posix threads when using a C++ compiler other than +// gcc on a platform that supports Posix threads. (When using gcc, +// this is the default - use SIGSLOT_PURE_ISO to disable this if +// necessary) +// +// SIGSLOT_DEFAULT_MT_POLICY - Where thread support is enabled, this defaults to multi_threaded_global. +// Otherwise, the default is single_threaded. #define this yourself to +// override the default. In pure ISO mode, anything other than +// single_threaded will cause a compiler error. +// +// PLATFORM NOTES +// +// Win32 - On Win32, the WIN32 symbol must be #defined. Most mainstream +// compilers do this by default, but you may need to define it +// yourself if your build environment is less standard. This causes +// the Win32 thread support to be compiled in and used automatically. +// +// Unix/Linux/BSD, etc. - If you're using gcc, it is assumed that you have Posix threads +// available, so they are used automatically. You can override this +// (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using +// something other than gcc but still want to use Posix threads, you +// need to #define SIGSLOT_USE_POSIX_THREADS. +// +// ISO C++ - If none of the supported platforms are detected, or if +// SIGSLOT_PURE_ISO is defined, all multithreading support is turned off, +// along with any code that might cause a pure ISO C++ environment to +// complain. Before you ask, gcc -ansi -pedantic won't compile this +// library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of +// errors that aren't really there. If you feel like investigating this, +// please contact the author. +// +// +// THREADING MODES +// +// single_threaded - Your program is assumed to be single threaded from the point of view +// of signal/slot usage (i.e. all objects using signals and slots are +// created and destroyed from a single thread). Behaviour if objects are +// destroyed concurrently is undefined (i.e. you'll get the occasional +// segmentation fault/memory exception). +// +// multi_threaded_global - Your program is assumed to be multi threaded. Objects using signals and +// slots can be safely created and destroyed from any thread, even when +// connections exist. In multi_threaded_global mode, this is achieved by a +// single global mutex (actually a critical section on Windows because they +// are faster). This option uses less OS resources, but results in more +// opportunities for contention, possibly resulting in more context switches +// than are strictly necessary. +// +// multi_threaded_local - Behaviour in this mode is essentially the same as multi_threaded_global, +// except that each signal, and each object that inherits has_slots, all +// have their own mutex/critical section. In practice, this means that +// mutex collisions (and hence context switches) only happen if they are +// absolutely essential. However, on some platforms, creating a lot of +// mutexes can slow down the whole OS, so use this option with care. +// +// USING THE LIBRARY +// +// See the full documentation at http://sigslot.sourceforge.net/ +// +// + +#ifndef SIGSLOT_H__ +#define SIGSLOT_H__ + +#include +#include + +#if defined(SIGSLOT_PURE_ISO) || (!defined(WIN32) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS) && !defined(SIGSLOT_USE_LWP_THREADS)) +# define _SIGSLOT_SINGLE_THREADED +#elif defined(WIN32) +# define _SIGSLOT_HAS_WIN32_THREADS +# include +#elif (defined(__GNUG__) && defined(__GCCORE_H__)) || defined(SIGSLOT_USE_LWP_THREADS) +# define _SIGSLOT_SINGLE_THREADED +#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS) +# define _SIGSLOT_HAS_POSIX_THREADS +# include +#else +# define _SIGSLOT_SINGLE_THREADED +#endif + +#ifndef SIGSLOT_DEFAULT_MT_POLICY +# ifdef _SIGSLOT_SINGLE_THREADED +# define SIGSLOT_DEFAULT_MT_POLICY single_threaded +# else +# define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_global +# endif +#endif + + +namespace sigslot { + + class single_threaded + { + public: + single_threaded() + { + ; + } + + virtual ~single_threaded() + { + ; + } + + virtual void lock() + { + ; + } + + virtual void unlock() + { + ; + } + }; + +#ifdef _SIGSLOT_HAS_WIN32_THREADS + // The multi threading policies only get compiled in if they are enabled. + class multi_threaded_global + { + public: + multi_threaded_global() + { + static bool isinitialised = false; + + if(!isinitialised) + { + InitializeCriticalSection(get_critsec()); + isinitialised = true; + } + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + EnterCriticalSection(get_critsec()); + } + + virtual void unlock() + { + LeaveCriticalSection(get_critsec()); + } + + private: + CRITICAL_SECTION* get_critsec() + { + static CRITICAL_SECTION g_critsec; + return &g_critsec; + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + InitializeCriticalSection(&m_critsec); + } + + multi_threaded_local(const multi_threaded_local&) + { + InitializeCriticalSection(&m_critsec); + } + + virtual ~multi_threaded_local() + { + DeleteCriticalSection(&m_critsec); + } + + virtual void lock() + { + EnterCriticalSection(&m_critsec); + } + + virtual void unlock() + { + LeaveCriticalSection(&m_critsec); + } + + private: + CRITICAL_SECTION m_critsec; + }; +#endif // _SIGSLOT_HAS_WIN32_THREADS + +#ifdef _SIGSLOT_HAS_POSIX_THREADS + // The multi threading policies only get compiled in if they are enabled. + class multi_threaded_global + { + public: + multi_threaded_global() + { + pthread_mutex_init(get_mutex(), NULL); + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + pthread_mutex_lock(get_mutex()); + } + + virtual void unlock() + { + pthread_mutex_unlock(get_mutex()); + } + + private: + pthread_mutex_t* get_mutex() + { + static pthread_mutex_t g_mutex; + return &g_mutex; + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + pthread_mutex_init(&m_mutex, NULL); + } + + multi_threaded_local(const multi_threaded_local&) + { + pthread_mutex_init(&m_mutex, NULL); + } + + virtual ~multi_threaded_local() + { + pthread_mutex_destroy(&m_mutex); + } + + virtual void lock() + { + pthread_mutex_lock(&m_mutex); + } + + virtual void unlock() + { + pthread_mutex_unlock(&m_mutex); + } + + private: + pthread_mutex_t m_mutex; + }; +#endif // _SIGSLOT_HAS_POSIX_THREADS + +#ifdef _SIGSLOT_HAS_LWP_THREADS + // The multi threading policies only get compiled in if they are enabled. + //!making mutex static because libogc only supports up to 64 mutex - Dimok + static mutex_t g_mutex = LWP_MUTEX_NULL; + + class multi_threaded_global + { + public: + multi_threaded_global() + { + if(g_mutex == LWP_MUTEX_NULL) + LWP_MutexInit(&g_mutex, NULL); + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + LWP_MutexLock(g_mutex); + } + + virtual void unlock() + { + LWP_MutexUnlock(g_mutex); + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + ; + } + + multi_threaded_local(const multi_threaded_local&) + { + ; + } + + virtual ~multi_threaded_local() + { + } + + virtual void lock() + { + ; + } + + virtual void unlock() + { + ; + } + }; + +#endif // _SIGSLOT_HAS_LWP_THREADS + + template + class lock_block + { + public: + mt_policy *m_mutex; + + lock_block(mt_policy *mtx) + : m_mutex(mtx) + { + m_mutex->lock(); + } + + ~lock_block() + { + m_mutex->unlock(); + } + }; + + template + class has_slots; + + template + class _connection_base0 + { + public: + virtual ~_connection_base0() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit() = 0; + virtual _connection_base0* clone() = 0; + virtual _connection_base0* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base1 + { + public: + virtual ~_connection_base1() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type) = 0; + virtual _connection_base1* clone() = 0; + virtual _connection_base1* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base2 + { + public: + virtual ~_connection_base2() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type) = 0; + virtual _connection_base2* clone() = 0; + virtual _connection_base2* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base3 + { + public: + virtual ~_connection_base3() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type) = 0; + virtual _connection_base3* clone() = 0; + virtual _connection_base3* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base4 + { + public: + virtual ~_connection_base4() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0; + virtual _connection_base4* clone() = 0; + virtual _connection_base4* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base5 + { + public: + virtual ~_connection_base5() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type) = 0; + virtual _connection_base5* clone() = 0; + virtual _connection_base5* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base6 + { + public: + virtual ~_connection_base6() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type) = 0; + virtual _connection_base6* clone() = 0; + virtual _connection_base6* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base7 + { + public: + virtual ~_connection_base7() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type, arg7_type) = 0; + virtual _connection_base7* clone() = 0; + virtual _connection_base7* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base8 + { + public: + virtual ~_connection_base8() { ; } + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type, arg7_type, arg8_type) = 0; + virtual _connection_base8* clone() = 0; + virtual _connection_base8* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _signal_base : public mt_policy + { + public: + virtual void slot_disconnect(has_slots* pslot) = 0; + virtual void slot_duplicate(const has_slots* poldslot, has_slots* pnewslot) = 0; + }; + + template + class has_slots : public mt_policy + { + private: + typedef typename std::set<_signal_base *> sender_set; + typedef typename sender_set::const_iterator const_iterator; + + public: + has_slots() + { + ; + } + + has_slots(const has_slots& hs) + : mt_policy(hs) + { + lock_block lock(this); + const_iterator it = hs.m_senders.begin(); + const_iterator itEnd = hs.m_senders.end(); + + while(it != itEnd) + { + (*it)->slot_duplicate(&hs, this); + m_senders.insert(*it); + ++it; + } + } + + void signal_connect(_signal_base* sender) + { + lock_block lock(this); + m_senders.insert(sender); + } + + void signal_disconnect(_signal_base* sender) + { + lock_block lock(this); + m_senders.erase(sender); + } + + virtual ~has_slots() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_senders.begin(); + const_iterator itEnd = m_senders.end(); + + while(it != itEnd) + { + (*it)->slot_disconnect(this); + ++it; + } + + m_senders.erase(m_senders.begin(), m_senders.end()); + } + + private: + sender_set m_senders; + }; + + template + class _signal_base0 : public _signal_base + { + public: + typedef typename std::list<_connection_base0 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base0() + { + ; + } + + _signal_base0(const _signal_base0& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + ~_signal_base0() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base1 : public _signal_base + { + public: + typedef typename std::list<_connection_base1 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base1() + { + ; + } + + _signal_base1(const _signal_base1& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base1() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base2 : public _signal_base + { + public: + typedef typename std::list<_connection_base2 *> + connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base2() + { + ; + } + + _signal_base2(const _signal_base2& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base2() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base3 : public _signal_base + { + public: + typedef std::list<_connection_base3 *> + connections_list; + + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + _signal_base3() + { + ; + } + + _signal_base3(const _signal_base3& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base3() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base4 : public _signal_base + { + public: + typedef std::list<_connection_base4 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base4() + { + ; + } + + _signal_base4(const _signal_base4& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base4() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + this->m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base5 : public _signal_base + { + public: + typedef std::list<_connection_base5 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base5() + { + ; + } + + _signal_base5(const _signal_base5& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base5() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base6 : public _signal_base + { + public: + typedef std::list<_connection_base6 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base6() + { + ; + } + + _signal_base6(const _signal_base6& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base6() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base7 : public _signal_base + { + public: + typedef std::list<_connection_base7 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base7() + { + ; + } + + _signal_base7(const _signal_base7& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base7() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base8 : public _signal_base + { + public: + typedef std::list<_connection_base8 *> + connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base8() + { + ; + } + + _signal_base8(const _signal_base8& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base8() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + bool connected() + { + return m_connected_slots.size() != 0; + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + + template + class _connection0 : public _connection_base0 + { + public: + _connection0() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection0(dest_type* pobject, void (dest_type::*pmemfun)()) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection0() + { + ; + } + + virtual _connection_base0* clone() + { + return new _connection0(*this); + } + + virtual _connection_base0* duplicate(has_slots* pnewdest) + { + return new _connection0((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit() + { + (m_pobject->*m_pmemfun)(); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(); + }; + + template + class _connection1 : public _connection_base1 + { + public: + _connection1() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection1() + { + ; + } + + virtual _connection_base1* clone() + { + return new _connection1(*this); + } + + virtual _connection_base1* duplicate(has_slots* pnewdest) + { + return new _connection1((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1) + { + (m_pobject->*m_pmemfun)(a1); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type); + }; + + template + class _connection2 : public _connection_base2 + { + public: + _connection2() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection2() + { + ; + } + + + virtual _connection_base2* clone() + { + return new _connection2(*this); + } + + virtual _connection_base2* duplicate(has_slots* pnewdest) + { + return new _connection2((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2) + { + (m_pobject->*m_pmemfun)(a1, a2); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type); + }; + + template + class _connection3 : public _connection_base3 + { + public: + _connection3() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection3() + { + ; + } + + + virtual _connection_base3* clone() + { + return new _connection3(*this); + } + + virtual _connection_base3* duplicate(has_slots* pnewdest) + { + return new _connection3((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3) + { + (m_pobject->*m_pmemfun)(a1, a2, a3); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type); + }; + + template + class _connection4 : public _connection_base4 + { + public: + _connection4() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection4() + { + ; + } + + virtual _connection_base4* clone() + { + return new _connection4(*this); + } + + virtual _connection_base4* duplicate(has_slots* pnewdest) + { + return new _connection4((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, + arg4_type a4) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, + arg4_type); + }; + + template + class _connection5 : public _connection_base5 + { + public: + _connection5() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection5() + { + ; + } + + virtual _connection_base5* clone() + { + return new _connection5(*this); + } + + virtual _connection_base5* duplicate(has_slots* pnewdest) + { + return new _connection5((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type); + }; + + template + class _connection6 : public _connection_base6 + { + public: + _connection6() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection6() + { + ; + } + + virtual _connection_base6* clone() + { + return new _connection6(*this); + } + + virtual _connection_base6* duplicate(has_slots* pnewdest) + { + return new _connection6((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type); + }; + + template + class _connection7 : public _connection_base7 + { + public: + _connection7() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection7() + { + ; + } + + virtual _connection_base7* clone() + { + return new _connection7(*this); + } + + virtual _connection_base7* duplicate(has_slots* pnewdest) + { + return new _connection7((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type); + }; + + template + class _connection8 : public _connection_base8 + { + public: + _connection8() + { + this->pobject = NULL; + this->pmemfun = NULL; + } + + _connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type, arg8_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection8() + { + ; + } + + virtual _connection_base8* clone() + { + return new _connection8(*this); + } + + virtual _connection_base8* duplicate(has_slots* pnewdest) + { + return new _connection8((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type); + }; + + template + class signal0 : public _signal_base0 + { + public: + typedef typename _signal_base0::connections_list::const_iterator const_iterator; + signal0() + { + ; + } + + signal0(const signal0& s) + : _signal_base0(s) + { + ; + } + + virtual ~signal0() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)()) + { + lock_block lock(this); + _connection0* conn = + new _connection0(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit() + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(); + + it = itNext; + } + } + + void operator()() + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(); + + it = itNext; + } + } + }; + + template + class signal1 : public _signal_base1 + { + public: + typedef typename _signal_base1::connections_list::const_iterator const_iterator; + signal1() + { + ; + } + + signal1(const signal1& s) + : _signal_base1(s) + { + ; + } + + virtual ~signal1() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type)) + { + lock_block lock(this); + _connection1* conn = + new _connection1(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1); + + it = itNext; + } + } + + void operator()(arg1_type a1) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1); + + it = itNext; + } + } + }; + + template + class signal2 : public _signal_base2 + { + public: + typedef typename _signal_base2::connections_list::const_iterator const_iterator; + signal2() + { + ; + } + + signal2(const signal2& s) + : _signal_base2(s) + { + ; + } + + virtual ~signal2() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type)) + { + lock_block lock(this); + _connection2* conn = new + _connection2(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2); + + it = itNext; + } + } + }; + + template + class signal3 : public _signal_base3 + { + public: + typedef typename _signal_base3::connections_list::const_iterator const_iterator; + signal3() + { + ; + } + + signal3(const signal3& s) + : _signal_base3(s) + { + ; + } + + virtual ~signal3() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type)) + { + lock_block lock(this); + _connection3* conn = + new _connection3(pclass, + pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3); + + it = itNext; + } + } + }; + + template + class signal4 : public _signal_base4 + { + public: + typedef typename _signal_base4::connections_list::const_iterator const_iterator; + signal4() + { + ; + } + + signal4(const signal4& s) + : _signal_base4(s) + { + ; + } + + virtual ~signal4() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type)) + { + lock_block lock(this); + _connection4* + conn = new _connection4(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4); + + it = itNext; + } + } + }; + + template + class signal5 : public _signal_base5 + { + public: + typedef typename _signal_base5::connections_list::const_iterator const_iterator; + signal5() + { + ; + } + + signal5(const signal5& s) + : _signal_base5(s) + { + ; + } + + virtual ~signal5() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type)) + { + lock_block lock(this); + _connection5* conn = new _connection5(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5); + + it = itNext; + } + } + }; + + + template + class signal6 : public _signal_base6 + { + public: + typedef typename _signal_base6::connections_list::const_iterator const_iterator; + signal6() + { + ; + } + + signal6(const signal6& s) + : _signal_base6(s) + { + ; + } + + virtual ~signal6() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) + { + lock_block lock(this); + _connection6* conn = + new _connection6(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6); + + it = itNext; + } + } + }; + + template + class signal7 : public _signal_base7 + { + public: + typedef typename _signal_base7::connections_list::const_iterator const_iterator; + signal7() + { + ; + } + + signal7(const signal7& s) + : _signal_base7(s) + { + ; + } + + virtual ~signal7() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type)) + { + lock_block lock(this); + _connection7* conn = + new _connection7(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7); + + it = itNext; + } + } + }; + + template + class signal8 : public _signal_base8 + { + public: + typedef typename _signal_base8::connections_list::const_iterator const_iterator; + signal8() + { + ; + } + + signal8(const signal8& s) + : _signal_base8(s) + { + ; + } + + virtual ~signal8() + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type, arg8_type)) + { + lock_block lock(this); + _connection8* conn = + new _connection8(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + lock_block lock(this); + const_iterator itNext, it = this->m_connected_slots.begin(); + const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); + + it = itNext; + } + } + }; + +}; // namespace sigslot + +#endif // SIGSLOT_H__ diff --git a/source/GameCube/DEVO_Config.h b/source/GameCube/DEVO_Config.h new file mode 100644 index 0000000..87a1f48 --- /dev/null +++ b/source/GameCube/DEVO_Config.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 DEVO_CONFIG_H_ +#define DEVO_CONFIG_H_ + +#define LAUNCH_DEVO() ((void(*)(void))loader_bin)() + +#define DEVO_SIG 0x3EF9DB23 +#define DEVO_CONFIG_VERSION 0x0200 + +enum DEVOConfig +{ + DEVO_CFG_WIFILOG = (1<<0), // added in Devo r100, config version 0x0110 + DEVO_CFG_WIDE = (1<<1), // added in Devo r142 + DEVO_CFG_NOLED = (1<<2), + DEVO_CFG_FZERO_AX = (1<<3), // added in Devo r196, config version x0111 + DEVO_CFG_TIMER_FIX = (1<<4), + DEVO_CFG_D_BUTTONS = (1<<5), // added in Devo r200, config version 0x0112 + DEVO_CFG_CROP_OVERSCAN = (1<<6), // added in Devo r234, config version 0x0200 + DEVO_CFG_DISC_DELAY = (1<<7), + DEVO_CFG_PLAYLOG = (1<<8), +}; + +typedef struct _DEVO_CFG +{ + u32 signature; //0x3EF9DB23 + u16 version; //0x00000200 + u16 device_signature; + u32 memcard_cluster; + u32 disc1_cluster; + u32 disc2_cluster; + u32 options; // added in Devo config version 0x0110 +} DEVO_CFG; + +#endif diff --git a/source/GameCube/DML_Config.h b/source/GameCube/DML_Config.h new file mode 100644 index 0000000..c4093b6 --- /dev/null +++ b/source/GameCube/DML_Config.h @@ -0,0 +1,71 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 DML_CONFIG_H_ +#define DML_CONFIG_H_ + +#include + +#define DML_CONFIG_ADDRESS 0x80001700 +#define DML_CONFIG_ADDRESS_V1_2 0x81200000 +#define DML_MAGIC 0xD1050CF6 +#define DML_VERSION 0x00000002 + +enum DMLConfig +{ + DML_CFG_CHEATS = (1<<0), + DML_CFG_DEBUGGER = (1<<1), + DML_CFG_DEBUGWAIT = (1<<2), + DML_CFG_NMM = (1<<3), + DML_CFG_NMM_DEBUG = (1<<4), + DML_CFG_GAME_PATH = (1<<5), + DML_CFG_CHEAT_PATH = (1<<6), + DML_CFG_ACTIVITY_LED = (1<<7), + DML_CFG_PADHOOK = (1<<8), + DML_CFG_NODISC = (1<<9), // unused since DML v1.0, removed in v2.1 + DML_CFG_FORCE_WIDE = (1<<9), // DM v2.1+, Config v02 + DML_CFG_BOOT_DISC = (1<<10), + // DML_CFG_BOOT_DOL = (1<<11), // unused since DML v1.0, removed in v2.1 + DML_CFG_BOOT_DISC2 = (1<<11), // added in DM v2.1+, Config v02, used in v2.6+ + DML_CFG_NODISC2 = (1<<12), // added back in DM v2.2 update2 (r20) and removed in v2.3 + DML_CFG_SCREENSHOT = (1<<13), // added in v2.5 +}; + +enum DMLVideoModes +{ + DML_VID_DML_AUTO = (0<<16), + DML_VID_FORCE = (1<<16), + DML_VID_NONE = (2<<16), + + DML_VID_FORCE_PAL50 = (1<<0), + DML_VID_FORCE_PAL60 = (1<<1), + DML_VID_FORCE_NTSC = (1<<2), + DML_VID_FORCE_PROG = (1<<3), + DML_VID_PROG_PATCH = (1<<4) + +}; + +typedef struct _DML_CFG +{ + u32 Magicbytes; // 0xD1050CF6 + u32 Version; // 0x00000002 + u32 VideoMode; + u32 Config; + char GamePath[255]; + char CheatPath[255]; +} DML_CFG; + +#endif diff --git a/source/GameCube/GCDumper.cpp b/source/GameCube/GCDumper.cpp new file mode 100644 index 0000000..53bfa7b --- /dev/null +++ b/source/GameCube/GCDumper.cpp @@ -0,0 +1,403 @@ +/*************************************************************************** + * Copyright (C) 2012 + * by OverjoY and FIX94 for Wiiflow + * + * Adjustments for USB Loader GX by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include +#include + +#include "GCDumper.hpp" +#include "FileOperations/fileops.h" +#include "language/gettext.h" +#include "prompts/ProgressWindow.h" +#include "usbloader/disc.h" +#include "usbloader/wdvd.h" +#include "usbloader/wbfs/wbfs_fat.h" +#include "usbloader/wbfs/wbfs_rw.h" +#include "utils/ShowError.h" +#include "utils/tools.h" +#include "gecko.h" + +static const u32 BUF_SIZE = (64*1024); + +GCDumper::GCDumper() + : force_align32(false) + , compressed(false) + , ReadBuffer((u8 *) memalign(32, ALIGN32(BUF_SIZE))) +{ + +} +GCDumper::~GCDumper() +{ + if(ReadBuffer) + free(ReadBuffer); +} + +s32 GCDumper::CopyDiscData(FILE *f, u64 offset, u32 length, u8 *buffer) +{ + u32 toread = 0; + u32 wrote = 0; + + while(length) + { + if(ProgressCanceled()) + return PROGRESS_CANCELED; + + ShowProgress(discWrote, discTotal); + + toread = std::min(length, BUF_SIZE); + s32 ret = __ReadDVDPlain(buffer, toread, offset); + if (ret < 0) + return ret; + + fwrite(buffer, 1, toread, f); + wrote += toread; + offset += toread; + length -= toread; + discWrote += toread; + } + return wrote; +} + +s32 GCDumper::ReadDiscHeader(void) +{ + if(!ReadBuffer) + return -1; + + s32 result = 0; + + struct discHdr *gcheader = (struct discHdr *) memalign(32, ALIGN32(sizeof(struct discHdr))); + if(!gcheader) + return -1; + + s32 ret = Disc_ReadHeader(gcheader); + if(ret < 0) { + free(gcheader); + return ret; + } + + if(memcmp(gcheader->id, "GCOPDV", 6) == 0) + { + while(result == 0) + { + __ReadDVDPlain(ReadBuffer, 0x10, 0x40+(gameOffsets.size()*4)); + u64 MultiGameOffset = ((u64)(*(u32*)ReadBuffer)) << 2ULL; + if(!MultiGameOffset) + break; + + ret = __ReadDVDPlain(gcheader, sizeof(struct discHdr), MultiGameOffset); + if(ret < 0) + result = -3; + + if(ReadDiscInfo(MultiGameOffset) < 0) + result = -4; + discHeaders.push_back(*gcheader); + gameOffsets.push_back(MultiGameOffset); + } + } + else + { + discHeaders.push_back(*gcheader); + gameOffsets.push_back(0); + + if(ReadDiscInfo(0) < 0) + result = -5; + } + + free(gcheader); + return result; +} + +int GCDumper::ReadDiscInfo(const u64 &game_offset) +{ + if(!ReadBuffer) + return -1; + + s32 ret = __ReadDVDPlain(ReadBuffer, 0x440, game_offset); + if(ret < 0) + return -2; + + u32 FSTOffset = *(u32*)(ReadBuffer+0x424); + u32 FSTSize = *(u32*)(ReadBuffer+0x428); + u32 GamePartOffset = *(u32*)(ReadBuffer+0x434); + u32 DataSize = *(u32*)(ReadBuffer+0x438); + u32 DiscSize = DataSize + GamePartOffset; + + u32 installSize = 0; + + if(!compressed) + { + installSize += DiscSize; + } + else + { + u8 *FSTBuffer = (u8 *)memalign(32, ALIGN32(FSTSize)); + + ret = __ReadDVDPlain(FSTBuffer, ALIGN32(FSTSize), game_offset+FSTOffset); + if(ret < 0) + { + free(FSTBuffer); + return -3; + } + + u8 *FSTable = (u8*)FSTBuffer; + u32 FSTEnt = *(u32*)(FSTable+0x08); + FST *fst = (FST *)(FSTable); + + installSize += (FSTOffset + FSTSize); + + u32 i; + u32 correction; + u32 align; + + for( i=1; i < FSTEnt; ++i ) + { + if( fst[i].Type ) { + continue; + } + else + { + for(align = 0x8000; align > 2; align/=2) + { + if((fst[i].FileOffset & (align-1)) == 0 || force_align32) + { + correction = 0; + while(((installSize+correction) & (align-1)) != 0) + correction++; + installSize += correction; + break; + } + } + installSize += fst[i].FileLength; + } + } + free(FSTBuffer); + } + + gameSizes.push_back(installSize); + return 0; +} + +s32 GCDumper::InstallGame(const char *installpath, u32 game, const char *installedGamePath) +{ + if(!ReadBuffer || game >= discHeaders.size() || game >= gameOffsets.size() || game >= gameSizes.size()) + return -1; + + const u64 &game_offset = gameOffsets[game]; + const struct discHdr &gcheader = discHeaders[game]; + + discWrote = 0; + discTotal = gameSizes[game]; + + //! check for enough free space + { + struct statvfs sd_vfs; + if(statvfs(installpath, &sd_vfs) != 0) + { + ShowError(tr("Could not get free device space for game.")); + return -102; + } + + if(((u64)sd_vfs.f_frsize * (u64)sd_vfs.f_bfree) < discTotal) + { + ShowError(tr("Not enough free space on device.")); + return -103; + } + } + + s32 ret = __ReadDVDPlain(ReadBuffer, 0x440, game_offset); + if(ret < 0) { + ShowError(tr("Disc read error.")); + return -2; + } + + u32 Disc = *(u8*)(ReadBuffer+0x06); + u32 ApploaderSize = *(u32*)(ReadBuffer+0x400); + u32 DOLOffset = *(u32*)(ReadBuffer+0x420); + u32 FSTOffset = *(u32*)(ReadBuffer+0x424); + u32 FSTSize = *(u32*)(ReadBuffer+0x428); + u32 GamePartOffset = *(u32*)(ReadBuffer+0x434); + u32 DataSize = *(u32*)(ReadBuffer+0x438); + u32 DOLSize = FSTOffset - DOLOffset; + u32 DiscSize = DataSize + GamePartOffset; + + u8 *FSTBuffer = (u8 *)memalign(32, ALIGN32(FSTSize)); + if(!FSTBuffer) { + ShowError(tr("Not enough memory for FST.")); + return -3; + } + + ret = __ReadDVDPlain(FSTBuffer, ALIGN32(FSTSize), game_offset+FSTOffset); + if(ret < 0) + { + free(FSTBuffer); + ShowError(tr("Disc read error.")); + return -3; + } + + char gametitle[65]; + snprintf(gametitle, sizeof(gametitle), "%s", gcheader.title); + Wbfs_Fat::CleanTitleCharacters(gametitle); + + char gamepath[512]; + // snprintf(gamepath, sizeof(gamepath), "%s%s [%.6s]%s/", installpath, gametitle, gcheader.id, Disc ? "2" : ""); // Disc2 currently needs to be on the same folder. + snprintf(gamepath, sizeof(gamepath), "%s%s [%.6s]/", installpath, gametitle, gcheader.id); + + // If another Disc from the same gameID already exists, let's use that path + if(strlen((char *)installedGamePath) != 0) + snprintf(gamepath, sizeof(gamepath), "%s/", installedGamePath); + + CreateSubfolder(gamepath); + + // snprintf(gamepath, sizeof(gamepath), "%s%s [%.6s]%s/game.iso", installpath, gametitle, gcheader.id, Disc ? "2" : ""); // Disc2 currently needs to be on the same folder. + snprintf(gamepath, sizeof(gamepath), "%s%s.iso", gamepath, Disc ? "disc2" : "game"); + + FILE *f = fopen(gamepath, "wb"); + if(!f) + { + free(FSTBuffer); + ShowError(tr("Can't open file for write: %s"), gamepath); + return -4; + } + + u8 *FSTable = (u8*)FSTBuffer; + u32 FSTEnt = *(u32*)(FSTable+0x08); + + FST *fst = (FST *)(FSTable); + + gprintf("Dumping: %s %s\n", gcheader.title, compressed ? "compressed" : "full"); + + gprintf("Apploader size : %d\n", ApploaderSize); + gprintf("DOL offset : 0x%08x\n", DOLOffset); + gprintf("DOL size : %d\n", DOLSize); + gprintf("FST offset : 0x%08x\n", FSTOffset); + gprintf("FST size : %d\n", FSTSize); + gprintf("Num FST entries: %d\n", FSTEnt); + gprintf("Data Offset : 0x%08x\n", FSTOffset+FSTSize); + gprintf("Disc size : %d\n", DiscSize); + if(compressed) + gprintf("Compressed size: %d\n", discTotal); + + + gprintf("Writing %s\n", gamepath); + + s32 result = 0; + + ProgressCancelEnable(true); + StartProgress(tr("Installing Game Cube Game..."), gcheader.title, 0, true, true); + + if(compressed) + { + u32 align; + u32 correction; + u32 toread; + u32 wrote = 0; + + ret = CopyDiscData(f, game_offset, (FSTOffset + FSTSize), ReadBuffer); + if(ret < 0) + result = -3; + + wrote += (FSTOffset + FSTSize); + + for(u32 i = 1; (result == 0) && (i < FSTEnt); ++i) + { + if(ProgressCanceled()) { + result = PROGRESS_CANCELED; + break; + } + + if( fst[i].Type ) { + continue; + } + else + { + for(align = 0x8000; align > 2; align/=2) + { + if((fst[i].FileOffset & (align-1)) == 0 || force_align32) + { + correction = 0; + while(((wrote+correction) & (align-1)) != 0) + correction++; + + wrote += correction; + while(correction) + { + toread = std::min(correction, BUF_SIZE); + memset(ReadBuffer, 0, toread); + fwrite(ReadBuffer, 1, toread, f); + correction -= toread; + } + break; + } + } + ret = CopyDiscData(f, game_offset+fst[i].FileOffset, fst[i].FileLength, ReadBuffer); + if(ret < 0) { + result = -2; + break; + } + + fst[i].FileOffset = wrote; + wrote += ret; + } + } + + fseek(f, FSTOffset, SEEK_SET); + fwrite(fst, 1, FSTSize, f); + + gprintf("Done!! Disc old size: %d, disc new size: %d, saved: %d\n", DiscSize, wrote, DiscSize - wrote); + } + else + { + ret = CopyDiscData(f, game_offset, discTotal, ReadBuffer); + if( ret < 0 ) + result = -2; + else + gprintf("Done!! Disc size: %d\n", DiscSize); + } + + // Stop progress + ProgressStop(); + ProgressCancelEnable(false); + + free(FSTBuffer); + fclose(f); + + if(result < 0) + { + RemoveFile(gamepath); + if(strlen((char *)installedGamePath) == 0) // If no other disc is installed in that folder, delete it. + { + char *pathPtr = strrchr(gamepath, '/'); + if(pathPtr) *pathPtr = 0; + RemoveFile(gamepath); + } + + if(result != PROGRESS_CANCELED) + ShowError(tr("Disc read error.")); + } + + return result; +} diff --git a/source/GameCube/GCDumper.hpp b/source/GameCube/GCDumper.hpp new file mode 100644 index 0000000..4d6a232 --- /dev/null +++ b/source/GameCube/GCDumper.hpp @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (C) 2012 + * by OverjoY and FIX94 for Wiiflow + * + * Adjustments for USB Loader GX by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ + +#ifndef GCDUMPER_H_ +#define GCDUMPER_H_ + +#include +#include + +using namespace std; + +class GCDumper +{ +public: + GCDumper(); + ~GCDumper(); + s32 InstallGame(const char *installpath, u32 game, const char *installedGamePath); + s32 ReadDiscHeader(void); + int ReadDiscInfo(const u64 &game_offset); + void SetForceAlign(bool b) { force_align32 = b; } + void SetCompressed(bool b) { compressed = b; } + vector & GetDiscHeaders() { return discHeaders; } + vector & GetDiscSizes() { return gameSizes; } +private: + s32 CopyDiscData(FILE *f, u64 offset, u32 length, u8 *buffer); + + vector discHeaders; + vector gameSizes; + vector gameOffsets; + bool force_align32; + bool compressed; + u32 discWrote; + u32 discTotal; + u8 *ReadBuffer; + + typedef struct + { + union + { + struct + { + u32 Type :8; + u32 NameOffset :24; + }; + u32 TypeName; + }; + union + { + struct + { + u32 FileOffset; + u32 FileLength; + }; + struct + { + u32 ParentOffset; + u32 NextOffset; + }; + u32 entry[2]; + }; + } FST; +}; +#endif diff --git a/source/GameCube/GCGames.cpp b/source/GameCube/GCGames.cpp new file mode 100644 index 0000000..07129a4 --- /dev/null +++ b/source/GameCube/GCGames.cpp @@ -0,0 +1,650 @@ +/**************************************************************************** + * Copyright (C) 2011 Dimok + * + * 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 +#include "GCGames.h" +#include "FileOperations/fileops.h" +#include "settings/GameTitles.h" +#include "settings/CSettings.h" +#include "prompts/GCDeleteMenu.h" +#include "prompts/PromptWindows.h" +#include "prompts/ProgressWindow.h" +#include "language/gettext.h" +#include "usbloader/wbfs/wbfs_fat.h" +#include "utils/tools.h" +#include "system/IosLoader.h" +#include "menu.h" +#include "gecko.h" + +GCGames *GCGames::instance = NULL; + +inline bool isGameID(const u8 *id) +{ + for (int i = 0; i < 6; i++) + if (!isalnum((int) id[i])) + return false; + + return true; +} + +const char *GCGames::GetPath(const char *gameID) const +{ + if(!gameID) + return ""; + + for(u32 i = 0; i < HeaderList.size(); i++) + { + if(strncasecmp((const char *) HeaderList[i].id, gameID, 6) == 0) + return PathList[i].c_str(); + } + + return ""; +} + +void GCGames::LoadGameList(const string &path, vector &headerList, vector &pathList) +{ + struct discHdr tmpHdr; + struct stat st; + u8 id[8]; + u8 disc_number = 0; + char fpath[1024]; + char fname_title[64]; + DIR *dir_iter; + struct dirent *dirent; + + dir_iter = opendir(path.c_str()); + if (!dir_iter) return; + + while ((dirent = readdir(dir_iter)) != 0) + { + const char *dirname = dirent->d_name; + if(!dirname) + continue; + + if (dirname[0] == '.') continue; + + // reset id and title + memset(id, 0, sizeof(id)); + *fname_title = 0; + + bool lay_a = false; + bool lay_b = false; + int len = strlen(dirname); + if (len >= 8) + { + if (Wbfs_Fat::CheckLayoutB((char *) dirname, len, id, fname_title)) + { + // path/TITLE[GAMEID]/game.iso + lay_b = true; + } + else if (dirname[6] == '_') + { + // path/GAMEID_TITLE/game.iso + memcpy(id, dirname, 6); + + if(isGameID(id)) + { + lay_a = true; + snprintf(fname_title, sizeof(fname_title), "%s", &dirname[7]); + } + } + } + else if(len == 6 && isGameID((u8*)dirname)) { + memcpy(id, dirname, 6); + lay_a = true; + } + + if(!lay_a && !lay_b) + memset(id, 0, sizeof(id)); + + bool found = false; + bool extracted = false; + + for(int i = 0; i < 4; i++) + { + char name[50]; + snprintf(name, sizeof(name), "%.6s.%s", (i % 2) == 0 ? "game" : (char *) id, i >= 2 ? "gcm" : "iso"); + snprintf(fpath, sizeof(fpath), "%s%s/%s", path.c_str(), dirname, name); + if((found = (stat(fpath, &st) == 0)) == true) + break; + } + + // Check if only disc2.iso is present + if(!found) + { + for(int i = 0; i < 2; i++) + { + char name[50]; + snprintf(name, sizeof(name), "disc2.%s", (i % 2) == 0 ? "gcm" : "iso"); // allow gcm, though DM(L) require "disc2.iso" filename + snprintf(fpath, sizeof(fpath), "%s%s/%s", path.c_str(), dirname, name); + if((found = (stat(fpath, &st) == 0)) == true) + { + disc_number = 1; + break; + } + } + } + + if(!found) + { + snprintf(fpath, sizeof(fpath), "%s%s/sys/boot.bin", path.c_str(), dirname); + if(stat(fpath, &st) != 0) + continue; + // this game is extracted + extracted = true; + } + + //! GAMEID was not found + if(!lay_a && !lay_b) { + // read game ID and title from disc header + // iso file + FILE *fp = fopen(fpath, "rb"); + if (fp != NULL) + { + memset(&tmpHdr, 0, sizeof(tmpHdr)); + fread(&tmpHdr, sizeof(struct discHdr), 1, fp); + fclose(fp); + + if (tmpHdr.gc_magic == GCGames::MAGIC) + { + memcpy(id, tmpHdr.id, 6); + snprintf(fname_title, sizeof(fname_title), "%s", tmpHdr.title); + } + } + } + + // if we have titles.txt entry use that + const char *title = GameTitles.GetTitle(id); + + // if no titles.txt get title from dir or file name + if (strlen(title) == 0 && !Settings.ForceDiscTitles && strlen(fname_title) > 0) + title = fname_title; + + if (*id != 0 && strlen(title) > 0) + { + string gamePath = string(path) + dirname + (extracted ? "/" : strrchr(fpath, '/')); + memset(&tmpHdr, 0, sizeof(tmpHdr)); + memcpy(tmpHdr.id, id, 6); + strncpy(tmpHdr.title, title, sizeof(tmpHdr.title)-1); + tmpHdr.magic = GCGames::MAGIC; + tmpHdr.type = extracted ? TYPE_GAME_GC_EXTRACTED : TYPE_GAME_GC_IMG; + tmpHdr.disc_no = disc_number; + headerList.push_back(tmpHdr); + pathList.push_back(gamePath); + continue; + } + + // else read it from file directly + // iso file + FILE *fp = fopen(fpath, "rb"); + if (fp != NULL) + { + memset(&tmpHdr, 0, sizeof(tmpHdr)); + fread(&tmpHdr, sizeof(struct discHdr), 1, fp); + fclose(fp); + + if (tmpHdr.gc_magic == GCGames::MAGIC) + { + string gamePath = string(path) + dirname + (extracted ? "/" : strrchr(fpath, '/')); + tmpHdr.magic = tmpHdr.gc_magic; + tmpHdr.type = extracted ? TYPE_GAME_GC_EXTRACTED : TYPE_GAME_GC_IMG; + headerList.push_back(tmpHdr); + pathList.push_back(gamePath); + + // Save title for next start + GameTitles.SetGameTitle(tmpHdr.id, tmpHdr.title); + } + } + } + + closedir(dir_iter); +} + +u32 GCGames::LoadAllGames(void) +{ + PathList.clear(); + HeaderList.clear(); + sdGCList.clear(); + sdGCPathList.clear(); + + if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) == 0 || Settings.GameCubeSource != GC_SOURCE_SD) + LoadGameList(Settings.GameCubePath, HeaderList, PathList); + + if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) != 0 && (Settings.GameCubeSource != GC_SOURCE_MAIN)) + { + LoadGameList(Settings.GameCubeSDPath, sdGCList, sdGCPathList); + + for(u32 i = 0; i < sdGCList.size(); ++i) + { + if(Settings.GameCubeSource != GC_SOURCE_SD) + { + u32 n; + for(n = 0; n < HeaderList.size(); ++n) + { + //! Display only one game if it is present on both SD and USB. + if(memcmp(HeaderList[n].id, sdGCList[i].id, 6) == 0) + { + if((Settings.GameCubeSource == GC_SOURCE_MAIN_SD) || + (Settings.GameCubeSource == GC_SOURCE_AUTO && (IosLoader::GetMIOSInfo() == DIOS_MIOS || IosLoader::GetMIOSInfo() == QUADFORCE_USB))) // DIOS MIOS - Show the game on USB in priority + { + break; + } + else // replace the one loaded from USB with the same games on SD + { + memcpy(&HeaderList[n], &sdGCList[i], sizeof(struct discHdr)); + PathList[n] = sdGCPathList[i]; + break; + } + } + } + + // Not available in the main GC path + if(n == HeaderList.size()) { + HeaderList.push_back(sdGCList[i]); + PathList.push_back(sdGCPathList[i]); + } + } + else // GC_SOURCE_SD + { + HeaderList.push_back(sdGCList[i]); + PathList.push_back(sdGCPathList[i]); + } + } + } + + return HeaderList.size(); +} + +bool GCGames::RemoveGame(const char *gameID) +{ + const char *path = GetPath(gameID); + if(*path == 0) + return false; + + RemoveSDGame(gameID); + + if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) == 0) + return true; + + struct discHdr *header = NULL; + for(u32 i = 0; i < HeaderList.size(); ++i) + { + if(strncmp(gameID, (char*)HeaderList[i].id, 6) == 0) + { + header = &HeaderList[i]; + break; + } + } + if(!header) + return false; + + char filepath[512]; + int result = 0; + + // the main path is the SD path as it is prefered, now delete USB + char cIsoPath[256]; + snprintf(cIsoPath, sizeof(cIsoPath), "%s", path + strlen(Settings.GameCubeSDPath)); + + if(header->type == TYPE_GAME_GC_IMG) + { + // Remove game iso + snprintf(filepath, sizeof(filepath), "%s%s", Settings.GameCubePath, cIsoPath); + if(!RemoveFile(filepath)) + result = -1; + + // Remove path + char *pathPtr = strrchr(filepath, '/'); + if(pathPtr) *pathPtr = 0; + if(!RemoveFile(filepath)) + result = -1; + } + else if(header->type == TYPE_GAME_GC_EXTRACTED) + { + //! remove extracted gamecube game + snprintf(filepath, sizeof(filepath), "%s%s", Settings.GameCubePath, cIsoPath); + if(!RemoveDirectory(path)) + result = -1; + } + + return (result == 0); +} + +bool GCGames::RemoveSDGame(const char *gameID) +{ + const char *path = GetPath(gameID); + if(*path == 0) + return false; + + struct discHdr *header = NULL; + for(u32 i = 0; i < HeaderList.size(); ++i) + { + if(strncmp(gameID, (char*)HeaderList[i].id, 6) == 0) + { + header = &HeaderList[i]; + break; + } + } + if(!header) + return false; + + char filepath[512]; + int result = 0; + int ret; + + if(header->type == TYPE_GAME_GC_IMG) + { + // Remove game iso + snprintf(filepath, sizeof(filepath), "%s", path); + ret = RemoveFile(filepath); + if(ret != 0) + result = -1; + + // Remove path + char *pathPtr = strrchr(filepath, '/'); + if(pathPtr) *pathPtr = 0; + ret = RemoveFile(filepath); + if(ret != 0) + result = -1; + } + else if(header->type == TYPE_GAME_GC_EXTRACTED) + { + //! remove extracted gamecube game + ret = RemoveDirectory(path); + if(ret < 0) + result = -1; + } + + return (result == 0); +} + +float GCGames::GetGameSize(const char *gameID) +{ + const char *path = GetPath(gameID); + if(*path == 0) + return 0.0f; + + struct stat st; + + if(stat(path, &st) != 0) + return 0.0f; + + return ((float) st.st_size / GB_SIZE); +} + +bool GCGames::IsInstalled(const char *gameID, u8 disc_number) const +{ + for(u32 n = 0; n < HeaderList.size(); n++) + { + if(memcmp(HeaderList[n].id, gameID, 6) == 0) + { + if(HeaderList[n].type == TYPE_GAME_GC_EXTRACTED || Settings.GCInstallCompressed) + return true; // Multi-disc games in extracted form are currently unsupported by DML, no need to check further. + + if(HeaderList[n].disc_no == disc_number) // Disc number already in headerList. If Disc2 is loaded in headerList, then Disc1 is not installed yet + { + return true; + } + else if(disc_number == 1) // Check if the second Game Disc exists in the same folder than Disc1. + { + char filepath[512]; + snprintf(filepath, sizeof(filepath), "%s", GetPath(gameID)); + char *pathPtr = strrchr(filepath, '/'); + if(pathPtr) *pathPtr = 0; + snprintf(filepath, sizeof(filepath), "%s/disc2.iso", filepath); + + if(CheckFile(filepath)) + return true; + } + } + } + return false; +} + +bool GCGames::CopyUSB2SD(const struct discHdr *header) +{ + const char *path = GetPath((char*)header->id); + int oldGameCubeSource = Settings.GameCubeSource; + if(*path == 0) + return false; + + int choice = WindowPrompt(tr("The game is on USB."), tr("Do you want to copy the game to SD or delete a game on SD?"), tr("Copy"), tr("Show SD"), tr("Cancel")); + if(choice == 0) + return false; + + const char *cpTitle = GameTitles.GetTitle(header); + + if(choice == 2) + { + // Load Games from SD card only + Settings.GameCubeSource = GC_SOURCE_SD; + GCGames::Instance()->LoadAllGames(); + + GCDeleteMenu gcDeleteMenu; + gcDeleteMenu.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + gcDeleteMenu.SetEffect(EFFECT_FADE, 20); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&gcDeleteMenu); + + gcDeleteMenu.Show(); + + gcDeleteMenu.SetEffect(EFFECT_FADE, -20); + while(gcDeleteMenu.GetEffect() > 0) usleep(1000); + + mainWindow->Remove(&gcDeleteMenu); + mainWindow->SetState(STATE_DEFAULT); + + // Reload user's gameCubeSource setting + Settings.GameCubeSource = oldGameCubeSource; + GCGames::Instance()->LoadAllGames(); + + if(!WindowPrompt(tr("Do you want to copy now?"), cpTitle, tr("Yes"), tr("Cancel"))) + return false; + } + + struct statvfs sd_vfs; + if(statvfs(Settings.GameCubeSDPath, &sd_vfs) != 0) + { + WindowPrompt(tr("Error:"), tr("SD Card could not be accessed."), tr("OK")); + return false; + } + + u64 filesize = 0; + + if(header->type == TYPE_GAME_GC_IMG) { + filesize = FileSize(path); + } + else if(header->type == TYPE_GAME_GC_EXTRACTED) { + StartProgress(tr("Getting game folder size..."), tr("Please wait"), 0, true, true); + ShowProgress(0, 1); + filesize = FileSize(path); + ProgressStop(); + } + + while(((u64)sd_vfs.f_frsize * (u64)sd_vfs.f_bfree) < filesize) + { + choice = WindowPrompt(tr("Error: Not enough space on SD."), tr("Do you want to delete a game on SD?"), tr("Yes"), tr("Cancel")); + if(choice == 0) + return false; + + GCDeleteMenu gcDeleteMenu; + gcDeleteMenu.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + gcDeleteMenu.SetEffect(EFFECT_FADE, 20); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&gcDeleteMenu); + + gcDeleteMenu.Show(); + + gcDeleteMenu.SetEffect(EFFECT_FADE, -20); + while(gcDeleteMenu.GetEffect() > 0) usleep(1000); + + mainWindow->Remove(&gcDeleteMenu); + mainWindow->SetState(STATE_DEFAULT); + + statvfs(Settings.GameCubeSDPath, &sd_vfs); + } + + const char *cIsoPath = path + strlen(Settings.GameCubePath); + char destPath[512]; + snprintf(destPath, sizeof(destPath), "%s%s", Settings.GameCubeSDPath, cIsoPath); + + int res = -1; + + if(header->type == TYPE_GAME_GC_IMG) + { + ProgressCancelEnable(true); + StartProgress(tr("Copying GC game..."), cpTitle, 0, true, true); + + char *ptr = strrchr(destPath, '/'); + if(ptr) *ptr = 0; + + CreateSubfolder(destPath); + + snprintf(destPath, sizeof(destPath), "%s%s", Settings.GameCubeSDPath, cIsoPath); + + res = CopyFile(path, destPath); + } + else if(header->type == TYPE_GAME_GC_EXTRACTED) + { + res = CopyDirectory(path, destPath); + } + + // Refresh list + GCGames::Instance()->LoadAllGames(); + + ProgressStop(); + ProgressCancelEnable(false); + + if(res == PROGRESS_CANCELED) + { + if(header->type == TYPE_GAME_GC_IMG) + { + // remove file and path + RemoveFile(destPath); + char *ptr = strrchr(destPath, '/'); + if(ptr) *ptr = 0; + RemoveFile(destPath); + } + + WindowPrompt(tr("Copying Canceled"), 0, tr("OK")); + return false; + } + else if(res < 0) + { + if(header->type == TYPE_GAME_GC_IMG) + { + // remove file and path + RemoveFile(destPath); + char *ptr = strrchr(destPath, '/'); + if(ptr) *ptr = 0; + RemoveFile(destPath); + } + + WindowPrompt(tr("Error:"), tr("Failed copying file"), tr("OK")); + return false; + } + else + { + return WindowPrompt(tr("Successfully copied"), tr("Do you want to start the game now?"), tr("Yes"), tr("Cancel")); + } +} + +int nintendontBuildDate(const char *NIN_loader_path, char *NINBuildDate) +{ + + char NIN_loader[100]; + snprintf(NIN_loader, sizeof(NIN_loader), "%sboot.dol", NIN_loader_path); + if(!CheckFile(NIN_loader)) + snprintf(NIN_loader, sizeof(NIN_loader), "%sloader.dol", NIN_loader_path); + if(CheckFile(NIN_loader)) + { + u8 *buffer = NULL; + u32 filesize = 0; + const char* str = "Nintendont Loader"; + bool found = false; + if(LoadFileToMem(NIN_loader, &buffer, &filesize)) + { + for(u32 i = 0; i < filesize-100; ++i) + { + if( memcmp(buffer+i, str, strlen(str)) == 0) + { + // Write buffer in NINheader + char NINHeader[100]; + for(u8 j = 0 ; j < 99 ; j++) + NINHeader[j] = *(u8*)(buffer+i+j) == 0 ? ' ' : *(u8*)(buffer+i+j); // replace \0 with a space. + NINHeader[99] = '\0'; + + // Search month string start position in header + char *dateStart = NULL; + const char *month[] = {"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ", "Jui ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "}; + for(u8 m = 0 ; m < 12 ; m++) + { + dateStart = strstr(NINHeader, month[m]); + if(dateStart != NULL) + break; + } + if(dateStart == NULL) + break; + + dateStart[20] = '\0'; + + sprintf(NINBuildDate, "%.20s", dateStart); + gprintf("Nintendont Build date : %.20s \n", dateStart); + + found = true; + break; + } + } + free(buffer); + } + if(found) + return 1; + } + + return 0; +} + +int nintendontVersion(const char *NIN_loader_path, char *NINVersion, int len) +{ + char NIN_loader[100]; + u32 NINRev = 0; + snprintf(NIN_loader, sizeof(NIN_loader), "%sboot.dol", NIN_loader_path); + if(!CheckFile(NIN_loader)) + snprintf(NIN_loader, sizeof(NIN_loader), "%sloader.dol", NIN_loader_path); + if(CheckFile(NIN_loader)) + { + u8 *buffer = NULL; + u32 filesize = 0; + const char* str = "$$Version:"; + if(LoadFileToMem(NIN_loader, &buffer, &filesize)) + { + for(u32 i = 0; i < filesize; i += 32) + { + if(memcmp( buffer+i, str, strlen(str)) == 0) + { + // Write buffer in NINVersion + snprintf(NINVersion, len, "%s", buffer+i+strlen(str)); + NINRev = atoi(strchr(NINVersion, '.')+1); + break; + } + } + free(buffer); + } + } + + return NINRev; +} diff --git a/source/GameCube/GCGames.h b/source/GameCube/GCGames.h new file mode 100644 index 0000000..38bc3e4 --- /dev/null +++ b/source/GameCube/GCGames.h @@ -0,0 +1,74 @@ +/**************************************************************************** + * Copyright (C) 2011 Dimok + * + * 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 _GCGAMES_H_ +#define _GCGAMES_H_ + +#include +#include +#include +#include "usbloader/disc.h" +#include "settings/CSettings.h" + +int nintendontBuildDate(const char *NIN_loader_path, char* NINBuildDate); +int nintendontVersion(const char *NIN_loader_path, char* NINVersion, int len); + +using namespace std; + +class GCGames +{ +public: + static const u32 MAGIC = 0xC2339F3D; + + static GCGames *Instance(void) { if(!instance) instance = new GCGames(); return instance; } + static void DestroyInstance(void) { delete instance; instance = NULL; } + + static u8 *GetOpeningBnr(const char *gameID); + + u32 LoadAllGames(void); + + void LoadGameList(const string &path, vector &headerList, vector &pathList); + + bool RemoveGame(const char *gameID); + bool RemoveSDGame(const char *gameID); + float GetGameSize(const char *gameID); + + const char *GetPath(const char *gameID) const; + + vector & GetHeaders(void) + { + LoadAllGames(); + + return HeaderList; + } + + vector & GetSDHeaders(void) { + return sdGCList; + } + + bool CopyUSB2SD(const struct discHdr *header); + bool IsInstalled(const char *gameID, u8 disc_number) const; +private: + + static GCGames *instance; + + vector PathList; + vector HeaderList; + vector sdGCList; + vector sdGCPathList; +}; + +#endif diff --git a/source/GameCube/NIN_Config.h b/source/GameCube/NIN_Config.h new file mode 100644 index 0000000..9845d0f --- /dev/null +++ b/source/GameCube/NIN_Config.h @@ -0,0 +1,122 @@ +/**************************************************************************** + * Copyright (C) 2013 Cyan + * + * 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 NIN_CONFIG_H_ +#define NIN_CONFIG_H_ + +#include + +#define NIN_MAGIC 0x01070CF6 +#define NIN_CFG_VERSION 0x00000009 // ASA + +typedef struct NIN_CFG +{ + u32 Magicbytes; // 0x01070CF6 + u32 Version; // v4 since v3.354, v5 since v3.358, v6 since v3.368, v7 since 4.424, v8 since 4.431, v9 since 6.489 // ASA + u32 Config; + u32 VideoMode; + u32 Language; + char GamePath[255]; + char CheatPath[255]; + u32 MaxPads; // added in r42 - cfg version 2 + u32 GameID; // added in r83 - cfg version 2 + union + { + u32 MemCardBlocks; // added in v1.135 - cfg version 3 - u32 in v3, Char in v4 + struct + { + char MemCardBlocksV4;// replaced in v3.354 - cfg version 4 - from u32 in v3 to Char in v4 + char VideoScale; // added in v3.354 - cfg version 4 + char VideoOffset; // added in v3.354 - cfg version 4 + char BBAProfile; // added in v6.489 - cfg version 9 // ASA + }; + }; +} NIN_CFG; + +enum ninconfig +{ + NIN_CFG_CHEATS = (1<<0), + NIN_CFG_DEBUGGER = (1<<1), // Only for Wii Version + NIN_CFG_DEBUGWAIT = (1<<2), // Only for Wii Version + NIN_CFG_MEMCARDEMU = (1<<3), + NIN_CFG_CHEAT_PATH = (1<<4), + NIN_CFG_FORCE_WIDE = (1<<5), + NIN_CFG_FORCE_PROG = (1<<6), + NIN_CFG_AUTO_BOOT = (1<<7), + NIN_CFG_HID = (1<<8), // Unused since v3.304 + NIN_CFG_REMLIMIT = (1<<8), // v3.358 cfg version 5 + NIN_CFG_OSREPORT = (1<<9), + NIN_CFG_USB = (1<<10), // r40 + NIN_CFG_LED = (1<<11), // v1.45 + NIN_CFG_LOG = (1<<12), // v1.109 + NIN_CFG_MC_MULTI = (1<<13), // v1.135 + NIN_CFG_NATIVE_SI = (1<<14), // v2.189 + NIN_CFG_WIIU_WIDE = (1<<15), // v2.258 + NIN_CFG_ARCADE_MODE = (1<<16), // v4.424 + NIN_CFG_CC_RUMBLE = (1 << 17),// v4.431 cfg version 8 + NIN_CFG_SKIP_IPL = (1 << 18),// v4.435 + NIN_CFG_BBA = (1 << 19),// v6.489 // ASA +}; + +enum ninvideomode +{ + NIN_VID_AUTO = (0<<16), + NIN_VID_FORCE = (1<<16), + NIN_VID_NONE = (2<<16), // replaced by FORCE_DF in v2.200 - v2.207 + NIN_VID_FORCE_DF = (4<<16), // v2.208+ + + NIN_VID_MASK = NIN_VID_AUTO|NIN_VID_FORCE|NIN_VID_NONE|NIN_VID_FORCE_DF, + + NIN_VID_FORCE_PAL50 = (1<<0), + NIN_VID_FORCE_PAL60 = (1<<1), + NIN_VID_FORCE_NTSC = (1<<2), + NIN_VID_FORCE_MPAL = (1<<3), + + NIN_VID_FORCE_MASK = NIN_VID_FORCE_PAL50|NIN_VID_FORCE_PAL60|NIN_VID_FORCE_NTSC|NIN_VID_FORCE_MPAL, + + NIN_VID_PROG = (1<<4), + NIN_VID_PATCH_PAL50 = (1<<5), // v3.368 cfg version 6 +}; + +enum ninlanguage +{ + NIN_LAN_ENGLISH = 0, + NIN_LAN_GERMAN = 1, + NIN_LAN_FRENCH = 2, + NIN_LAN_SPANISH = 3, + NIN_LAN_ITALIAN = 4, + NIN_LAN_DUTCH = 5, + +/* Auto will use English for E/P region codes and + only other languages when these region codes are used: D/F/S/I */ + + NIN_LAN_AUTO = -1, +}; + +// blocks = value , internal code , file size/bytes +//Mem0059 = 0, 0x04, 0x0080000 +//Mem0123 = 1, 0x08, 0x0100000 +//Mem0251 = 2, 0x10, 0x0200000 +//Mem0507 = 3, 0x20, 0x0400000 +//Mem1019 = 4, 0x40, 0x0800000 +//Mem2043 = 5, 0x80, 0x1000000 +#define MEM_CARD_MAX (5) +#define MEM_CARD_CODE(x) (1<<(x+2)) +#define MEM_CARD_SIZE(x) (1<<(x+19)) +#define MEM_CARD_BLOCKS(x) ((1<<(x+6))-5) + + +#endif diff --git a/source/ImageOperations/ImageWrite.c b/source/ImageOperations/ImageWrite.c new file mode 100644 index 0000000..c7d1558 --- /dev/null +++ b/source/ImageOperations/ImageWrite.c @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include "ImageWrite.h" + +#define LIMIT(x, min, max) ( (x < min) ? min : (x > max) ? max : x ) + +bool WriteGDImage(const char * filepath, gdImagePtr gdImg, u8 format, u8 compression) +{ + if(gdImg == 0) + return false; + + FILE * file = fopen(filepath, "wb"); + if(!file) + return false; + + switch(format) + { + default: + case IMAGE_PNG: + gdImagePng(gdImg, file); + break; + case IMAGE_JPEG: + gdImageJpeg(gdImg, file, LIMIT(100-compression, 0, 100)); + break; + } + + fclose(file); + + return true; +} diff --git a/source/ImageOperations/ImageWrite.h b/source/ImageOperations/ImageWrite.h new file mode 100644 index 0000000..c90d69d --- /dev/null +++ b/source/ImageOperations/ImageWrite.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef IMAGEWRITE_H_ +#define IMAGEWRITE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** Supported image write formats **/ +#define IMAGE_PNG 0 +#define IMAGE_JPEG 1 + +/** compression **/ +//!< JPEG-Format (0-100): where 0 is best quality and 100 best compression + +bool WriteGDImage(const char * filepath, gdImagePtr gdImg, u8 format, u8 compression); + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif //IMAGEWRITE_H_ diff --git a/source/ImageOperations/TextureConverter.c b/source/ImageOperations/TextureConverter.c new file mode 100644 index 0000000..72182be --- /dev/null +++ b/source/ImageOperations/TextureConverter.c @@ -0,0 +1,611 @@ +/*************************************************************************** + * Copyright (C) 2010 + * Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * TextureConverter.cpp + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include "TextureConverter.h" + +#define MAXWIDTH 1024.0f +#define MAXHEIGHT 768.0f + +static u16 avg(u16 w0, u16 w1, u16 c0, u16 c1) +{ + u16 a0, a1; + u16 a, c; + + a0 = c0 >> 11; + a1 = c1 >> 11; + a = (w0*a0 + w1*a1) / (w0 + w1); + c = a << 11; + + a0 = (c0 >> 5) & 63; + a1 = (c1 >> 5) & 63; + a = (w0*a0 + w1*a1) / (w0 + w1); + c |= a << 5; + + a0 = c0 & 31; + a1 = c1 & 31; + a = (w0*a0 + w1*a1) / (w0 + w1); + c |= a; + + return c; +} + +bool I4ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im) +{ + u32 x, y; + u32 x1, y1; + u32 iv; + + if(!buffer) + return false; + + *im = gdImageCreateTrueColor(width, height); + if(*im == 0) + return false; + + gdImageAlphaBlending(*im, 0); + gdImageSaveAlpha(*im, 1); + + for(iv = 0, y1 = 0; y1 < height; y1 += 8) + { + for(x1 = 0; x1 < width; x1 += 8) + { + for(y = y1; y < (y1 + 8); y++) + { + for(x = x1; x < (x1 + 8); x += 2, iv++) + { + if((x >= width) || (y >= height)) + continue; + + u8 oldpixel = buffer[iv]; + u8 b = (oldpixel >> 4) * 255 / 15; + u8 g = (oldpixel >> 4) * 255 / 15; + u8 r = (oldpixel >> 4) * 255 / 15; + u8 a = gdAlphaOpaque; + + gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a)); + + r = (oldpixel & 0xF) * 255 / 15; + g = (oldpixel & 0xF) * 255 / 15; + b = (oldpixel & 0xF) * 255 / 15; + a = gdAlphaOpaque; + + gdImageSetPixel(*im, x+1, y, gdTrueColorAlpha(r, g, b, a)); + } + } + } + } + return true; +} + +bool IA4ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im) +{ + u32 x, y; + u32 x1, y1; + u32 iv; + + if(!buffer) + return false; + + *im = gdImageCreateTrueColor(width, height); + if(*im == 0) + return false; + + gdImageAlphaBlending(*im, 0); + gdImageSaveAlpha(*im, 1); + + for(iv = 0, y1 = 0; y1 < height; y1 += 4) + { + for(x1 = 0; x1 < width; x1 += 8) + { + for(y = y1; y < (y1 + 4); y++) + { + for(x = x1; x < (x1 + 8); x++) + { + u8 oldpixel = *(u8*)(buffer + (iv++)); + oldpixel = ~oldpixel; + + if((x >= width) || (y >= height)) + continue; + + u8 r = ((oldpixel & 0xF) * 255) / 15; + u8 g = ((oldpixel & 0xF) * 255) / 15; + u8 b = ((oldpixel & 0xF) * 255) / 15; + u8 a = ((oldpixel >> 4) * 255) / 15; + a = 127-127*a/255; + + gdImageSetPixel(*im, x+1, y, gdTrueColorAlpha(r, g, b, a)); + } + } + } + } + return true; +} + +bool I8ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im) +{ + u32 x, y; + u32 x1, y1; + u32 iv; + + if(!buffer) + return false; + + *im = gdImageCreateTrueColor(width, height); + if(*im == 0) + return false; + + gdImageAlphaBlending(*im, 0); + gdImageSaveAlpha(*im, 1); + + for(iv = 0, y1 = 0; y1 < height; y1 += 4) + { + for(x1 = 0; x1 < width; x1 += 8) + { + for(y = y1; y < (y1 + 4); y++) + { + for(x = x1; x < (x1 + 8); x++) + { + u8 pixel = *(u8*)(buffer + ((iv++) * 1)); + if((x >= width) || (y >= height)) + continue; + + u8 r = pixel; + u8 g = pixel; + u8 b = pixel; + u8 a = gdAlphaOpaque; + + gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a)); + } + } + } + } + + return true; +} + +bool IA8ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im) +{ + u32 x, y; + u32 x1, y1; + u32 iv; + + if(!buffer) + return false; + + *im = gdImageCreateTrueColor(width, height); + if(*im == 0) + return false; + + gdImageAlphaBlending(*im, 0); + gdImageSaveAlpha(*im, 1); + + for(iv = 0, y1 = 0; y1 < height; y1 += 4) + { + for(x1 = 0; x1 < width; x1 += 4) + { + for(y = y1; y < (y1 + 4); y++) + { + for(x = x1; x < (x1 + 4); x++) + { + u16 oldpixel = *(u16*)(buffer + ((iv++) * 2)); + + if((x >= width) || (y >= height)) + continue; + + u8 r = oldpixel >> 8; + u8 g = oldpixel >> 8; + u8 b = oldpixel >> 8; + u8 a = oldpixel & 0xFF; + a = 127-127*a/255; + + gdImageSetPixel(*im, x+1, y, gdTrueColorAlpha(r, g, b, a)); + } + } + } + } + return true; +} + +bool CMPToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im) +{ + u32 x, y; + u8 r, g, b, a; + u16 raw; + u16 c[4]; + int x0, x1, x2, y0, y1, y2, off; + int ww = (-(-(width) & -(8))); + int ix; + u32 px; + + if(!buffer) + return false; + + *im = gdImageCreateTrueColor(width, height); + if(*im == 0) + return false; + + gdImageAlphaBlending(*im, 0); + gdImageSaveAlpha(*im, 1); + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + x0 = x & 3; + x1 = (x >> 2) & 1; + x2 = x >> 3; + y0 = y & 3; + y1 = (y >> 2) & 1; + y2 = y >> 3; + off = (8 * x1) + (16 * y1) + (32 * x2) + (4 * ww * y2); + + c[0] = *(u16*)(buffer + off); + c[1] = *(u16*)(buffer + off + 2); + if (c[0] > c[1]) { + c[2] = avg(2, 1, c[0], c[1]); + c[3] = avg(1, 2, c[0], c[1]); + } else { + c[2] = avg(1, 1, c[0], c[1]); + c[3] = 0; + } + + px = *(u32*)(buffer + off + 4); + ix = x0 + (4 * y0); + raw = c[(px >> (30 - (2 * ix))) & 3]; + + r = (raw >> 8) & 0xf8; + g = (raw >> 3) & 0xf8; + b = (raw << 3) & 0xf8; + a = gdAlphaOpaque; + + gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a)); + } + } + + return true; +} + +bool RGB565ToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im) +{ + u32 x, y; + u32 x1, y1; + u32 iv; + + if(!buffer) + return false; + + *im = gdImageCreateTrueColor(width, height); + if(*im == 0) + return false; + + gdImageAlphaBlending(*im, 0); + gdImageSaveAlpha(*im, 1); + + for(iv = 0, y1 = 0; y1 < height; y1 += 4) + { + for(x1 = 0; x1 < width; x1 += 4) + { + for(y = y1; y < (y1 + 4); y++) + { + for(x = x1; x < (x1 + 4); x++) + { + if((x >= width) || (y >= height)) + continue; + + u16 pixel = *(u16*)(buffer + ((iv++) * 2)); + + u8 r = ((pixel >> 11) & 0x1F) << 3; + u8 g = ((pixel >> 5) & 0x3F) << 2; + u8 b = ((pixel >> 0) & 0x1F) << 3; + u8 a = gdAlphaOpaque; + + gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a)); + } + } + } + } + return true; +} + +bool RGB565A3ToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im) +{ + u32 x, y; + u32 x1, y1; + u32 iv; + + if(!buffer) + return false; + + *im = gdImageCreateTrueColor(width, height); + if(*im == 0) + return false; + + gdImageAlphaBlending(*im, 0); + gdImageSaveAlpha(*im, 1); + + for(iv = 0, y1 = 0; y1 < height; y1 += 4) + { + for(x1 = 0; x1 < width; x1 += 4) + { + for(y = y1; y < (y1 + 4); y++) + { + for(x = x1; x < (x1 + 4); x++) + { + u16 pixel = *(u16*)(buffer + ((iv++) * 2)); + if((x >= width) || (y >= height)) + continue; + + if(pixel & (1 << 15)) + { + // RGB5 + u8 r = (((pixel >> 10) & 0x1F) * 255) / 31; + u8 g = (((pixel >> 5) & 0x1F) * 255) / 31; + u8 b = (((pixel >> 0) & 0x1F) * 255) / 31; + u8 a = gdAlphaOpaque; + + gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a)); + } + else + { + // RGB4A3 + u8 r = (((pixel >> 12) & 0xF) * 255) / 15; + u8 g = (((pixel >> 8) & 0xF) * 255) / 15; + u8 b = (((pixel >> 4) & 0xF) * 255) / 15; + u8 a = (((pixel >> 0) & 0x7) * 64) / 7; + a = 127-127*a/255; + + gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a)); + } + } + } + } + } + + return true; +} + +bool RGBA8ToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im) +{ + u32 x, y, offset; + u8 r, g, b, a; + + if(!buffer) + return false; + + *im = gdImageCreateTrueColor(width, height); + if(*im == 0) + return false; + + gdImageAlphaBlending(*im, 0); + gdImageSaveAlpha(*im, 1); + + for(y = 0; y < height; y++) + { + for(x = 0; x < width; x++) + { + offset = coordsRGBA8(x, y, width); + a = *(buffer+offset); + r = *(buffer+offset+1); + g = *(buffer+offset+32); + b = *(buffer+offset+33); + + a = 127-127*a/255; + + gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a)); + } + } + + return true; +} + +bool YCbYCrToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im) +{ + u32 x, y, x1, YCbYCr; + int r, g, b; + u8 r1, g1, b1; + + if(!buffer) + return false; + + *im = gdImageCreateTrueColor(width, height); + if(*im == 0) + return false; + + gdImageAlphaBlending(*im, 0); + gdImageSaveAlpha(*im, 1); + + for(y = 0; y < height; y++) + { + for (x = 0, x1 = 0; x < (width / 2); x++, x1++) + { + YCbYCr = ((u32 *) buffer)[y*width/2+x]; + + u8 * val = (u8 *) &YCbYCr; + + r = (int) (1.371f * (val[3] - 128)); + g = (int) (- 0.698f * (val[3] - 128) - 0.336f * (val[1] - 128)); + b = (int) (1.732f * (val[1] - 128)); + + r1 = LIMIT(val[0] + r, 0, 255); + g1 = LIMIT(val[0] + g, 0, 255); + b1 = LIMIT(val[0] + b, 0, 255); + + gdImageSetPixel(*im, x1, y, gdTrueColorAlpha(r1, g1, b1, gdAlphaOpaque)); + x1++; + + r1 = LIMIT(val[2] + r, 0, 255); + g1 = LIMIT(val[2] + g, 0, 255); + b1 = LIMIT(val[2] + b, 0, 255); + gdImageSetPixel(*im, x1, y, gdTrueColorAlpha(r1, g1, b1, gdAlphaOpaque)); + } + } + + return true; +} + +u8 * GDImageToRGBA8(gdImagePtr * gdImg, int * w, int * h) +{ + int width = gdImageSX(*gdImg); + int height = gdImageSY(*gdImg); + float scale = 1.0f; + int retries = 100; //shouldn't need that long but to be sure + + gdImageAlphaBlending(*gdImg, 0); + gdImageSaveAlpha(*gdImg, 1); + + while(width*scale > MAXWIDTH || height*scale > MAXHEIGHT) + { + if(width*scale > MAXWIDTH) + scale = MAXWIDTH/width; + if(height*scale > MAXHEIGHT) + scale = MAXHEIGHT/height; + + retries--; + + if(!retries) + { + while(width*scale > MAXWIDTH || height*scale > MAXHEIGHT) + scale -= 0.02; + break; + } + } + + width = ALIGN((int) (width * scale)); + height = ALIGN((int) (height * scale)); + + if(width != gdImageSX(*gdImg) || height != gdImageSY(*gdImg)) + { + gdImagePtr dst = gdImageCreateTrueColor(width, height); + gdImageAlphaBlending(dst, 0); + gdImageSaveAlpha(dst, 1); + gdImageCopyResized(dst, *gdImg, 0, 0, 0, 0, width, height, gdImageSX(*gdImg), gdImageSY(*gdImg)); + + gdImageDestroy(*gdImg); + *gdImg = dst; + + width = gdImageSX(*gdImg); + height = gdImageSY(*gdImg); + } + + int len = datasizeRGBA8(width, height); + + u8 * data = (u8 *) memalign(32, len); + if(!data) + return NULL; + + u8 a; + int x, y; + u32 pixel, offset; + + for(y = 0; y < height; ++y) + { + for(x = 0; x < width; ++x) + { + pixel = gdImageGetPixel(*gdImg, x, y); + + a = 254 - 2*((u8)gdImageAlpha(*gdImg, pixel)); + if(a == 254) a++; + + offset = coordsRGBA8(x, y, width); + data[offset] = a; + data[offset+1] = (u8)gdImageRed(*gdImg, pixel); + data[offset+32] = (u8)gdImageGreen(*gdImg, pixel); + data[offset+33] = (u8)gdImageBlue(*gdImg, pixel); + } + } + + DCFlushRange(data, len); + + if(w) + *w = width; + if(h) + *h = height; + + return data; +} + +u8 * FlipRGBAImage(const u8 *src, u32 width, u32 height) +{ + u32 x, y; + + int len = datasizeRGBA8(width, height); + + u8 * data = memalign(32, len); + if(!data) + return NULL; + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + u32 offset = coordsRGBA8(x, y, width); + u8 a = src[offset]; + u8 r = src[offset+1]; + u8 g = src[offset+32]; + u8 b = src[offset+33]; + + u32 offset2 = coordsRGBA8((width-x-1), (height-y-1), width); + data[offset2] = a; + data[offset2+1] = r; + data[offset2+32] = g; + data[offset2+33] = b; + } + } + + DCFlushRange(data, len); + + return data; +} + +u8 * RGB8ToRGBA8(const u8 *src, u32 width, u32 height) +{ + u32 x, y, offset; + + int len = datasizeRGBA8(width, height); + + u8 * dst = (u8 *) memalign(32, len); + if(!dst) + return NULL; + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + offset = coordsRGBA8(x, y, width); + dst[offset] = 0xFF; + dst[offset+1] = src[(y*width+x)*3]; + dst[offset+32] = src[(y*width+x)*3+1]; + dst[offset+33] = src[(y*width+x)*3+2]; + } + } + + DCFlushRange(dst, len); + + return dst; +} diff --git a/source/ImageOperations/TextureConverter.h b/source/ImageOperations/TextureConverter.h new file mode 100644 index 0000000..43cc4f1 --- /dev/null +++ b/source/ImageOperations/TextureConverter.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2010 + * Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * TextureConverter.h + * + * A texture to GD image converter. + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef __TEXTURE_CONVERTER_H_ +#define __TEXTURE_CONVERTER_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include "utils/tools.h" + +#define coordsRGBA8(x, y, w) (((((y >> 2) * (w >> 2) + (x >> 2)) << 5) + ((y & 3) << 2) + (x & 3)) << 1) +#define datasizeRGBA8(w, h) ALIGN32(((w+3)>>2)*((h+3)>>2)*32*2) + +bool I4ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im); +bool IA4ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im); +bool I8ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im); +bool IA8ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im); +bool CMPToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im); +bool RGB565ToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im); +bool RGB565A3ToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im); +bool RGBA8ToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im); +bool YCbYCrToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im); +u8 * GDImageToRGBA8(gdImagePtr * gdImg, int * w, int * h); +u8 * FlipRGBAImage(const u8 *src, u32 width, u32 height); +u8 * RGB8ToRGBA8(const u8 *src, u32 width, u32 height); + +#ifdef __cplusplus +} +#endif + +#endif //__TEXTURE_CONVERTER_H_ diff --git a/source/ImageOperations/TplImage.cpp b/source/ImageOperations/TplImage.cpp new file mode 100644 index 0000000..29cda56 --- /dev/null +++ b/source/ImageOperations/TplImage.cpp @@ -0,0 +1,244 @@ +/*************************************************************************** + * Copyright (C) 2010 + * Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * TplImage.cpp + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include "FileOperations/fileops.h" +#include "TextureConverter.h" +#include "TplImage.h" + +TplImage::TplImage(const char * filepath) +{ + TPLBuffer = NULL; + TPLSize = 0; + + u8 * buffer = NULL; + u32 filesize = 0; + LoadFileToMem(filepath, &buffer, &filesize); + + if(buffer) + { + LoadImage(buffer, filesize); + free(buffer); + } +} + +TplImage::TplImage(const u8 * imgBuffer, u32 imgSize) +{ + TPLBuffer = NULL; + TPLSize = 0; + + if(imgBuffer) + { + LoadImage(imgBuffer, imgSize); + } +} + +TplImage::~TplImage() +{ + if(TPLBuffer) + free(TPLBuffer); + + Texture.clear(); + TextureHeader.clear(); + TplTextureBuffer.clear(); +} + +bool TplImage::LoadImage(const u8 * imgBuffer, u32 imgSize) +{ + if(TPLBuffer) + free(TPLBuffer); + + TPLBuffer = NULL; + TPLSize = 0; + + if(!imgBuffer) + return false; + + TPLBuffer = (u8 *) malloc(imgSize); + if(!TPLBuffer) + return false; + + TPLSize = imgSize; + + memcpy(TPLBuffer, imgBuffer, imgSize); + + return ParseTplFile(); +} + +bool TplImage::ParseTplFile() +{ + if(!TPLBuffer) + return false; + + TPLHeader = (const TPL_Header *) TPLBuffer; + + if(TPLHeader->magic != 0x0020AF30) + return false; + + if(TPLHeader->head_size != 12) + return false; + + const TPL_Texture * curTexture = (const TPL_Texture *) (TPLHeader+1); + + for(u32 i = 0; i < TPLHeader->num_textures; i++) + { + Texture.resize(i+1); + TextureHeader.resize(i+1); + TplTextureBuffer.resize(i+1); + + Texture[i] = curTexture; + + TextureHeader[i] = (const TPL_Texture_Header *) ((const u8 *) TPLBuffer+Texture[i]->text_header_offset); + + TplTextureBuffer[i] = TPLBuffer + TextureHeader[i]->offset; + + curTexture++; + } + + return true; + +} + +int TplImage::GetWidth(int pos) +{ + if(pos < 0 || pos >= (int) Texture.size()) + { + return 0; + } + + return TextureHeader[pos]->width; +} + +int TplImage::GetHeight(int pos) +{ + if(pos < 0 || pos >= (int) TextureHeader.size()) + { + return 0; + } + + return TextureHeader[pos]->height; +} + +u32 TplImage::GetFormat(int pos) +{ + if(pos < 0 || pos >= (int) TextureHeader.size()) + { + return 0; + } + + return TextureHeader[pos]->format; +} + +const u8 * TplImage::GetTextureBuffer(int pos) +{ + if(pos < 0 || pos >= (int) TplTextureBuffer.size()) + { + return 0; + } + + return TplTextureBuffer[pos]; +} + +int TplImage::GetTextureSize(int pos) +{ + int width = GetWidth(pos); + int height = GetHeight(pos); + int len = 0; + + switch(GetFormat(pos)) + { + case GX_TF_I4: + case GX_TF_CI4: + case GX_TF_CMPR: + len = ((width+7)>>3)*((height+7)>>3)*32; + break; + case GX_TF_I8: + case GX_TF_IA4: + case GX_TF_CI8: + len = ((width+7)>>3)*((height+7)>>2)*32; + break; + case GX_TF_IA8: + case GX_TF_CI14: + case GX_TF_RGB565: + case GX_TF_RGB5A3: + len = ((width+3)>>2)*((height+3)>>2)*32; + break; + case GX_TF_RGBA8: + len = ((width+3)>>2)*((height+3)>>2)*32*2; + break; + default: + len = ((width+3)>>2)*((height+3)>>2)*32*2; + break; + } + + return len; +} + +gdImagePtr TplImage::ConvertToGD(int pos) +{ + if(pos < 0 || pos >= (int) Texture.size()) + { + return 0; + } + + gdImagePtr gdImg = 0; + + switch(TextureHeader[pos]->format) + { + case GX_TF_RGB565: + RGB565ToGD(TplTextureBuffer[pos], TextureHeader[pos]->width, TextureHeader[pos]->height, &gdImg); + break; + case GX_TF_RGB5A3: + RGB565A3ToGD(TplTextureBuffer[pos], TextureHeader[pos]->width, TextureHeader[pos]->height, &gdImg); + break; + case GX_TF_RGBA8: + RGBA8ToGD(TplTextureBuffer[pos], TextureHeader[pos]->width, TextureHeader[pos]->height, &gdImg); + break; + case GX_TF_I4: + I4ToGD(TplTextureBuffer[pos], TextureHeader[pos]->width, TextureHeader[pos]->height, &gdImg); + break; + case GX_TF_I8: + I8ToGD(TplTextureBuffer[pos], TextureHeader[pos]->width, TextureHeader[pos]->height, &gdImg); + break; + case GX_TF_IA4: + IA4ToGD(TplTextureBuffer[pos], TextureHeader[pos]->width, TextureHeader[pos]->height, &gdImg); + break; + case GX_TF_IA8: + IA8ToGD(TplTextureBuffer[pos], TextureHeader[pos]->width, TextureHeader[pos]->height, &gdImg); + break; + case GX_TF_CMPR: + CMPToGD(TplTextureBuffer[pos], TextureHeader[pos]->width, TextureHeader[pos]->height, &gdImg); + break; + default: + gdImg = 0; + break; + } + + return gdImg; +} diff --git a/source/ImageOperations/TplImage.h b/source/ImageOperations/TplImage.h new file mode 100644 index 0000000..c2a5c17 --- /dev/null +++ b/source/ImageOperations/TplImage.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (C) 2010 + * Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * TplImage.h + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef TPL_IMAGE_H_ +#define TPL_IMAGE_H_ + +#include +#include +#include + +typedef struct +{ + u32 magic; + u32 num_textures; + u32 head_size; +} TPL_Header; + +typedef struct +{ + u32 text_header_offset; + u32 text_palette_offset; +} TPL_Texture; + +typedef struct +{ + u16 height; + u16 width; + u32 format; + u32 offset; + u32 wrap_s; + u32 wrap_t; + u32 min; + u32 mag; + f32 lod_bias; + u8 edge_lod; + u8 min_lod; + u8 max_lod; + u8 unpacked; +} TPL_Texture_Header; + +typedef struct +{ + u16 num_items; + u8 unpacked; + u8 pad; + u32 format; + u32 offset; +} TPL_Palette_Header; + +class TplImage +{ + public: + TplImage(const char * filepath); + TplImage(const u8 * imgBuffer, u32 imgSize); + ~TplImage(); + bool LoadImage(const u8 * imgBuffer, u32 imgSize); + int GetWidth(int Texture); + int GetHeight(int Texture); + u32 GetFormat(int Texture); + const u8 * GetTextureBuffer(int Texture); + int GetTextureSize(int Texture); + gdImagePtr ConvertToGD(int Texture); + private: + bool ParseTplFile(); + + u8 * TPLBuffer; + u32 TPLSize; + const TPL_Header * TPLHeader; + std::vector Texture; + std::vector TextureHeader; + std::vector TplTextureBuffer; +}; + +#endif diff --git a/source/SoundOperations/AifDecoder.cpp b/source/SoundOperations/AifDecoder.cpp new file mode 100644 index 0000000..8b4046f --- /dev/null +++ b/source/SoundOperations/AifDecoder.cpp @@ -0,0 +1,235 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include "AifDecoder.hpp" + +typedef struct +{ + u32 fccCOMM; + u32 size; + u16 channels; + u8 frames[4]; + u16 bps; + u8 freq[10]; +} SAIFFCommChunk; + +typedef struct +{ + u32 fccSSND; + u32 size; + u32 offset; + u32 blockSize; +} SAIFFSSndChunk; + +// ------ +// Copyright (C) 1988-1991 Apple Computer, Inc. +#ifndef HUGE_VAL +# define HUGE_VAL HUGE +#endif + +# define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0) + +static double ConvertFromIeeeExtended(const unsigned char* bytes) +{ + double f; + int expon; + unsigned long hiMant, loMant; + + expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); + hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) + | ((unsigned long)(bytes[3] & 0xFF) << 16) + | ((unsigned long)(bytes[4] & 0xFF) << 8) + | ((unsigned long)(bytes[5] & 0xFF)); + loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) + | ((unsigned long)(bytes[7] & 0xFF) << 16) + | ((unsigned long)(bytes[8] & 0xFF) << 8) + | ((unsigned long)(bytes[9] & 0xFF)); + + if (expon == 0 && hiMant == 0 && loMant == 0) { + f = 0; + } + else { + if (expon == 0x7FFF) { + f = HUGE_VAL; + } + else { + expon -= 16383; + f = ldexp(UnsignedToFloat(hiMant), expon-=31); + f += ldexp(UnsignedToFloat(loMant), expon-=32); + } + } + + if (bytes[0] & 0x80) + return -f; + else + return f; +} + +AifDecoder::AifDecoder(const char * filepath) + : SoundDecoder(filepath) +{ + SoundType = SOUND_AIF; + + if(!file_fd) + return; + + OpenFile(); +} + +AifDecoder::AifDecoder(const u8 * snd, int len) + : SoundDecoder(snd, len) +{ + SoundType = SOUND_AIF; + + if(!file_fd) + return; + + OpenFile(); +} + +AifDecoder::~AifDecoder() +{ +} + +void AifDecoder::OpenFile() +{ + SWaveHdr Header; + file_fd->read((u8 *) &Header, sizeof(SWaveHdr)); + + if (Header.magicRIFF != 'FORM') + { + CloseFile(); + return; + } + else if(Header.magicWAVE != 'AIFF') + { + CloseFile(); + return; + } + + u32 magic = 0; + + while(1) + { + int ret = file_fd->read((u8 *) &magic, sizeof(magic)); + if(ret <= 0) + { + CloseFile(); + return; + } + + if(magic == 'COMM') + break; + else + file_fd->seek(-3, SEEK_CUR); + } + + // seek back to COMM chunk start + file_fd->seek(-sizeof(magic), SEEK_CUR); + + SAIFFCommChunk CommHdr; + file_fd->read((u8 *) &CommHdr, sizeof(SAIFFCommChunk)); + + if(CommHdr.fccCOMM != 'COMM') + { + CloseFile(); + return; + } + + // Seek to next chunk start + file_fd->seek(-sizeof(SAIFFCommChunk) + sizeof(SWaveChunk) + CommHdr.size, SEEK_CUR); + + int ret = -1; + SWaveChunk chunkHdr; + memset(&chunkHdr, 0, sizeof(SWaveChunk)); + + do + { + // Seek to next chunk start + file_fd->seek(chunkHdr.size, SEEK_CUR); + ret = file_fd->read((u8 *) &chunkHdr, sizeof(SWaveChunk)); + } + while(ret > 0 && chunkHdr.magicDATA != 'SSND'); + + // Seek back to start of SSND chunk + file_fd->seek(-sizeof(SWaveChunk), SEEK_CUR); + + SAIFFSSndChunk SSndChunk; + file_fd->read((u8 *) &SSndChunk, sizeof(SAIFFSSndChunk)); + + if(SSndChunk.fccSSND != 'SSND') + { + CloseFile(); + return; + } + + DataOffset = file_fd->tell(); + DataSize = SSndChunk.size-8; + SampleRate = (u32) ConvertFromIeeeExtended(CommHdr.freq); + Format = VOICE_STEREO_16BIT; + + if(CommHdr.channels == 1 && CommHdr.bps == 8) + Format = VOICE_MONO_8BIT; + else if (CommHdr.channels == 1 && CommHdr.bps == 16) + Format = VOICE_MONO_16BIT; + else if (CommHdr.channels == 2 && CommHdr.bps == 8) + Format = VOICE_STEREO_8BIT; + else if (CommHdr.channels == 2 && CommHdr.bps == 16) + Format = VOICE_STEREO_16BIT; + + Decode(); +} + +void AifDecoder::CloseFile() +{ + if(file_fd) + delete file_fd; + + file_fd = NULL; +} + +int AifDecoder::Read(u8 * buffer, int buffer_size, int pos) +{ + if(!file_fd) + return -1; + + if(CurPos >= (int) DataSize) + return 0; + + file_fd->seek(DataOffset+CurPos, SEEK_SET); + + if(buffer_size > (int) DataSize-CurPos) + buffer_size = DataSize-CurPos; + + int read = file_fd->read(buffer, buffer_size); + if(read > 0) + { + CurPos += read; + } + + return read; +} diff --git a/source/SoundOperations/AifDecoder.hpp b/source/SoundOperations/AifDecoder.hpp new file mode 100644 index 0000000..2544b4b --- /dev/null +++ b/source/SoundOperations/AifDecoder.hpp @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef AIFDECODER_HPP_ +#define AIFDECODER_HPP_ + +#include "SoundDecoder.hpp" +#include "WavDecoder.hpp" + +class AifDecoder : public SoundDecoder +{ + public: + AifDecoder(const char * filepath); + AifDecoder(const u8 * snd, int len); + virtual ~AifDecoder(); + int GetFormat() { return Format; }; + int GetSampleRate() { return SampleRate; }; + int Read(u8 * buffer, int buffer_size, int pos); + protected: + void OpenFile(); + void CloseFile(); + u32 DataOffset; + u32 DataSize; + u32 SampleRate; + u8 Format; +}; + +#endif diff --git a/source/SoundOperations/BNSDecoder.cpp b/source/SoundOperations/BNSDecoder.cpp new file mode 100644 index 0000000..f6964f7 --- /dev/null +++ b/source/SoundOperations/BNSDecoder.cpp @@ -0,0 +1,365 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include "BNSDecoder.hpp" + +SoundBlock DecodefromBNS(const u8 *buffer, u32 size); + +BNSDecoder::BNSDecoder(const char * filepath) + : SoundDecoder(filepath) +{ + SoundType = SOUND_BNS; + memset(&SoundData, 0, sizeof(SoundBlock)); + + if(!file_fd) + return; + + OpenFile(); +} + +BNSDecoder::BNSDecoder(const u8 * snd, int len) + : SoundDecoder(snd, len) +{ + SoundType = SOUND_BNS; + memset(&SoundData, 0, sizeof(SoundBlock)); + + if(!file_fd) + return; + + OpenFile(); +} + +BNSDecoder::~BNSDecoder() +{ + ExitRequested = true; + while(Decoding) + usleep(100); + + if(SoundData.buffer != NULL) + free(SoundData.buffer); + + SoundData.buffer = NULL; +} + +void BNSDecoder::OpenFile() +{ + u8 * tempbuff = new (std::nothrow) u8[file_fd->size()]; + if(!tempbuff) + { + CloseFile(); + return; + } + + int done = 0; + + while(done < file_fd->size()) + { + int read = file_fd->read(tempbuff+done, file_fd->size()-done); + if(read > 0) + done += read; + else + { + CloseFile(); + return; + } + } + + SoundData = DecodefromBNS(tempbuff, done); + if(SoundData.buffer == NULL) + { + CloseFile(); + return; + } + + delete [] tempbuff; + tempbuff = NULL; + + Decode(); +} + +void BNSDecoder::CloseFile() +{ + if(file_fd) + delete file_fd; + + file_fd = NULL; +} + +int BNSDecoder::Read(u8 * buffer, int buffer_size, int pos) +{ + if(!SoundData.buffer) + return -1; + + if(SoundData.loopFlag) + { + int factor = SoundData.format == VOICE_STEREO_16BIT ? 4 : 2; + if(CurPos >= (int) SoundData.loopEnd*factor) + CurPos = SoundData.loopStart*factor; + + if(buffer_size > (int) SoundData.loopEnd*factor-CurPos) + buffer_size = SoundData.loopEnd*factor-CurPos; + } + else + { + if(CurPos >= (int) SoundData.size) + return 0; + + if(buffer_size > (int) SoundData.size-CurPos) + buffer_size = SoundData.size-CurPos; + } + + memcpy(buffer, SoundData.buffer+CurPos, buffer_size); + CurPos += buffer_size; + + return buffer_size; +} + +struct BNSHeader +{ + u32 fccBNS; + u32 magic; + u32 size; + u16 unk1; + u16 unk2; + u32 infoOffset; + u32 infoSize; + u32 dataOffset; + u32 dataSize; +} __attribute__((packed)); + +struct BNSInfo +{ + u32 fccINFO; + u32 size; + u8 codecNum; + u8 loopFlag; + u8 chanCount; + u8 zero; + u16 freq; + u8 pad1[2]; + u32 loopStart; + u32 loopEnd; + u32 offsetToChanStarts; + u8 pad2[4]; + u32 chan1StartOffset; + u32 chan2StartOffset; + u32 chan1Start; + u32 coeff1Offset; + u8 pad3[4]; + u32 chan2Start; + u32 coeff2Offset; + u8 pad4[4]; + s16 coefficients1[8][2]; + u16 chan1Gain; + u16 chan1PredictiveScale; + s16 chan1PrevSamples[2]; + u16 chan1LoopPredictiveScale; + s16 chan1LoopPrevSamples[2]; + u16 chan1LoopPadding; + s16 coefficients2[8][2]; + u16 chan2Gain; + u16 chan2PredictiveScale; + s16 chan2PrevSamples[2]; + u16 chan2LoopPredictiveScale; + s16 chan2LoopPrevSamples[2]; + u16 chan2LoopPadding; +} __attribute__((packed)); + +struct BNSData +{ + u32 fccDATA; + u32 size; + u8 data; +} __attribute__((packed)); + +struct ADPCMByte +{ + s8 sample1 : 4; + s8 sample2 : 4; +} __attribute__((packed)); + +struct BNSADPCMBlock +{ + u8 pad : 1; + u8 coeffIndex : 3; + u8 lshift : 4; + ADPCMByte samples[7]; +} __attribute__((packed)); + +struct BNSDecObj +{ + s16 prevSamples[2]; + s16 coeff[8][2]; +}; + +static void loadBNSInfo(BNSInfo &bnsInfo, const u8 *buffer) +{ + const u8 *ptr = buffer + 8; + bnsInfo = *(const BNSInfo *)buffer; + if (bnsInfo.offsetToChanStarts == 0x18 && bnsInfo.chan1StartOffset == 0x20 && bnsInfo.chan2StartOffset == 0x2C + && bnsInfo.coeff1Offset == 0x38 && bnsInfo.coeff2Offset == 0x68) + return; + bnsInfo.chan1StartOffset = *(const u32 *)(ptr + bnsInfo.offsetToChanStarts); + bnsInfo.chan1Start = *(const u32 *)(ptr + bnsInfo.chan1StartOffset); + bnsInfo.coeff1Offset = *(const u32 *)(ptr + bnsInfo.chan1StartOffset + 4); + if ((u8 *)bnsInfo.coefficients1 != ptr + bnsInfo.coeff1Offset) + memcpy(bnsInfo.coefficients1, ptr + bnsInfo.coeff1Offset, (u8 *)bnsInfo.coefficients2 - (u8 *)&bnsInfo.coefficients1); + if (bnsInfo.chanCount == 2) + { + bnsInfo.chan2StartOffset = *(const u32 *)(ptr + bnsInfo.offsetToChanStarts + 4); + bnsInfo.chan2Start = *(const u32 *)(ptr + bnsInfo.chan2StartOffset); + bnsInfo.coeff2Offset = *(const u32 *)(ptr + bnsInfo.chan2StartOffset + 4); + if ((u8 *)bnsInfo.coefficients2 != ptr + bnsInfo.coeff2Offset) + memcpy(bnsInfo.coefficients2, ptr + bnsInfo.coeff2Offset, (u8 *)bnsInfo.coefficients2 - (u8 *)&bnsInfo.coefficients1); + } +} + +static void decodeADPCMBlock(s16 *buffer, const BNSADPCMBlock &block, BNSDecObj &bnsDec) +{ + int h1 = bnsDec.prevSamples[0]; + int h2 = bnsDec.prevSamples[1]; + int c1 = bnsDec.coeff[block.coeffIndex][0]; + int c2 = bnsDec.coeff[block.coeffIndex][1]; + for (int i = 0; i < 14; ++i) + { + int nibSample = ((i & 1) == 0) ? block.samples[i / 2].sample1 : block.samples[i / 2].sample2; + int sampleDeltaHP = (nibSample << block.lshift) << 11; + int predictedSampleHP = c1 * h1 + c2 * h2; + int sampleHP = predictedSampleHP + sampleDeltaHP; + buffer[i] = std::min(std::max(-32768, (sampleHP + 1024) >> 11), 32767); + h2 = h1; + h1 = buffer[i]; + } + bnsDec.prevSamples[0] = h1; + bnsDec.prevSamples[1] = h2; +} + +static u8 * decodeBNS(u32 &size, const BNSInfo &bnsInfo, const BNSData &bnsData) +{ + static s16 smplBlock[14]; + BNSDecObj decObj; + int numBlocks = (bnsData.size - 8) / 8; + int numSamples = numBlocks * 14; + const BNSADPCMBlock *inputBuf = (const BNSADPCMBlock *)&bnsData.data; + u8 * buffer = (u8 *) malloc(numSamples * sizeof (s16)); + s16 *outputBuf; + + if (!buffer) + return buffer; + memcpy(decObj.coeff, bnsInfo.coefficients1, sizeof decObj.coeff); + memcpy(decObj.prevSamples, bnsInfo.chan1PrevSamples, sizeof decObj.prevSamples); + outputBuf = (s16 *)buffer; + if (bnsInfo.chanCount == 1) + for (int i = 0; i < numBlocks; ++i) + { + decodeADPCMBlock(smplBlock, inputBuf[i], decObj); + memcpy(outputBuf, smplBlock, sizeof smplBlock); + outputBuf += 14; + } + else + { + numBlocks /= 2; + for (int i = 0; i < numBlocks; ++i) + { + decodeADPCMBlock(smplBlock, inputBuf[i], decObj); + for (int j = 0; j < 14; ++j) + outputBuf[j * 2] = smplBlock[j]; + outputBuf += 2 * 14; + } + outputBuf = (s16 *)buffer + 1; + memcpy(decObj.coeff, bnsInfo.coefficients2, sizeof decObj.coeff); + memcpy(decObj.prevSamples, bnsInfo.chan2PrevSamples, sizeof decObj.prevSamples); + for (int i = 0; i < numBlocks; ++i) + { + decodeADPCMBlock(smplBlock, inputBuf[numBlocks + i], decObj); + for (int j = 0; j < 14; ++j) + outputBuf[j * 2] = smplBlock[j]; + outputBuf += 2 * 14; + } + } + size = numSamples * sizeof (s16); + return buffer; +} + +SoundBlock DecodefromBNS(const u8 *buffer, u32 size) +{ + SoundBlock OutBlock; + memset(&OutBlock, 0, sizeof(SoundBlock)); + + const BNSHeader &hdr = *(BNSHeader *)buffer; + if (size < sizeof hdr) + return OutBlock; + if (hdr.fccBNS != 'BNS ') + return OutBlock; + // Find info and data + BNSInfo infoChunk; + loadBNSInfo(infoChunk, buffer + hdr.infoOffset); + const BNSData &dataChunk = *(const BNSData *)(buffer + hdr.dataOffset); + // Check sizes + if (size < hdr.size || size < hdr.infoOffset + hdr.infoSize || size < hdr.dataOffset + hdr.dataSize + || hdr.infoSize < 0x60 || hdr.dataSize < sizeof dataChunk + || infoChunk.size != hdr.infoSize || dataChunk.size > hdr.dataSize) + return OutBlock; + // Check format + if (infoChunk.codecNum != 0) // Only codec i've found : 0 = ADPCM. Maybe there's also 1 and 2 for PCM 8 or 16 bits ? + return OutBlock; + u8 format = (u8)-1; + if (infoChunk.chanCount == 1 && infoChunk.codecNum == 0) + format = VOICE_MONO_16BIT; + else if (infoChunk.chanCount == 2 && infoChunk.codecNum == 0) + format = VOICE_STEREO_16BIT; + if (format == (u8)-1) + return OutBlock; + u32 freq = (u32) infoChunk.freq; + u32 length = 0; + // Copy data + if (infoChunk.codecNum == 0) + { + OutBlock.buffer = decodeBNS(length, infoChunk, dataChunk); + if (!OutBlock.buffer) + return OutBlock; + } + else + { + OutBlock.buffer = (u8*) malloc(dataChunk.size); + if (!OutBlock.buffer) + return OutBlock; + memcpy(OutBlock.buffer, &dataChunk.data, dataChunk.size); + length = dataChunk.size; + } + + OutBlock.frequency = freq; + OutBlock.format = format; + OutBlock.size = length; + OutBlock.loopStart = infoChunk.loopStart; + OutBlock.loopEnd = infoChunk.loopEnd; + OutBlock.loopFlag = infoChunk.loopFlag; + + return OutBlock; +} diff --git a/source/SoundOperations/BNSDecoder.hpp b/source/SoundOperations/BNSDecoder.hpp new file mode 100644 index 0000000..1248433 --- /dev/null +++ b/source/SoundOperations/BNSDecoder.hpp @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef BNSDECODER_HPP_ +#define BNSDECODER_HPP_ + +#include "SoundDecoder.hpp" + +typedef struct _SoundBlock +{ + u8 * buffer; + u32 size; + u8 format; + u32 frequency; + u32 loopStart; + u32 loopEnd; + u8 loopFlag; +} SoundBlock; + +class BNSDecoder : public SoundDecoder +{ + public: + BNSDecoder(const char * filepath); + BNSDecoder(const u8 * snd, int len); + virtual ~BNSDecoder(); + int GetFormat() { return SoundData.format; }; + int GetSampleRate() { return SoundData.frequency; }; + int Read(u8 * buffer, int buffer_size, int pos); + protected: + void OpenFile(); + void CloseFile(); + SoundBlock SoundData; +}; + +#endif diff --git a/source/SoundOperations/BufferCircle.cpp b/source/SoundOperations/BufferCircle.cpp new file mode 100644 index 0000000..71945df --- /dev/null +++ b/source/SoundOperations/BufferCircle.cpp @@ -0,0 +1,144 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include "BufferCircle.hpp" + +#define ALIGN32(x) (((x) + 31) & ~31) + +BufferCircle::BufferCircle() +{ + which = 0; + BufferBlockSize = 0; +} + +BufferCircle::~BufferCircle() +{ + FreeBuffer(); + SoundBuffer.clear(); + BufferSize.clear(); + BufferReady.clear(); +} + +void BufferCircle::SetBufferBlockSize(int size) +{ + if(size < 0) + return; + + BufferBlockSize = size; + + for(int i = 0; i < Size(); i++) + { + if(SoundBuffer[i] != NULL) + free(SoundBuffer[i]); + + SoundBuffer[i] = (u8 *) memalign(32, ALIGN32(BufferBlockSize)); + BufferSize[i] = 0; + BufferReady[i] = false; + } +} + +void BufferCircle::Resize(int size) +{ + while(size < Size()) + RemoveBuffer(Size()-1); + + int oldSize = Size(); + + SoundBuffer.resize(size); + BufferSize.resize(size); + BufferReady.resize(size); + + for(int i = oldSize; i < Size(); i++) + { + if(BufferBlockSize > 0) + SoundBuffer[i] = (u8 *) memalign(32, ALIGN32(BufferBlockSize)); + else + SoundBuffer[i] = NULL; + BufferSize[i] = 0; + BufferReady[i] = false; + } +} + +void BufferCircle::RemoveBuffer(int pos) +{ + if(!Valid(pos)) + return; + + if(SoundBuffer[pos] != NULL) + free(SoundBuffer[pos]); + + SoundBuffer.erase(SoundBuffer.begin()+pos); + BufferSize.erase(BufferSize.begin()+pos); + BufferReady.erase(BufferReady.begin()+pos); +} + +void BufferCircle::ClearBuffer() +{ + for(int i = 0; i < Size(); i++) + { + BufferSize[i] = 0; + BufferReady[i] = false; + } + which = 0; +} + +void BufferCircle::FreeBuffer() +{ + for(int i = 0; i < Size(); i++) + { + if(SoundBuffer[i] != NULL) + free(SoundBuffer[i]); + + SoundBuffer[i] = NULL; + BufferSize[i] = 0; + BufferReady[i] = false; + } +} + +void BufferCircle::LoadNext() +{ + int pos = (which+Size()-1) % Size(); + BufferReady[pos] = false; + BufferSize[pos] = 0; + + which = (which+1) % Size(); +} + +void BufferCircle::SetBufferReady(int pos, bool state) +{ + if(!Valid(pos)) + return; + + BufferReady[pos] = state; +} + +void BufferCircle::SetBufferSize(int pos, int size) +{ + if(!Valid(pos)) + return; + + BufferSize[pos] = size; +} diff --git a/source/SoundOperations/BufferCircle.hpp b/source/SoundOperations/BufferCircle.hpp new file mode 100644 index 0000000..b1041e8 --- /dev/null +++ b/source/SoundOperations/BufferCircle.hpp @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef BUFFER_CIRCLE_HPP_ +#define BUFFER_CIRCLE_HPP_ + +#include +#include + +class BufferCircle +{ + public: + //!> Constructor + BufferCircle(); + //!> Destructor + ~BufferCircle(); + //!> Set circle size + void Resize(int size); + //!> Get the circle size + int Size() { return SoundBuffer.size(); }; + //!> Set/resize the buffer size + void SetBufferBlockSize(int size); + //!> Remove a buffer + void RemoveBuffer(int pos); + //!> Set all buffers clear + void ClearBuffer(); + //!> Free all buffers + void FreeBuffer(); + //!> Switch to next buffer + void LoadNext(); + //!> Get the current buffer + u8 * GetBuffer() { if(!Valid(which)) return 0; return SoundBuffer[which]; }; + //!> Get a buffer at a position + u8 * GetBuffer(int pos) { if(!Valid(pos)) return NULL; else return SoundBuffer[pos]; }; + //!> Get next buffer + u8 * GetNextBuffer() { if(Size() <= 0) return 0; else return SoundBuffer[(which+1) % Size()]; }; + //!> Get previous buffer + u8 * GetLastBuffer() { if(Size() <= 0) return 0; else return SoundBuffer[(which+Size()-1) % Size()]; }; + //!> Get current buffer size + u32 GetBufferSize() { if(!Valid(which)) return 0; else return BufferSize[which]; }; + //!> Get buffer size at position + u32 GetBufferSize(int pos) { if(!Valid(pos)) return 0; else return BufferSize[pos]; }; + //!> Get previous buffer size + u32 GetLastBufferSize() { if(Size() <= 0) return 0; else return BufferSize[(which+Size()-1) % Size()]; }; + //!> Is current buffer ready + bool IsBufferReady() { if(!Valid(which)) return false; else return BufferReady[which]; }; + //!> Is a buffer at a position ready + bool IsBufferReady(int pos) { if(!Valid(pos)) return false; else return BufferReady[pos]; }; + //!> Is next buffer ready + bool IsNextBufferReady() { if(Size() <= 0) return false; else return BufferReady[(which+1) % Size()]; }; + //!> Is last buffer ready + bool IsLastBufferReady() { if(Size() <= 0) return false; else return BufferReady[(which+Size()-1) % Size()]; }; + //!> Set a buffer at a position to a ready state + void SetBufferReady(int pos, bool st); + //!> Set the buffersize at a position + void SetBufferSize(int pos, int size); + //!> Get the current position in the circle + u16 Which() { return which; }; + protected: + //!> Check if the position is a valid position in the vector + bool Valid(int pos) { return !(pos < 0 || pos >= Size()); }; + + u16 which; + u32 BufferBlockSize; + std::vector SoundBuffer; + std::vector BufferSize; + std::vector BufferReady; +}; + +#endif diff --git a/source/SoundOperations/Mp3Decoder.cpp b/source/SoundOperations/Mp3Decoder.cpp new file mode 100644 index 0000000..e29b912 --- /dev/null +++ b/source/SoundOperations/Mp3Decoder.cpp @@ -0,0 +1,218 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include "Mp3Decoder.hpp" + +Mp3Decoder::Mp3Decoder(const char * filepath) + : SoundDecoder(filepath) +{ + SoundType = SOUND_MP3; + ReadBuffer = NULL; + mad_timer_reset(&Timer); + mad_stream_init(&Stream); + mad_frame_init(&Frame); + mad_synth_init(&Synth); + + if(!file_fd) + return; + + OpenFile(); +} + +Mp3Decoder::Mp3Decoder(const u8 * snd, int len) + : SoundDecoder(snd, len) +{ + SoundType = SOUND_MP3; + ReadBuffer = NULL; + mad_timer_reset(&Timer); + mad_stream_init(&Stream); + mad_frame_init(&Frame); + mad_synth_init(&Synth); + + if(!file_fd) + return; + + OpenFile(); +} + +Mp3Decoder::~Mp3Decoder() +{ + ExitRequested = true; + while(Decoding) + usleep(100); + + mad_synth_finish(&Synth); + mad_frame_finish(&Frame); + mad_stream_finish(&Stream); + + if(ReadBuffer) + free(ReadBuffer); + ReadBuffer = NULL; +} + +void Mp3Decoder::OpenFile() +{ + GuardPtr = NULL; + ReadBuffer = (u8 *) memalign(32, SoundBlockSize*SoundBlocks); + if(!ReadBuffer) + { + if(file_fd) + delete file_fd; + file_fd = NULL; + return; + } + + u8 dummybuff[4096]; + int ret = Read(dummybuff, 4096, 0); + if(ret <= 0) + { + if(file_fd) + delete file_fd; + file_fd = NULL; + return; + } + + SampleRate = (u32) Frame.header.samplerate; + Format = ((MAD_NCHANNELS(&Frame.header) == 2) ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT); + Rewind(); + Decode(); +} + +int Mp3Decoder::Rewind() +{ + mad_synth_finish(&Synth); + mad_frame_finish(&Frame); + mad_stream_finish(&Stream); + mad_timer_reset(&Timer); + mad_stream_init(&Stream); + mad_frame_init(&Frame); + mad_synth_init(&Synth); + SynthPos = 0; + GuardPtr = NULL; + + if(!file_fd) + return -1; + + return SoundDecoder::Rewind(); +} + +static inline s16 FixedToShort(mad_fixed_t Fixed) +{ + /* Clipping */ + if(Fixed>=MAD_F_ONE) + return(SHRT_MAX); + if(Fixed<=-MAD_F_ONE) + return(-SHRT_MAX); + + Fixed=Fixed>>(MAD_F_FRACBITS-15); + return((s16)Fixed); +} + +int Mp3Decoder::Read(u8 * buffer, int buffer_size, int pos) +{ + if(!file_fd) + return -1; + + if(Format == VOICE_STEREO_16BIT) + buffer_size &= ~0x0003; + else + buffer_size &= ~0x0001; + + u8 * write_pos = buffer; + u8 * write_end = buffer+buffer_size; + + while(1) + { + while(SynthPos < Synth.pcm.length) + { + if(write_pos >= write_end) + return write_pos-buffer; + + *((s16 *) write_pos) = FixedToShort(Synth.pcm.samples[0][SynthPos]); + write_pos += 2; + + if(MAD_NCHANNELS(&Frame.header) == 2) + { + *((s16 *) write_pos) = FixedToShort(Synth.pcm.samples[1][SynthPos]); + write_pos += 2; + } + SynthPos++; + } + + if(Stream.buffer == NULL || Stream.error == MAD_ERROR_BUFLEN) + { + u8 * ReadStart = ReadBuffer; + int ReadSize = SoundBlockSize*SoundBlocks; + int Remaining = 0; + + if(Stream.next_frame != NULL) + { + Remaining = Stream.bufend - Stream.next_frame; + memmove(ReadBuffer, Stream.next_frame, Remaining); + ReadStart += Remaining; + ReadSize -= Remaining; + } + + ReadSize = file_fd->read(ReadStart, ReadSize); + if(ReadSize <= 0) + { + GuardPtr = ReadStart; + memset(GuardPtr, 0, MAD_BUFFER_GUARD); + ReadSize = MAD_BUFFER_GUARD; + } + + CurPos += ReadSize; + mad_stream_buffer(&Stream, ReadBuffer, Remaining+ReadSize); + } + + if(mad_frame_decode(&Frame,&Stream)) + { + if(MAD_RECOVERABLE(Stream.error)) + { + if(Stream.error != MAD_ERROR_LOSTSYNC || !GuardPtr) + continue; + } + else + { + if(Stream.error != MAD_ERROR_BUFLEN) + return -1; + else if(Stream.error == MAD_ERROR_BUFLEN && GuardPtr) + return -1; + } + } + + mad_timer_add(&Timer,Frame.header.duration); + mad_synth_frame(&Synth,&Frame); + SynthPos = 0; + } + + return 0; +} diff --git a/source/SoundOperations/Mp3Decoder.hpp b/source/SoundOperations/Mp3Decoder.hpp new file mode 100644 index 0000000..c6ffd88 --- /dev/null +++ b/source/SoundOperations/Mp3Decoder.hpp @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include + +#include "SoundDecoder.hpp" + +class Mp3Decoder : public SoundDecoder +{ + public: + Mp3Decoder(const char * filepath); + Mp3Decoder(const u8 * sound, int len); + virtual ~Mp3Decoder(); + int GetFormat() { return Format; }; + int GetSampleRate() { return SampleRate; }; + int Rewind(); + int Read(u8 * buffer, int buffer_size, int pos); + protected: + void OpenFile(); + struct mad_stream Stream; + struct mad_frame Frame; + struct mad_synth Synth; + mad_timer_t Timer; + u8 * GuardPtr; + u8 * ReadBuffer; + u8 Format; + u32 SampleRate; + u32 SynthPos; +}; diff --git a/source/SoundOperations/OggDecoder.cpp b/source/SoundOperations/OggDecoder.cpp new file mode 100644 index 0000000..09228b1 --- /dev/null +++ b/source/SoundOperations/OggDecoder.cpp @@ -0,0 +1,144 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include "OggDecoder.hpp" + +extern "C" int ogg_read(void * punt, int bytes, int blocks, int *f) +{ + return ((CFile *) f)->read((u8 *) punt, bytes*blocks); +} + +extern "C" int ogg_seek(int *f, ogg_int64_t offset, int mode) +{ + return ((CFile *) f)->seek((u64) offset, mode); +} + +extern "C" int ogg_close(int *f) +{ + ((CFile *) f)->close(); + return 0; +} + +extern "C" long ogg_tell(int *f) +{ + return (long) ((CFile *) f)->tell(); +} + +static ov_callbacks callbacks = { + (size_t (*)(void *, size_t, size_t, void *)) ogg_read, + (int (*)(void *, ogg_int64_t, int)) ogg_seek, + (int (*)(void *)) ogg_close, + (long (*)(void *)) ogg_tell +}; + +OggDecoder::OggDecoder(const char * filepath) + : SoundDecoder(filepath) +{ + SoundType = SOUND_OGG; + + if(!file_fd) + return; + + OpenFile(); +} + +OggDecoder::OggDecoder(const u8 * snd, int len) + : SoundDecoder(snd, len) +{ + SoundType = SOUND_OGG; + + if(!file_fd) + return; + + OpenFile(); +} + +OggDecoder::~OggDecoder() +{ + ExitRequested = true; + while(Decoding) + usleep(100); + + if(file_fd) + ov_clear(&ogg_file); +} + +void OggDecoder::OpenFile() +{ + if (ov_open_callbacks(file_fd, &ogg_file, NULL, 0, callbacks) < 0) + { + delete file_fd; + file_fd = NULL; + return; + } + + ogg_info = ov_info(&ogg_file, -1); + Decode(); +} + +int OggDecoder::GetFormat() +{ + if(!file_fd) + return VOICE_STEREO_16BIT; + + return ((ogg_info->channels == 2) ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT); +} + +int OggDecoder::GetSampleRate() +{ + if(!file_fd) + return 0; + + return (int) ogg_info->rate; +} + +int OggDecoder::Rewind() +{ + if(!file_fd) + return -1; + + int ret = ov_time_seek(&ogg_file, 0); + CurPos = 0; + EndOfFile = false; + + return ret; +} + +int OggDecoder::Read(u8 * buffer, int buffer_size, int pos) +{ + if(!file_fd) + return -1; + + int bitstream = 0; + + int read = ov_read(&ogg_file, (char *) buffer, buffer_size, &bitstream); + + if(read > 0) + CurPos += read; + + return read; +} diff --git a/source/SoundOperations/OggDecoder.hpp b/source/SoundOperations/OggDecoder.hpp new file mode 100644 index 0000000..7624708 --- /dev/null +++ b/source/SoundOperations/OggDecoder.hpp @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include + +#include "SoundDecoder.hpp" + +class OggDecoder : public SoundDecoder +{ + public: + OggDecoder(const char * filepath); + OggDecoder(const u8 * snd, int len); + virtual ~OggDecoder(); + int GetFormat(); + int GetSampleRate(); + int Rewind(); + int Read(u8 * buffer, int buffer_size, int pos); + protected: + void OpenFile(); + OggVorbis_File ogg_file; + vorbis_info *ogg_info; +}; diff --git a/source/SoundOperations/SoundDecoder.cpp b/source/SoundOperations/SoundDecoder.cpp new file mode 100644 index 0000000..aacf830 --- /dev/null +++ b/source/SoundOperations/SoundDecoder.cpp @@ -0,0 +1,156 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * 3Band resampling thanks to libmad + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include "SoundDecoder.hpp" +#include "main.h" + +SoundDecoder::SoundDecoder() +{ + file_fd = NULL; + Init(); +} + +SoundDecoder::SoundDecoder(const char * filepath) +{ + file_fd = new CFile(filepath, "rb"); + Init(); +} + +SoundDecoder::SoundDecoder(const u8 * buffer, int size) +{ + file_fd = new CFile(buffer, size); + Init(); +} + +SoundDecoder::~SoundDecoder() +{ + ExitRequested = true; + while(Decoding) + usleep(100); + + if(file_fd) + delete file_fd; + file_fd = NULL; +} + +void SoundDecoder::Init() +{ + SoundType = SOUND_RAW; + SoundBlocks = 8; + SoundBlockSize = 8192; + CurPos = 0; + Loop = false; + EndOfFile = false; + Decoding = false; + ExitRequested = false; + SoundBuffer.SetBufferBlockSize(SoundBlockSize); + SoundBuffer.Resize(SoundBlocks); +} + +int SoundDecoder::Rewind() +{ + CurPos = 0; + EndOfFile = false; + file_fd->rewind(); + + return 0; +} + +int SoundDecoder::Read(u8 * buffer, int buffer_size, int pos) +{ + int ret = file_fd->read(buffer, buffer_size); + CurPos += ret; + + return ret; +} + +void SoundDecoder::Decode() +{ + if(!file_fd || ExitRequested || EndOfFile) + return; + + u16 newWhich = SoundBuffer.Which(); + u16 i = 0; + for (i = 0; i < SoundBuffer.Size()-2; i++) + { + if(!SoundBuffer.IsBufferReady(newWhich)) + break; + + newWhich = (newWhich+1) % SoundBuffer.Size(); + } + + if(i == SoundBuffer.Size()-2) + return; + + Decoding = true; + + int done = 0; + u8 * write_buf = SoundBuffer.GetBuffer(newWhich); + if(!write_buf) + { + ExitRequested = true; + Decoding = false; + return; + } + + while(done < SoundBlockSize) + { + int ret = Read(&write_buf[done], SoundBlockSize-done, Tell()); + + if(ret <= 0) + { + if(Loop) + { + Rewind(); + continue; + } + else + { + EndOfFile = true; + break; + } + } + + done += ret; + } + + if(done > 0) + { + SoundBuffer.SetBufferSize(newWhich, done); + SoundBuffer.SetBufferReady(newWhich, true); + } + + if(!SoundBuffer.IsBufferReady((newWhich+1) % SoundBuffer.Size())) + Decode(); + + Decoding = false; +} + diff --git a/source/SoundOperations/SoundDecoder.hpp b/source/SoundOperations/SoundDecoder.hpp new file mode 100644 index 0000000..9d05a9c --- /dev/null +++ b/source/SoundOperations/SoundDecoder.hpp @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef SOUND_DECODER_HPP +#define SOUND_DECODER_HPP + +#include +#include +#include +#include "utils/timer.h" +#include "FileOperations/File.hpp" +#include "BufferCircle.hpp" + +enum +{ + SOUND_RAW = 0, + SOUND_MP3, + SOUND_OGG, + SOUND_WAV, + SOUND_BNS, + SOUND_AIF +}; + +class SoundDecoder +{ + public: + SoundDecoder(); + SoundDecoder(const char * filepath); + SoundDecoder(const u8 * buffer, int size); + virtual ~SoundDecoder(); + virtual int Read(u8 * buffer, int buffer_size, int pos); + virtual int Tell() { return CurPos; }; + virtual int Seek(int pos) { CurPos = pos; return file_fd->seek(CurPos, SEEK_SET); }; + virtual int Rewind(); + virtual int GetFormat() { return VOICE_STEREO_16BIT; }; + virtual int GetSampleRate() { return 48000; }; + virtual void Decode(); + virtual u32 GetBufferSize() { return SoundBuffer.GetBufferSize(); }; + virtual u8 * GetBuffer() { return SoundBuffer.GetBuffer(); }; + virtual u8 * GetNextBuffer() { return SoundBuffer.GetNextBuffer(); }; + virtual u8 * GetLastBuffer() { return SoundBuffer.GetLastBuffer(); }; + virtual void LoadNext() { SoundBuffer.LoadNext(); }; + virtual bool IsBufferReady() { return SoundBuffer.IsBufferReady(); }; + virtual bool IsNextBufferReady() { return SoundBuffer.IsNextBufferReady(); }; + virtual bool IsLastBufferReady() { return SoundBuffer.IsLastBufferReady(); }; + virtual bool IsEOF() { return EndOfFile; }; + virtual void SetLoop(bool l) { Loop = l; }; + virtual u8 GetSoundType() { return SoundType; }; + virtual void ClearBuffer() { SoundBuffer.ClearBuffer(); }; + virtual bool IsStereo() { return (GetFormat() == VOICE_STEREO_16BIT || GetFormat() == VOICE_STEREO_8BIT); }; + virtual bool Is16Bit() { return (GetFormat() == VOICE_STEREO_16BIT || GetFormat() == VOICE_MONO_16BIT); }; + protected: + void Init(); + + CFile * file_fd; + BufferCircle SoundBuffer; + u8 SoundType; + u16 SoundBlocks; + int SoundBlockSize; + int CurPos; + bool Loop; + bool EndOfFile; + bool Decoding; + bool ExitRequested; +}; + +#endif diff --git a/source/SoundOperations/SoundHandler.cpp b/source/SoundOperations/SoundHandler.cpp new file mode 100644 index 0000000..305e64b --- /dev/null +++ b/source/SoundOperations/SoundHandler.cpp @@ -0,0 +1,264 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include "SoundHandler.hpp" +#include "Mp3Decoder.hpp" +#include "OggDecoder.hpp" +#include "WavDecoder.hpp" +#include "AifDecoder.hpp" +#include "BNSDecoder.hpp" + +SoundHandler * SoundHandler::instance = NULL; + +SoundHandler::SoundHandler() +{ + Decoding = false; + ExitRequested = false; + for(u32 i = 0; i < MAX_DECODERS; ++i) + DecoderList[i] = NULL; + + ThreadStack = (u8 *) memalign(32, 32768); + if(!ThreadStack) + return; + + LWP_CreateThread(&SoundThread, UpdateThread, this, ThreadStack, 32768, 80); +} + +SoundHandler::~SoundHandler() +{ + ExitRequested = true; + ThreadSignal(); + LWP_JoinThread(SoundThread, NULL); + SoundThread = LWP_THREAD_NULL; + if(ThreadStack) + free(ThreadStack); + + ClearDecoderList(); +} + +SoundHandler * SoundHandler::Instance() +{ + if (instance == NULL) + { + instance = new SoundHandler(); + } + return instance; +} + +void SoundHandler::DestroyInstance() +{ + if(instance) + { + delete instance; + } + instance = NULL; +} + +void SoundHandler::AddDecoder(int voice, const char * filepath) +{ + if(voice < 0 || voice >= MAX_DECODERS) + return; + + if(DecoderList[voice] != NULL) + RemoveDecoder(voice); + + DecoderList[voice] = GetSoundDecoder(filepath); +} + +void SoundHandler::AddDecoder(int voice, const u8 * snd, int len) +{ + if(voice < 0 || voice >= MAX_DECODERS) + return; + + if(DecoderList[voice] != NULL) + RemoveDecoder(voice); + + DecoderList[voice] = GetSoundDecoder(snd, len); +} + +void SoundHandler::RemoveDecoder(int voice) +{ + if(voice < 0 || voice >= MAX_DECODERS) + return; + + if(DecoderList[voice] != NULL) + delete DecoderList[voice]; + + DecoderList[voice] = NULL; +} + +void SoundHandler::ClearDecoderList() +{ + for(u32 i = 0; i < MAX_DECODERS; ++i) + RemoveDecoder(i); +} + +static inline bool CheckMP3Signature(const u8 * buffer) +{ + const char MP3_Magic[][3] = + { + {'I', 'D', '3'}, //'ID3' + {0xff, 0xfe}, //'MPEG ADTS, layer III, v1.0 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xff}, //'MPEG ADTS, layer III, v1.0', 'mp3', 'audio/mpeg'), + {0xff, 0xfa}, //'MPEG ADTS, layer III, v1.0 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xfb}, //'MPEG ADTS, layer III, v1.0', 'mp3', 'audio/mpeg'), + {0xff, 0xf2}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xf3}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'), + {0xff, 0xf4}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xf5}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'), + {0xff, 0xf6}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xf7}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'), + {0xff, 0xe2}, //'MPEG ADTS, layer III, v2.5 [protected]', 'mp3', 'audio/mpeg'), + {0xff, 0xe3}, //'MPEG ADTS, layer III, v2.5', 'mp3', 'audio/mpeg'), + }; + + if(buffer[0] == MP3_Magic[0][0] && buffer[1] == MP3_Magic[0][1] && + buffer[2] == MP3_Magic[0][2]) + { + return true; + } + + for(int i = 1; i < 13; i++) + { + if(buffer[0] == MP3_Magic[i][0] && buffer[1] == MP3_Magic[i][1]) + return true; + } + + return false; +} + +SoundDecoder * SoundHandler::GetSoundDecoder(const char * filepath) +{ + u32 magic; + CFile f(filepath, "rb"); + if(f.size() == 0) + return NULL; + + do + { + f.read((u8 *) &magic, 1); + } + while(((u8 *) &magic)[0] == 0 && f.tell() < f.size()); + + if(f.tell() == f.size()) + return NULL; + + f.seek(f.tell()-1, SEEK_SET); + f.read((u8 *) &magic, 4); + f.close(); + + if(magic == 'OggS') + { + return new OggDecoder(filepath); + } + else if(magic == 'RIFF') + { + return new WavDecoder(filepath); + } + else if(magic == 'BNS ') + { + return new BNSDecoder(filepath); + } + else if(magic == 'FORM') + { + return new AifDecoder(filepath); + } + else if(CheckMP3Signature((u8 *) &magic) == true) + { + return new Mp3Decoder(filepath); + } + + return new SoundDecoder(filepath); +} + +SoundDecoder * SoundHandler::GetSoundDecoder(const u8 * sound, int length) +{ + const u8 * check = sound; + int counter = 0; + + while(check[0] == 0 && counter < length) + { + check++; + counter++; + } + + if(counter >= length) + return NULL; + + u32 * magic = (u32 *) check; + + if(magic[0] == 'OggS') + { + return new OggDecoder(sound, length); + } + else if(magic[0] == 'RIFF') + { + return new WavDecoder(sound, length); + } + else if(magic[0] == 'BNS ') + { + return new BNSDecoder(sound, length); + } + else if(magic[0] == 'FORM') + { + return new AifDecoder(sound, length); + } + else if(CheckMP3Signature(check) == true) + { + return new Mp3Decoder(sound, length); + } + + return new SoundDecoder(sound, length); +} + +void * SoundHandler::UpdateThread(void *arg) +{ + ((SoundHandler *) arg)->InternalSoundUpdates(); + return NULL; +} + +void SoundHandler::InternalSoundUpdates() +{ + u16 i = 0; + LWP_InitQueue(&ThreadQueue); + while (!ExitRequested) + { + LWP_ThreadSleep(ThreadQueue); + + for(i = 0; i < MAX_DECODERS; ++i) + { + if(DecoderList[i] == NULL) + continue; + + Decoding = true; + DecoderList[i]->Decode(); + } + Decoding = false; + } + LWP_CloseQueue(ThreadQueue); + ThreadQueue = LWP_TQUEUE_NULL; +} diff --git a/source/SoundOperations/SoundHandler.hpp b/source/SoundOperations/SoundHandler.hpp new file mode 100644 index 0000000..40239b5 --- /dev/null +++ b/source/SoundOperations/SoundHandler.hpp @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef SOUNDHANDLER_H_ +#define SOUNDHANDLER_H_ + +#include +#include +#include "SoundDecoder.hpp" + +#define MAX_DECODERS 16 + +class SoundHandler +{ + public: + static SoundHandler * Instance(); + static void DestroyInstance(); + + void AddDecoder(int voice, const char * filepath); + void AddDecoder(int voice, const u8 * snd, int len); + void RemoveDecoder(int voice); + void DestroyDecoder(SoundDecoder * decoder); + + SoundDecoder * Decoder(int i) { return ((i < 0 || i >= MAX_DECODERS) ? NULL : DecoderList[i]); }; + void ThreadSignal() { LWP_ThreadSignal(ThreadQueue); }; + bool IsDecoding() { return Decoding; }; + protected: + SoundHandler(); + ~SoundHandler(); + static void * UpdateThread(void *arg); + void InternalSoundUpdates(); + void ClearDecoderList(); + SoundDecoder * GetSoundDecoder(const char * filepath); + SoundDecoder * GetSoundDecoder(const u8 * sound, int length); + + static SoundHandler * instance; + u8 * ThreadStack; + lwp_t SoundThread; + lwpq_t ThreadQueue; + bool Decoding; + bool ExitRequested; + + SoundDecoder * DecoderList[MAX_DECODERS]; +}; + +#endif diff --git a/source/SoundOperations/WavDecoder.cpp b/source/SoundOperations/WavDecoder.cpp new file mode 100644 index 0000000..7d1f55e --- /dev/null +++ b/source/SoundOperations/WavDecoder.cpp @@ -0,0 +1,155 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include "WavDecoder.hpp" +#include "utils/uncompress.h" + +WavDecoder::WavDecoder(const char * filepath) + : SoundDecoder(filepath) +{ + SoundType = SOUND_WAV; + SampleRate = 48000; + Format = VOICE_STEREO_16BIT; + + if(!file_fd) + return; + + OpenFile(); +} + +WavDecoder::WavDecoder(const u8 * snd, int len) + : SoundDecoder(snd, len) +{ + SoundType = SOUND_WAV; + SampleRate = 48000; + Format = VOICE_STEREO_16BIT; + + if(!file_fd) + return; + + OpenFile(); +} + +WavDecoder::~WavDecoder() +{ +} + +void WavDecoder::OpenFile() +{ + SWaveHdr Header; + SWaveFmtChunk FmtChunk; + memset(&Header, 0, sizeof(SWaveHdr)); + memset(&FmtChunk, 0, sizeof(SWaveFmtChunk)); + + file_fd->read((u8 *) &Header, sizeof(SWaveHdr)); + file_fd->read((u8 *) &FmtChunk, sizeof(SWaveFmtChunk)); + + if (Header.magicRIFF != 'RIFF') + { + CloseFile(); + return; + } + else if(Header.magicWAVE != 'WAVE') + { + CloseFile(); + return; + } + else if(FmtChunk.magicFMT != 'fmt ') + { + CloseFile(); + return; + } + + DataOffset = sizeof(SWaveHdr)+le32(FmtChunk.size)+8; + file_fd->seek(DataOffset, SEEK_SET); + SWaveChunk DataChunk; + file_fd->read((u8 *) &DataChunk, sizeof(SWaveChunk)); + + while(DataChunk.magicDATA != 'data') + { + DataOffset += 8+le32(DataChunk.size); + file_fd->seek(DataOffset, SEEK_SET); + int ret = file_fd->read((u8 *) &DataChunk, sizeof(SWaveChunk)); + if(ret <= 0) + { + CloseFile(); + return; + } + } + + DataOffset += 8; + DataSize = le32(DataChunk.size); + Is16Bit = (le16(FmtChunk.bps) == 16); + SampleRate = le32(FmtChunk.freq); + + if (le16(FmtChunk.channels) == 1 && le16(FmtChunk.bps) == 8 && le16(FmtChunk.alignment) <= 1) + Format = VOICE_MONO_8BIT; + else if (le16(FmtChunk.channels) == 1 && le16(FmtChunk.bps) == 16 && le16(FmtChunk.alignment) <= 2) + Format = VOICE_MONO_16BIT; + else if (le16(FmtChunk.channels) == 2 && le16(FmtChunk.bps) == 8 && le16(FmtChunk.alignment) <= 2) + Format = VOICE_STEREO_8BIT; + else if (le16(FmtChunk.channels) == 2 && le16(FmtChunk.bps) == 16 && le16(FmtChunk.alignment) <= 4) + Format = VOICE_STEREO_16BIT; + + Decode(); +} + +void WavDecoder::CloseFile() +{ + if(file_fd) + delete file_fd; + + file_fd = NULL; +} + +int WavDecoder::Read(u8 * buffer, int buffer_size, int pos) +{ + if(!file_fd) + return -1; + + if(CurPos >= (int) DataSize) + return 0; + + file_fd->seek(DataOffset+CurPos, SEEK_SET); + + if(buffer_size > (int) DataSize-CurPos) + buffer_size = DataSize-CurPos; + + int read = file_fd->read(buffer, buffer_size); + if(read > 0) + { + if (Is16Bit) + { + read &= ~0x0001; + + for (u32 i = 0; i < (u32) (read / sizeof (u16)); ++i) + ((u16 *) buffer)[i] = le16(((u16 *) buffer)[i]); + } + CurPos += read; + } + + return read; +} diff --git a/source/SoundOperations/WavDecoder.hpp b/source/SoundOperations/WavDecoder.hpp new file mode 100644 index 0000000..ac18ad0 --- /dev/null +++ b/source/SoundOperations/WavDecoder.hpp @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef WAVDECODER_HPP_ +#define WAVDECODER_HPP_ + +#include "SoundDecoder.hpp" + +typedef struct +{ + u32 magicRIFF; + u32 size; + u32 magicWAVE; +} SWaveHdr; + +typedef struct +{ + u32 magicFMT; + u32 size; + u16 format; + u16 channels; + u32 freq; + u32 avgBps; + u16 alignment; + u16 bps; +} SWaveFmtChunk; + +typedef struct +{ + u32 magicDATA; + u32 size; +} SWaveChunk; + +class WavDecoder : public SoundDecoder +{ + public: + WavDecoder(const char * filepath); + WavDecoder(const u8 * snd, int len); + virtual ~WavDecoder(); + int GetFormat() { return Format; }; + int GetSampleRate() { return SampleRate; }; + int Read(u8 * buffer, int buffer_size, int pos); + protected: + void OpenFile(); + void CloseFile(); + u32 DataOffset; + u32 DataSize; + u32 SampleRate; + u8 Format; + bool Is16Bit; +}; + +#endif diff --git a/source/SoundOperations/gui_bgm.cpp b/source/SoundOperations/gui_bgm.cpp new file mode 100644 index 0000000..b315dc9 --- /dev/null +++ b/source/SoundOperations/gui_bgm.cpp @@ -0,0 +1,218 @@ +/**************************************************************************** + * SettingsPrompts + * USB Loader GX 2009 + * + * Backgroundmusic + ***************************************************************************/ +#include +#include "themes/CTheme.h" +#include "gui_bgm.h" +#include "menu.h" + +GuiBGM::GuiBGM(const u8 *s, int l, int v) : + GuiSound(s, l, v, 0) +{ + currentPath = NULL; + currentPlaying = 0; + voice = 0; +} + +GuiBGM::~GuiBGM() +{ + if (currentPath) delete[] currentPath; + + ClearList(); +} + +bool GuiBGM::Load(const char *path) +{ + if (!path) + { + LoadStandard(); + return false; + } + if (strcmp(path, "") == 0) + { + LoadStandard(); + return false; + } + + if (!GuiSound::Load(path)) + { + LoadStandard(); + return false; + } + + return ParsePath(path); +} + +bool GuiBGM::LoadStandard() +{ + ClearList(); + if (currentPath) + { + delete[] currentPath; + currentPath = NULL; + } + + strcpy(Settings.ogg_path, ""); + + bool ret = GuiSound::Load(Resources::GetFile("bg_music.ogg"), Resources::GetFileSize("bg_music.ogg")); + + if (ret) Play(); + + return ret; +} + +bool GuiBGM::ParsePath(const char * folderpath) +{ + ClearList(); + + if (currentPath) delete[] currentPath; + + currentPath = new char[strlen(folderpath) + 1]; + strcpy(currentPath, folderpath); + + char * isdirpath = strrchr(folderpath, '.'); + if (isdirpath) + { + char * pathptr = strrchr(currentPath, '/'); + if (pathptr) + { + pathptr++; + pathptr[0] = 0; + } + } + + char * LoadedFilename = strrchr(folderpath, '/') + 1; + + char filename[1024]; + struct dirent * dirent = NULL; + + DIR * dir = opendir(currentPath); + if (dir == NULL) + { + LoadStandard(); + return false; + } + u32 counter = 0; + + while ((dirent = readdir(dir)) != 0) + { + snprintf(filename, sizeof(filename), dirent->d_name); + + char * fileext = strrchr(filename, '.'); + if (!fileext) + continue; + + if (strcasecmp(fileext, ".mp3") == 0 || strcasecmp(fileext, ".ogg") == 0 || + strcasecmp(fileext, ".wav") == 0 || strcasecmp(fileext, ".aif") == 0) + { + AddEntrie(filename); + + if (strcmp(LoadedFilename, filename) == 0) currentPlaying = counter; + + counter++; + } + + } + + closedir(dir); + + snprintf(Settings.ogg_path, sizeof(Settings.ogg_path), "%s", folderpath); + + return true; +} + +void GuiBGM::AddEntrie(const char * filename) +{ + if (!filename) return; + + char * NewEntrie = new char[strlen(filename) + 1]; + strcpy(NewEntrie, filename); + + PlayList.push_back(NewEntrie); +} + +void GuiBGM::ClearList() +{ + for (u32 i = 0; i < PlayList.size(); i++) + { + if (PlayList.at(i) != NULL) + { + delete[] PlayList.at(i); + PlayList.at(i) = NULL; + } + } + + PlayList.clear(); +} + +bool GuiBGM::PlayNext() +{ + if (!currentPath) return false; + + currentPlaying++; + if (currentPlaying >= (int) PlayList.size()) currentPlaying = 0; + + snprintf(Settings.ogg_path, sizeof(Settings.ogg_path), "%s%s", currentPath, PlayList.at(currentPlaying)); + + if (!GuiSound::Load(Settings.ogg_path)) return false; + + Play(); + + return true; +} + +bool GuiBGM::PlayPrevious() +{ + if (!currentPath) return false; + + currentPlaying--; + if (currentPlaying < 0) currentPlaying = PlayList.size() - 1; + + snprintf(Settings.ogg_path, sizeof(Settings.ogg_path), "%s%s", currentPath, PlayList.at(currentPlaying)); + + if (!GuiSound::Load(Settings.ogg_path)) return false; + + Play(); + + return true; +} + +bool GuiBGM::PlayRandom() +{ + if (!currentPath) return false; + + srand(time(NULL)); + + currentPlaying = rand() % PlayList.size(); + + //just in case + if (currentPlaying < 0) + currentPlaying = PlayList.size() - 1; + else if (currentPlaying >= (int) PlayList.size()) currentPlaying = 0; + + snprintf(Settings.ogg_path, sizeof(Settings.ogg_path), "%s%s", currentPath, PlayList.at(currentPlaying)); + + if (!GuiSound::Load(Settings.ogg_path)) return false; + + Play(); + + return true; +} + +void GuiBGM::UpdateState() +{ + if (!IsPlaying()) + { + if (loop == DIR_LOOP) + { + PlayNext(); + } + else if (loop == RANDOM_BGM) + { + PlayRandom(); + } + } +} diff --git a/source/SoundOperations/gui_bgm.h b/source/SoundOperations/gui_bgm.h new file mode 100644 index 0000000..7a08645 --- /dev/null +++ b/source/SoundOperations/gui_bgm.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * SettingsPrompts + * USB Loader GX 2009 + * + * Backgroundmusic + ***************************************************************************/ + +#ifndef _BGM_H_ +#define _BGM_H_ + +#include +#include "gui_sound.h" + +enum +{ + ONCE = 0, LOOP, RANDOM_BGM, DIR_LOOP +}; + +class GuiBGM: public GuiSound +{ + public: + GuiBGM(const u8 *s, int l, int v); + virtual ~GuiBGM(); + bool Load(const char *path); + bool LoadStandard(); + bool ParsePath(const char * folderpath); + bool PlayNext(); + bool PlayPrevious(); + bool PlayRandom(); + void UpdateState(); + protected: + void AddEntrie(const char * filename); + void ClearList(); + + int currentPlaying; + char * currentPath; + std::vector PlayList; +}; + +#endif diff --git a/source/SoundOperations/gui_sound.cpp b/source/SoundOperations/gui_sound.cpp new file mode 100644 index 0000000..3e452ae --- /dev/null +++ b/source/SoundOperations/gui_sound.cpp @@ -0,0 +1,326 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include "GUI/gui.h" +#include "utils/uncompress.h" +#include "FileOperations/fileops.h" +#include "SoundHandler.hpp" +#include "WavDecoder.hpp" + +#define MAX_SND_VOICES 16 + +static bool VoiceUsed[MAX_SND_VOICES] = +{ + true, false, false, false, false, false, + false, false, false, false, false, false, + false, false, false, false +}; + +static inline int GetFirstUnusedVoice() +{ + for(int i = 1; i < MAX_SND_VOICES; i++) + { + if(VoiceUsed[i] == false) + return i; + } + + return -1; +} + +extern "C" void SoundCallback(s32 voice) +{ + SoundDecoder * decoder = SoundHandler::Instance()->Decoder(voice); + if(!decoder) + return; + + if(decoder->IsBufferReady()) + { + if(ASND_AddVoice(voice, decoder->GetBuffer(), decoder->GetBufferSize()) == SND_OK) + { + decoder->LoadNext(); + SoundHandler::Instance()->ThreadSignal(); + } + } + else if(decoder->IsEOF()) + { + ASND_StopVoice(voice); + //if(voice == 0) + //MusicPlayer::Instance()->SetPlaybackFinished(true); //see if next music must be played + } + else + { + SoundHandler::Instance()->ThreadSignal(); + } +} + +GuiSound::GuiSound(const char * filepath) +{ + sound = NULL; + length = 0; + voice = GetFirstUnusedVoice(); + if(voice > 0) + VoiceUsed[voice] = true; + + volume = 255; + SoundEffectLength = 0; + loop = 0; + Load(filepath); +} + +GuiSound::GuiSound(const u8 * snd, s32 len, int vol, int v) +{ + sound = NULL; + length = 0; + if(v < 0) + voice = GetFirstUnusedVoice(); + else + voice = v; + + if(voice > 0) + VoiceUsed[voice] = true; + + volume = vol; + SoundEffectLength = 0; + loop = 0; + Load(snd, len); +} + +GuiSound::~GuiSound() +{ + FreeMemory(); + if(voice > 0) + VoiceUsed[voice] = false; +} + +void GuiSound::FreeMemory() +{ + this->Stop(); + + SoundHandler::Instance()->RemoveDecoder(voice); + + if(sound != NULL && SoundEffectLength != 0) + free(sound); + + sound = NULL; + SoundEffectLength = 0; +} + +bool GuiSound::Load(const char * filepath) +{ + FreeMemory(); + + if(!filepath) + return false; + + SoundHandler::Instance()->AddDecoder(voice, filepath); + + SoundDecoder * decoder = SoundHandler::Instance()->Decoder(voice); + if(!decoder) + return false; + + if(!decoder->IsBufferReady()) + { + SoundHandler::Instance()->RemoveDecoder(voice); + return false; + } + + SetLoop(loop); + + return true; +} + +bool GuiSound::Load(const u8 * snd, s32 len) +{ + FreeMemory(); + + if(!snd) + return false; + + sound = (u8 *) snd; + length = len; + + SoundHandler::Instance()->AddDecoder(voice, sound, length); + + SoundDecoder * decoder = SoundHandler::Instance()->Decoder(voice); + if(!decoder) + return false; + + if(!decoder->IsBufferReady()) + { + SoundHandler::Instance()->RemoveDecoder(voice); + return false; + } + + SetLoop(loop); + + return true; +} + +bool GuiSound::LoadSoundEffect(const u8 * snd, s32 len) +{ + WavDecoder decoder(snd, len); + decoder.Rewind(); + + u32 done = 0; + sound = (u8 *) malloc(4096); + memset(sound, 0, 4096); + + while(1) + { + u8 * tmpsnd = (u8 *) realloc(sound, done+4096); + if(!tmpsnd) + { + free(sound); + sound = NULL; + return false; + } + + sound = tmpsnd; + + int read = decoder.Read(sound+done, 4096, done); + if(read <= 0) + break; + + done += read; + } + + sound = (u8 *) realloc(sound, done); + SoundEffectLength = done; + + return true; +} + +void GuiSound::Play() +{ + if(SoundEffectLength > 0) + { + ASND_StopVoice(voice); + ASND_SetVoice(voice, VOICE_STEREO_16BIT, 32000, 0, sound, SoundEffectLength, volume, volume, NULL); + return; + } + + if(IsPlaying()) + return; + + if(voice < 0 || voice >= 16) + return; + + SoundDecoder * decoder = SoundHandler::Instance()->Decoder(voice); + if(!decoder) + return; + + if(decoder->IsEOF()) + { + ASND_StopVoice(voice); + decoder->ClearBuffer(); + decoder->Rewind(); + decoder->Decode(); + } + + u8 * curbuffer = decoder->GetBuffer(); + int bufsize = decoder->GetBufferSize(); + decoder->LoadNext(); + SoundHandler::Instance()->ThreadSignal(); + + ASND_SetVoice(voice, decoder->GetFormat(), decoder->GetSampleRate(), 0, curbuffer, bufsize, volume, volume, SoundCallback); +} + +void GuiSound::Stop() +{ + if(voice < 0 || voice >= 16) + return; + + ASND_StopVoice(voice); + + SoundDecoder * decoder = SoundHandler::Instance()->Decoder(voice); + if(!decoder) + return; + + decoder->ClearBuffer(); + Rewind(); + SoundHandler::Instance()->ThreadSignal(); +} + +void GuiSound::Pause() +{ + if(voice < 0 || voice >= 16) + return; + + ASND_StopVoice(voice); +} + +void GuiSound::Resume() +{ + Play(); +} + +bool GuiSound::IsPlaying() +{ + if(voice < 0 || voice >= 16) + return false; + + int result = ASND_StatusVoice(voice); + + if(result == SND_WORKING || result == SND_WAITING) + return true; + + return false; +} + +void GuiSound::SetVolume(int vol) +{ + if(voice < 0 || voice >= 16) + return; + + if(vol < 0) + return; + + volume = (255 * vol)/100; + if(volume > 255) + volume = 255; + + ASND_ChangeVolumeVoice(voice, volume, volume); +} + +void GuiSound::SetLoop(u8 l) +{ + loop = l; + + SoundDecoder * decoder = SoundHandler::Instance()->Decoder(voice); + if(!decoder) + return; + + decoder->SetLoop(l == 1); +} + +void GuiSound::Rewind() +{ + SoundDecoder * decoder = SoundHandler::Instance()->Decoder(voice); + if(!decoder) + return; + + decoder->Rewind(); +} diff --git a/source/SoundOperations/gui_sound.h b/source/SoundOperations/gui_sound.h new file mode 100644 index 0000000..c5290c6 --- /dev/null +++ b/source/SoundOperations/gui_sound.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef GUI_SOUND_H_ +#define GUI_SOUND_H_ + +#include + +//!Sound conversion and playback. A wrapper for other sound libraries - ASND, libmad, ltremor, etc +class GuiSound +{ + public: + //!Constructor + //!\param sound Pointer to the sound data + //!\param filesize Length of sound data + GuiSound(const char * filepath); + GuiSound(const u8 * sound, s32 filesize, int volume, int voice = -1); + //!Destructor + virtual ~GuiSound(); + //!Load a file and replace the old one + virtual bool Load(const char * filepath); + //!Load a file and replace the old one + bool Load(const u8 * sound, s32 filesize); + //!For quick playback of the internal soundeffects + bool LoadSoundEffect(const u8 * snd, s32 len); + //!Start sound playback + void Play(); + //!Stop sound playback + void Stop(); + //!Pause sound playback + void Pause(); + //!Resume sound playback + void Resume(); + //!Checks if the sound is currently playing + //!\return true if sound is playing, false otherwise + bool IsPlaying(); + //!Rewind the music + void Rewind(); + //!Set sound volume + //!\param v Sound volume (0-100) + void SetVolume(int v); + //!\param l Loop (true to loop) + virtual void SetLoop(u8 l); + protected: + //!Stops sound and frees all memory/closes files + void FreeMemory(); + u8 * sound; //!< Pointer to the sound data + int length; //!< Length of sound data + s32 voice; //!< Currently assigned ASND voice channel + int volume; //!< Sound volume (0-100) + u8 loop; //!< Loop sound playback + u32 SoundEffectLength; //!< Check if it is an app soundeffect for faster playback +}; + +#endif diff --git a/source/StartUpProcess.cpp b/source/StartUpProcess.cpp new file mode 100644 index 0000000..4bc8fcd --- /dev/null +++ b/source/StartUpProcess.cpp @@ -0,0 +1,413 @@ +#include +#include "StartUpProcess.h" +#include "GUI/gui.h" +#include "video.h" +#include "audio.h" +#include "input.h" +#include "themes/CTheme.h" +#include "gecko.h" +#include "Controls/DeviceHandler.hpp" +#include "wad/nandtitle.h" +#include "SystemMenu/SystemMenuResources.h" +#include "system/IosLoader.h" +#include "libs/libruntimeiospatch/runtimeiospatch.h" +#include "utils/timer.h" +#include "settings/CSettings.h" +#include "settings/CGameSettings.h" +#include "settings/CGameStatistics.h" +#include "settings/CGameCategories.hpp" +#include "settings/GameTitles.h" +#include "usbloader/usbstorage2.h" +#include "usbloader/MountGamePartition.h" +#include "usbloader/GameBooter.hpp" +#include "usbloader/GameList.h" +#include "utils/tools.h" +#include "sys.h" +#include "svnrev.h" + +extern bool isWiiVC; // in sys.cpp + +StartUpProcess::StartUpProcess() +{ + //! Load default font for the next text outputs + Theme::LoadFont(""); + + background = new GuiImage(screenwidth, screenheight, (GXColor) {0, 0, 0, 255}); + + GXImageData = Resources::GetImageData("gxlogo.png"); + GXImage = new GuiImage(GXImageData); + GXImage->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + GXImage->SetPosition(screenwidth/2, screenheight/2-50); + + titleTxt = new GuiText("Loading...", 24, (GXColor) {255, 255, 255, 255}); + titleTxt->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + titleTxt->SetPosition(screenwidth/2, screenheight/2+30); + + messageTxt = new GuiText(" ", 22, (GXColor) {255, 255, 255, 255}); + messageTxt->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + messageTxt->SetPosition(screenwidth/2, screenheight/2+60); + + versionTxt = new GuiText(" ", 18, (GXColor) {255, 255, 255, 255}); + versionTxt->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + versionTxt->SetPosition(20, screenheight-20); + +#ifdef FULLCHANNEL + versionTxt->SetTextf("v3.0c Rev. %s [Asayu]", GetRev()); +#else + versionTxt->SetTextf("v3.0 Rev. %s [Asayu]", GetRev()); +#endif + +#if 0 // enable if you release a modded version - enabled by default to differentiate official releases + versionTxt->SetTextf("v3.0 Rev. %s mod", GetRev()); +#endif + + cancelTxt = new GuiText("Press B to cancel", 18, (GXColor) {255, 255, 255, 255}); + cancelTxt->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + cancelTxt->SetPosition(screenwidth/2, screenheight/2+90); + + trigB = new GuiTrigger; + trigB->SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + cancelBtn = new GuiButton(0, 0); + cancelBtn->SetTrigger(trigB); + + drawCancel = false; +} + +StartUpProcess::~StartUpProcess() +{ + delete background; + delete GXImageData; + delete GXImage; + delete titleTxt; + delete messageTxt; + delete versionTxt; + delete cancelTxt; + delete cancelBtn; + delete trigB; +} + +int StartUpProcess::ParseArguments(int argc, char *argv[]) +{ + int quickBoot = -1; + + //! The arguments override + for(int i = 0; i < argc; ++i) + { + if(!argv[i]) continue; + + gprintf("Boot argument %i: %s\n", i+1, argv[i]); + + char *ptr = strcasestr(argv[i], "-ios="); + if(ptr) + { + if(atoi(ptr+strlen("-ios=")) == 58) + Settings.LoaderIOS = 58; + else + Settings.LoaderIOS = LIMIT(atoi(ptr+strlen("-ios=")), 200, 255); + Settings.UseArgumentIOS = ON; + } + + ptr = strcasestr(argv[i], "-usbport="); + if(ptr) + { + Settings.USBPort = LIMIT(atoi(ptr+strlen("-usbport=")), 0, 2); + } + + ptr = strcasestr(argv[i], "-mountusb="); + if(ptr) + { + Settings.USBAutoMount = LIMIT(atoi(ptr+strlen("-mountusb=")), 0, 1); + } + + if(strlen(argv[i]) == 6 && strchr(argv[i], '=') == 0 && strchr(argv[i], '-') == 0) + quickBoot = i; + } + + return quickBoot; +} + +void StartUpProcess::TextFade(int direction) +{ + if(direction > 0) + { + for(int i = 0; i < 255; i += direction) + { + messageTxt->SetAlpha(i); + Draw(); + } + messageTxt->SetAlpha(255); + Draw(); + } + else if(direction < 0) + { + for(int i = 255; i > 0; i += direction) + { + messageTxt->SetAlpha(i); + Draw(); + } + messageTxt->SetAlpha(0); + Draw(); + } +} + +void StartUpProcess::SetTextf(const char * format, ...) +{ + char * tmp = NULL; + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + TextFade(-40); + gprintf(tmp); + messageTxt->SetText(tmp); + TextFade(40); + } + va_end(va); + + if(tmp) + free(tmp); +} + +bool StartUpProcess::USBSpinUp() +{ + drawCancel = true; + Timer countDown; + bool started0 = false; + bool started1 = false; + + const DISC_INTERFACE * handle0 = NULL; + const DISC_INTERFACE * handle1 = NULL; + if(Settings.USBPort == 0 || Settings.USBPort == 2) + handle0 = DeviceHandler::GetUSB0Interface(); + if(Settings.USBPort == 1 || Settings.USBPort == 2) + handle1 = DeviceHandler::GetUSB1Interface(); + + // wait 20 sec for the USB to spin up...stupid slow ass HDD + do + { + if(handle0) + started0 = (handle0->startup() && handle0->isInserted()); + + if(handle1) + started1 = (handle1->startup() && handle1->isInserted()); + + if( (!handle0 || started0) + && (!handle1 || started1)) { + break; + } + + + UpdatePads(); + for(int i = 0; i < 4; ++i) + cancelBtn->Update(&userInput[i]); + + if(cancelBtn->GetState() == STATE_CLICKED) + break; + + messageTxt->SetTextf("Waiting for HDD: %i sec left\n", 20-(int)countDown.elapsed()); + Draw(); + usleep(50000); + } + while(countDown.elapsed() < 20.f); + + drawCancel = false; + + return (started0 || started1); +} + +int StartUpProcess::Run(int argc, char *argv[]) +{ + int quickGameBoot = ParseArguments(argc, argv); + + StartUpProcess Process; + + int ret = Process.Execute(); + + if(quickGameBoot != -1) + return QuickGameBoot(argv[quickGameBoot]); + + return ret; +} + +int StartUpProcess::Execute() +{ + Settings.EntryIOS = IOS_GetVersion(); + + // Reload app cios if needed + SetTextf("Loading application cIOS %s\n", Settings.UseArgumentIOS ? "requested in meta.xml" : ""); + if(IosLoader::LoadAppCios() < 0) + { + SetTextf("Failed loading any cIOS. Trying with IOS58 + AHB access..."); + + // We can allow now operation without cIOS in channel mode with AHB access + if(!AHBPROT_DISABLED || (AHBPROT_DISABLED && IOS_GetVersion() != 58)) + { + SetTextf("Failed loading IOS 58. USB Loader GX requires a cIOS or IOS 58 with AHB access. Exiting...\n"); + sleep(5); + Sys_BackToLoader(); + } + else + { + Settings.LoaderIOS = 58; + SetTextf("Running on IOS 58. Wii disc based games and some channels will not work."); + sleep(5); + } + } + + if(!AHBPROT_DISABLED && IOS_GetVersion() < 200) + { + SetTextf("Failed loading IOS %i. USB Loader GX requires a cIOS or IOS58 with AHB access. Exiting...\n", IOS_GetVersion()); + sleep(5); + Sys_BackToLoader(); + } + + SetTextf("Using %sIOS %i\n", IOS_GetVersion() >= 200 ? "c" : "", IOS_GetVersion()); + + SetupPads(); + + SetTextf("Initialize sd card\n"); + DeviceHandler::Instance()->MountSD(); + + // Do not mount USB if not needed. USB is not available with WiiU WiiVC injected channel. + if(Settings.USBAutoMount == ON && !isWiiVC) + { + SetTextf("Initialize usb device\n"); + USBSpinUp(); + DeviceHandler::Instance()->MountAllUSB(false); + } + + SetTextf("Loading config files\n"); + + gprintf("\tLoading config...%s\n", Settings.Load() ? "done" : "failed"); + gprintf("\tLoading language...%s\n", Settings.LoadLanguage(Settings.language_path, CONSOLE_DEFAULT) ? "done" : "failed"); + gprintf("\tLoading game settings...%s\n", GameSettings.Load(Settings.ConfigPath) ? "done" : "failed"); + gprintf("\tLoading game statistics...%s\n", GameStatistics.Load(Settings.ConfigPath) ? "done" : "failed"); + gprintf("\tLoading game categories...%s\n", GameCategories.Load(Settings.ConfigPath) ? "done" : "failed"); + if(Settings.CacheTitles) + gprintf("\tLoading cached titles...%s\n", GameTitles.ReadCachedTitles(Settings.titlestxt_path) ? "done" : "failed (using default)"); + + // Reload to user's settings if different than current IOS, and if not using an injected WiiU WiiVC IOS255 (fw.img) + if(Settings.LoaderIOS != IOS_GetVersion() && !isWiiVC) + { + SetTextf("Reloading to config file's cIOS...\n"); + + // Unmount devices + DeviceHandler::DestroyInstance(); + if(Settings.USBAutoMount == ON) + USBStorage2_Deinit(); + + // Shut down pads + WPAD_Shutdown(); + + // Loading now the cios setup in the settings + IosLoader::LoadAppCios(); + + SetTextf("Reloaded into cIOS %i R%i\n", IOS_GetVersion(), IOS_GetRevision()); + + // Re-Mount devices + SetTextf("Reinitializing devices...\n"); + DeviceHandler::Instance()->MountSD(); + if(Settings.USBAutoMount == ON) + { + USBSpinUp(); + DeviceHandler::Instance()->MountAllUSB(false); + } + + // Start pads again + SetupPads(); + } + + if(!IosLoader::IsHermesIOS() && !IosLoader::IsD2X()) + { + Settings.USBPort = 0; + } + else if(Settings.USBPort == 1 && USBStorage2_GetPort() != Settings.USBPort) + { + if(Settings.USBAutoMount == ON && !isWiiVC) + { + SetTextf("Changing USB Port to %i\n", Settings.USBPort); + DeviceHandler::Instance()->UnMountAllUSB(); + DeviceHandler::Instance()->MountAllUSB(); + } + } + else if(Settings.USBPort == 2) + { + if(Settings.USBAutoMount == ON && !isWiiVC) + { + SetTextf("Mounting USB Port to 1\n"); + DeviceHandler::Instance()->MountUSBPort1(); + } + } + + // enable isfs permission if using Hermes v4 without AHB, or WiiU WiiVC (IOS255 fw.img) + if(IOS_GetVersion() < 200 || (IosLoader::IsHermesIOS() && IOS_GetRevision() == 4) || isWiiVC) + { + SetTextf("Patching %sIOS%d...\n", IOS_GetVersion() >= 200 ? "c" : "", IOS_GetVersion()); + if (IosPatch_RUNTIME(!isWiiVC, false, false, isWiiVC, false) == ERROR_PATCH) + gprintf("Patching %sIOS%d failed!\n", IOS_GetVersion() >= 200 ? "c" : "", IOS_GetVersion()); + else + NandTitles.Get(); // get NAND channel's titles + } + + // We only initialize once for the whole session + ISFS_Initialize(); + + // Check MIOS version + SetTextf("Checking installed MIOS... "); + IosLoader::GetMIOSInfo(); + + SetTextf("Loading resources\n"); + // Do not allow banner grid mode without AHBPROT + // this function does nothing if it was already initiated before + if( !SystemMenuResources::Instance()->IsLoaded() && !SystemMenuResources::Instance()->Init() + && Settings.gameDisplay == BANNERGRID_MODE) + { + Settings.gameDisplay = LIST_MODE; + Settings.GameWindowMode = GAMEWINDOW_DISC; + } + + gprintf("\tLoading font...%s\n", Theme::LoadFont(Settings.ConfigPath) ? "done" : "failed (using default)"); + gprintf("\tLoading theme...%s\n", Theme::Load(Settings.theme) ? "done" : "failed (using default)"); + + //! Init the rest of the System + Sys_Init(); + InitAudio(); + setlocale(LC_CTYPE, "C-UTF-8"); + setlocale(LC_MESSAGES, "C-UTF-8"); + AdjustOverscan(Settings.AdjustOverscanX, Settings.AdjustOverscanY); + + return 0; +} + +void StartUpProcess::Draw() +{ + background->Draw(); + GXImage->Draw(); + titleTxt->Draw(); + messageTxt->Draw(); + versionTxt->Draw(); + if(drawCancel) + cancelTxt->Draw(); + Menu_Render(); +} + +int StartUpProcess::QuickGameBoot(const char * gameID) +{ + MountGamePartition(false); + + struct discHdr *header = NULL; + for(int i = 0; i < gameList.size(); ++i) + { + if(strncasecmp((char *) gameList[i]->id, gameID, 6) == 0) + header = gameList[i]; + } + + if(!header) + return -1; + + GameStatistics.SetPlayCount(header->id, GameStatistics.GetPlayCount(header->id)+1); + GameStatistics.Save(); + + return GameBooter::BootGame(header); +} diff --git a/source/StartUpProcess.h b/source/StartUpProcess.h new file mode 100644 index 0000000..174feba --- /dev/null +++ b/source/StartUpProcess.h @@ -0,0 +1,34 @@ +#ifndef STARTUPPROCESS_H_ +#define STARTUPPROCESS_H_ + +#include "GUI/gui.h" + +class StartUpProcess +{ + public: + static int Run(int argc, char *argv[]); + private: + StartUpProcess(); + ~StartUpProcess(); + int Execute(); + bool USBSpinUp(); + void TextFade(int direction); + void SetTextf(const char * format, ...); + void Draw(); + static int ParseArguments(int argc, char *argv[]); + static int QuickGameBoot(const char * gameID); + + bool drawCancel; + + GuiImageData * GXImageData; + GuiImage * background; + GuiImage * GXImage; + GuiText * titleTxt; + GuiText * messageTxt; + GuiText * versionTxt; + GuiText * cancelTxt; + GuiButton * cancelBtn; + GuiTrigger * trigB; +}; + +#endif diff --git a/source/SystemMenu/BannerFrame.cpp b/source/SystemMenu/BannerFrame.cpp new file mode 100644 index 0000000..9c602d2 --- /dev/null +++ b/source/SystemMenu/BannerFrame.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 "BannerFrame.h" +#include "SystemMenu/SystemMenuResources.h" +#include "utils/U8Archive.h" +#include "utils/StringTools.h" + +BannerFrame::~BannerFrame() +{ + delete [] UTF16ButtonA; + delete [] UTF16ButtonB; +} + +bool BannerFrame::Load( const U8Archive &chanTtlArc ) +{ + // read layout data + u8 *brlytFile = chanTtlArc.GetFile( "/arc/blyt/my_ChTop_a.brlyt" ); + if( !brlytFile ) + return false; + + if(!Layout::Load(brlytFile)) + return false; + + // load textures + LoadTextures(chanTtlArc); + + N_BtnA = FindPane("N_BtnA"); + N_BtnB = FindPane("N_BtnB"); + + Loaded = true; + + return true; +} + +void BannerFrame::SetButtonAText(const char *text) +{ + //!< Set button text for left button + const wchar_t *buttonText = wfmt("%s", text); + int len = wcslen(buttonText); + + delete [] UTF16ButtonA; + UTF16ButtonA = new u16[len+1]; + + for(int i = 0; i < len; i++) + UTF16ButtonA[i] = (u16) buttonText[i]; + UTF16ButtonA[len] = 0; + + Textbox *T_BtnA = (Textbox *)FindPane("T_BtnA"); + if(T_BtnA) + T_BtnA->SetText(UTF16ButtonA); +} + +void BannerFrame::SetButtonBText(const char *text) +{ + //!< Set button text for right button + const wchar_t *buttonText = wfmt("%s", text); + int len = wcslen(buttonText); + + delete [] UTF16ButtonB; + UTF16ButtonB = new u16[len+1]; + + for(int i = 0; i < len; i++) + UTF16ButtonB[i] = (u16) buttonText[i]; + UTF16ButtonB[len] = 0; + + Textbox *T_BtnB = (Textbox *)FindPane("T_BtnB"); + if(T_BtnB) + T_BtnB->SetText(UTF16ButtonB); +} + + +void BannerFrame::AdvanceFrame() +{ + if(!N_BtnA || !N_BtnB) + return; + + if(GrowEffectBtnA && ScaleBtnA < 1.05f) + { + ScaleBtnA += 0.01f; + N_BtnA->SetScale(ScaleBtnA); + } + else if(!GrowEffectBtnA && ScaleBtnA > 1.0f) + { + ScaleBtnA -= 0.01f; + N_BtnA->SetScale(ScaleBtnA); + } + + if(GrowEffectBtnB && ScaleBtnB < 1.05f) + { + ScaleBtnB += 0.01f; + N_BtnB->SetScale(ScaleBtnB); + } + else if(!GrowEffectBtnB && ScaleBtnB > 1.0f) + { + ScaleBtnB -= 0.01f; + N_BtnB->SetScale(ScaleBtnB); + } + + // we don't load any brlan for it + // Layout::AdvanceFrame(); +} diff --git a/source/SystemMenu/BannerFrame.h b/source/SystemMenu/BannerFrame.h new file mode 100644 index 0000000..9871c15 --- /dev/null +++ b/source/SystemMenu/BannerFrame.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 BANNERFRAME_H +#define BANNERFRAME_H + +#include "banner/Layout.h" + +// this is a class to deal with the frame the goes over the large banners +class BannerFrame : public Layout +{ +public: + BannerFrame() + : Loaded(false), + GrowEffectBtnA(false), GrowEffectBtnB(false), + ScaleBtnA(1.f), ScaleBtnB(1.f), + N_BtnA(0), N_BtnB(0), + UTF16ButtonA(0), UTF16ButtonB(0) + { } + virtual ~BannerFrame(); + bool Load( const U8Archive &archive ); + bool IsLoaded() const { return Loaded; } + void AdvanceFrame(); + void SetButtonAGrow(bool b) { GrowEffectBtnA = b; } + void SetButtonBGrow(bool b) { GrowEffectBtnB = b; } + void SetButtonAText(const char *text); + void SetButtonBText(const char *text); +private: + bool Loaded; + bool GrowEffectBtnA; + bool GrowEffectBtnB; + float ScaleBtnA; + float ScaleBtnB; + Pane *N_BtnA; + Pane *N_BtnB; + u16 *UTF16ButtonA; + u16 *UTF16ButtonB; +}; + +#endif // BANNERFRAME_H diff --git a/source/SystemMenu/GCBanner.cpp b/source/SystemMenu/GCBanner.cpp new file mode 100644 index 0000000..c90e1af --- /dev/null +++ b/source/SystemMenu/GCBanner.cpp @@ -0,0 +1,43 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 "SystemMenu/SystemMenuResources.h" +#include "GCBanner.h" + +bool GCBanner::Load( const U8Archive &GCBannArc ) +{ + // read layout data + const u8 *brlytFile = GCBannArc.GetFile("/arc/blyt/my_GCTop_a.brlyt"); + if( !brlytFile ) + return false; + + if(!Layout::Load(brlytFile)) + return false; + + u32 length_start = 0, length_loop = 0; + + const u8 *brlan_loop = GCBannArc.GetFile("/arc/anim/my_GCTop_a_BackLoop.brlan"); + if (brlan_loop) + length_loop = Animator::LoadAnimators((const RLAN_Header *)brlan_loop, *this, 1); + + LoadTextures(GCBannArc); + SetLanguage("ENG"); + SetLoopStart(length_start); + SetLoopEnd(length_start + length_loop); + SetFrame(0); + + return true; +} diff --git a/source/SystemMenu/GCBanner.h b/source/SystemMenu/GCBanner.h new file mode 100644 index 0000000..5096693 --- /dev/null +++ b/source/SystemMenu/GCBanner.h @@ -0,0 +1,29 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 GCBANNER_H +#define GCBANNER_H + +#include "banner/Layout.h" + +// this is a class to deal with the gc disc channel +class GCBanner : public Layout +{ +public: + bool Load( const U8Archive &archive ); +}; + +#endif // STATICFRAME_H diff --git a/source/SystemMenu/StaticFrame.cpp b/source/SystemMenu/StaticFrame.cpp new file mode 100644 index 0000000..e1caa82 --- /dev/null +++ b/source/SystemMenu/StaticFrame.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 "StaticFrame.h" + +bool StaticFrame::Load( const U8Archive &chanSelArc ) +{ + // read layout data + const u8 *brlytFile = chanSelArc.GetFile("/arc/blyt/my_IplTop_b.brlyt"); + if( !brlytFile ) + return false; + + if(!Layout::Load(brlytFile)) + return false; + + u32 length_start = 0, length_loop = 0; + + const u8 *brlan_loop = chanSelArc.GetFile("/arc/anim/my_IplTop_b.brlan"); + if (brlan_loop) + length_loop = Animator::LoadAnimators((const RLAN_Header *)brlan_loop, *this, 1); + + LoadTextures(chanSelArc); + SetLanguage("ENG"); + SetLoopStart(length_start); + SetLoopEnd(length_start + length_loop); + SetFrame(0); + + return true; +} diff --git a/source/SystemMenu/StaticFrame.h b/source/SystemMenu/StaticFrame.h new file mode 100644 index 0000000..5a07187 --- /dev/null +++ b/source/SystemMenu/StaticFrame.h @@ -0,0 +1,29 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 STATICFRAME_H +#define STATICFRAME_H + +#include "banner/Layout.h" + +// this is a class to deal with the frame the goes as default channel +class StaticFrame : public Layout +{ +public: + bool Load( const U8Archive &archive ); +}; + +#endif // STATICFRAME_H diff --git a/source/SystemMenu/SystemMenuResources.cpp b/source/SystemMenu/SystemMenuResources.cpp new file mode 100644 index 0000000..b3fec0c --- /dev/null +++ b/source/SystemMenu/SystemMenuResources.cpp @@ -0,0 +1,314 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok, giantpune + * + * 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 "gecko.h" +#include "SystemMenu/SystemMenuResources.h" +#include "memory/mem2.h" +#include "utils/U8Archive.h" +#include "wad/nandtitle.h" + +SystemMenuResources *SystemMenuResources::instance = NULL; + +SystemMenuResources::SystemMenuResources(): + isInited( false ), + wbf1( NULL ), + wbf2( NULL ), + wbf1Buffer( NULL ), + wbf2Buffer( NULL ), + chanTtlAsh( NULL ), + chanSelAsh( NULL ), + GCBannAsh( NULL ), + systemFont( NULL ) +{ +} + +SystemMenuResources::~SystemMenuResources() +{ + FreeEverything(); +} + +bool SystemMenuResources::Init() +{ + if( isInited ) + return true; + + // get tmd + tmd *p_tmd = NandTitles.GetTMD( 0x100000002ull ); + if( !p_tmd ) + { + gprintf( "can\'t get system menu TMD\n" ); + return false; + } + + // determine resource cid + u16 idx = 0xffff; + tmd_content *contents = TMD_CONTENTS( p_tmd ); + for( u16 i = 0; i < p_tmd->num_contents; i++ ) + { + if( contents[ i ].index == 1 ) + { + idx = i; + break; + } + } + if( idx == 0xffff ) + { + gprintf( "SM main resource not found\n" ); + return false; + } + // build file path + char path[ ISFS_MAXPATH ]__attribute__((aligned( 32 ))); + sprintf( path, "/title/00000001/00000002/content/%08x.app", (unsigned int)contents[ idx ].cid ); + + // get resource archive + u8* resourceArc = NULL; + u32 resourceLen = 0; + int ret; + + if( ( ret = NandTitle::LoadFileFromNand( path, &resourceArc, &resourceLen ) ) < 0 ) + { + gprintf( "Error reading resource from nand: %i\n", ret ); + return false; + } + + // create U8 archive for reading files + U8Archive mainArc( resourceArc, resourceLen ); + + // Load the font archive + InitFontArchive(); + + // read ash files + chanTtlAsh = mainArc.GetFileAllocated( "/layout/common/chanTtl.ash", &chanTtlAshSize); + if(!chanTtlAsh) + { + gprintf( "Error while loading chanTtl.ash\n" ); + } + // move this to mem2 + else if(!isMEM2Buffer(chanTtlAsh)) + { + u8 *tmp = (u8 *) MEM2_alloc(chanTtlAshSize); + if(tmp) + { + memcpy(tmp, chanTtlAsh, chanTtlAshSize); + free(chanTtlAsh); + chanTtlAsh = tmp; + } + } + + // read ash files + chanSelAsh = mainArc.GetFileAllocated( "/layout/common/chanSel.ash", &chanSelAshSize); + if(!chanSelAsh) + { + gprintf( "Error while loading chanSel.ash\n" ); + } + // move this to mem2 + else if(!isMEM2Buffer(chanSelAsh)) + { + u8 *tmp = (u8 *) MEM2_alloc(chanSelAshSize); + if(tmp) + { + memcpy(tmp, chanSelAsh, chanSelAshSize); + free(chanSelAsh); + chanSelAsh = tmp; + } + } +/* Currently not used since we use a custom banner + // load GC banner for GC games + GCBannAsh = mainArc.GetFileAllocated( "/layout/common/GCBann.ash", &GCBannAshSize); + if(!GCBannAsh) + { + gprintf( "Error while loading GCBannAsh.ash\n" ); + } + // move this to mem2 + else if(!isMEM2Buffer(GCBannAsh)) + { + u8 *tmp = (u8 *) MEM2_alloc(GCBannAshSize); + if(tmp) + { + memcpy(tmp, GCBannAsh, GCBannAshSize); + free(GCBannAsh); + GCBannAsh = tmp; + } + } +*/ + // done with the huge U8 archie now that we already got everything out of it + free( resourceArc ); + + isInited = true; + return true; +} + +typedef struct map_entry +{ + char name[8]; + u8 hash[20]; +} __attribute__((packed)) map_entry_t; + +static const char contentMapPath[] ATTRIBUTE_ALIGN(32) = "/shared1/content.map"; +static const u8 WFB_HASH[] = { 0x4f, 0xad, 0x97, 0xfd, 0x4a, 0x28, 0x8c, 0x47, 0xe0, 0x58, 0x7f, 0x3b, 0xbd, 0x29, 0x23, 0x79, 0xf8, 0x70, 0x9e, 0xb9 }; +static const u8 WIIFONT_HASH[] = {0x32, 0xb3, 0x39, 0xcb, 0xbb, 0x50, 0x7d, 0x50, 0x27, 0x79, 0x25, 0x9a, 0x78, 0x66, 0x99, 0x5d, 0x03, 0x0b, 0x1d, 0x88}; +static const u8 WIIFONT_HASH_KOR[] = {0xb7, 0x15, 0x6d, 0xf0, 0xf4, 0xae, 0x07, 0x8f, 0xd1, 0x53, 0x58, 0x3e, 0x93, 0x6e, 0x07, 0xc0, 0x98, 0x77, 0x49, 0x0e}; + +bool SystemMenuResources::InitFontArchive(void) +{ + // get content.map + u8 *contentMap = NULL; + u32 mapsize = 0; + + NandTitle::LoadFileFromNand(contentMapPath, &contentMap, &mapsize); + if(!contentMap) + { + gprintf( "!contentMap\n" ); + return false; + } + + int fileCount = mapsize / sizeof(map_entry_t); + map_entry_t *mapEntryList = (map_entry_t *) contentMap; + + // search content.map for brfna archive + for( int i = 0; i < fileCount; i++ ) + { + if( memcmp(mapEntryList[i].hash, WFB_HASH, 20 ) ) + continue; + + // Name found + char font_filename[32] ATTRIBUTE_ALIGN(32); + snprintf( font_filename, sizeof( font_filename ), "/shared1/%.8s.app", mapEntryList[ i ].name ); + + u8 *fontArchiveBuffer = NULL; + u32 fontArchiveSize; + NandTitle::LoadFileFromNand( font_filename, &fontArchiveBuffer, &fontArchiveSize ); + if( !fontArchiveBuffer ) + { + free(contentMap); + return false; + } + + U8Archive fontArc(fontArchiveBuffer, fontArchiveSize); + wbf1Buffer = fontArc.GetFileAllocated("wbf1.brfna"); + wbf2Buffer = fontArc.GetFileAllocated("wbf2.brfna"); + + if(wbf1Buffer) + { + wbf1 = new WiiFont; + wbf1->SetName("wbf1.brfna"); + wbf1->Load(wbf1Buffer); + } + if(wbf2Buffer) + { + wbf2 = new WiiFont; + wbf2->SetName("wbf2.brfna"); + wbf2->Load(wbf2Buffer); + } + + free(fontArchiveBuffer); + break; + } + + if(!systemFont) + InitSystemFontArchive(CONF_GetLanguage() == CONF_LANG_KOREAN, contentMap, mapsize); + if(!systemFont) + InitSystemFontArchive(CONF_GetLanguage() != CONF_LANG_KOREAN, contentMap, mapsize); + + free( contentMap ); + + // not found + if( !systemFont || !wbf1Buffer || !wbf2Buffer ) + { + // shared fonts not found + return false; + } + + return true; +} + +bool SystemMenuResources::InitSystemFontArchive(bool korean, u8 *contentMap, u32 mapsize) +{ + int fileCount = mapsize / sizeof(map_entry_t); + + map_entry_t *mapEntryList = (map_entry_t *) contentMap; + + for (int i = 0; i < fileCount; i++) + { + if (memcmp(mapEntryList[i].hash, korean ? WIIFONT_HASH_KOR : WIIFONT_HASH, 20) != 0) + continue; + + // Name found, load it and unpack it + char font_filename[32] ATTRIBUTE_ALIGN(32); + snprintf(font_filename, sizeof(font_filename), "/shared1/%.8s.app", mapEntryList[i].name); + + u8 *fontArchive = NULL; + u32 filesize = 0; + + NandTitle::LoadFileFromNand(font_filename, &fontArchive, &filesize); + if(!fontArchive) + continue; + + U8Archive systemFontArc(fontArchive, filesize); + + systemFont = systemFontArc.GetFileAllocated(1, &systemFontSize); + if(!systemFont) + { + free(fontArchive); + continue; + } + // move this to mem2 + else if(!isMEM2Buffer(systemFont)) + { + u8 *tmp = (u8 *) MEM2_alloc(systemFontSize); + if(tmp) + { + memcpy(tmp, systemFont, systemFontSize); + free(systemFont); + systemFont = tmp; + } + } + + free(fontArchive); + gprintf("Loaded Wii System Font\n"); + return true; + } + + return false; +} + +void SystemMenuResources::FreeEverything() +{ + if(chanTtlAsh) + free(chanTtlAsh); + if(chanSelAsh) + free(chanSelAsh); + if(GCBannAsh) + free(GCBannAsh); + if(wbf1Buffer) + free(wbf1Buffer); + if(wbf2Buffer) + free(wbf2Buffer); + if(systemFont) + free(systemFont); + + delete wbf1; + delete wbf2; + + chanTtlAsh = NULL; + chanSelAsh = NULL; + GCBannAsh = NULL; + systemFont = NULL; + wbf1Buffer = NULL; + wbf2Buffer = NULL; + wbf1 = NULL; + wbf2 = NULL; +} diff --git a/source/SystemMenu/SystemMenuResources.h b/source/SystemMenu/SystemMenuResources.h new file mode 100644 index 0000000..c7f0fed --- /dev/null +++ b/source/SystemMenu/SystemMenuResources.h @@ -0,0 +1,87 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 SYSTEMMENURESOURCES_H +#define SYSTEMMENURESOURCES_H + +#include +#include "BannerFrame.h" +#include "StaticFrame.h" +#include "utils/U8Archive.h" + +class SystemMenuResources +{ +public: + static SystemMenuResources *Instance() { if(!instance) instance = new SystemMenuResources; return instance; } + + static void DestroyInstance() { delete instance; instance = NULL; } + + bool Init(); + bool IsLoaded() const { return isInited; } + + WiiFont *GetWbf1() const { return wbf1; } + WiiFont *GetWbf2() const { return wbf2; } + + const u8 *GetChanSelAsh() const { return chanSelAsh; } + u32 GetChanSelAshSize() const { return chanSelAshSize; } + + const u8 *GetChanTtlAsh() const { return chanTtlAsh; } + u32 GetChanTtlAshSize() const { return chanTtlAshSize; } + + const u8 *GetGCBannAsh() const { return GCBannAsh; } + u32 GetGCBannAshSize() const { return GCBannAshSize; } + + const u8 *GetSystemFont() const { return systemFont; } + u32 GetSystemFontSize() const { return systemFontSize; } + +protected: + SystemMenuResources(); + ~SystemMenuResources(); + + static SystemMenuResources *instance; + + bool InitFontArchive(void); + bool InitSystemFontArchive(bool korean, u8 *contentMap, u32 mapsize); + + bool isInited; + + //! banner font + WiiFont *wbf1; + WiiFont *wbf2; + u8 *wbf1Buffer; + u8 *wbf2Buffer; + + //! chanTtl.ash contains the frame and buttons that goes around the large banners + u8 *chanTtlAsh; + u32 chanTtlAshSize; + + //! chanSel.ash contains the channel grid layouts + u8 *chanSelAsh; + u32 chanSelAshSize; + + //! GCBann.ash contains the gamecube channel banner + u8 *GCBannAsh; + u32 GCBannAshSize; + + //! system font + u8 *systemFont; + u32 systemFontSize; + + // free data + void FreeEverything(); +}; + +#endif // SYSTEMMENURESOURCES_H diff --git a/source/ZipFile.cpp b/source/ZipFile.cpp new file mode 100644 index 0000000..665a0ca --- /dev/null +++ b/source/ZipFile.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** + * Copyright (C) 2009 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * ZipFile.cpp + * + * ZipFile Class + * for Wii-FileXplorer 2009 + * + * STILL UNCOMPLETE AND UNDER CONSTRUCTION + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include "prompts/ProgressWindow.h" +#include "FileOperations/fileops.h" +#include "ZipFile.h" +#include "language/gettext.h" + +ZipFile::ZipFile(const char *filepath) +{ + File = unzOpen(filepath); + if (File) this->LoadList(); +} + +ZipFile::~ZipFile() +{ + unzClose(File); +} + +bool ZipFile::LoadList() +{ + return true; +} + +bool ZipFile::FindFile(const char *file) +{ + if (!File) return false; + + char filename[MAXPATHLEN]; + + int ret = unzGoToFirstFile(File); + if (ret != UNZ_OK) return false; + + do + { + if(unzGetCurrentFileInfo(File, &cur_file_info, filename, sizeof(filename), NULL, 0, NULL, 0) != UNZ_OK) + continue; + + const char *realfilename = strrchr(filename, '/'); + if(!realfilename || strlen(realfilename) == 0) + realfilename = filename; + + if(strcasecmp(realfilename, file) == 0) + return true; + } + while(unzGoToNextFile(File) == UNZ_OK); + + return false; +} + +bool ZipFile::FindFilePart(const char *partfilename, std::string &realname) +{ + if (!File) return false; + + char filename[MAXPATHLEN]; + + int ret = unzGoToFirstFile(File); + if (ret != UNZ_OK) return false; + + do + { + if(unzGetCurrentFileInfo(File, &cur_file_info, filename, sizeof(filename), NULL, 0, NULL, 0) != UNZ_OK) + continue; + + if(strcasestr(filename, partfilename) != 0) + { + realname = filename; + return true; + } + } + while(unzGoToNextFile(File) == UNZ_OK); + + return false; +} + +bool ZipFile::ExtractAll(const char *dest) +{ + if (!File) return false; + + bool Stop = false; + + u32 blocksize = 1024 * 50; + u8 *buffer = new (std::nothrow) u8[blocksize]; + if (!buffer) return false; + + char writepath[MAXPATHLEN]; + char filename[MAXPATHLEN]; + memset(filename, 0, sizeof(filename)); + + int ret = unzGoToFirstFile(File); + if (ret != UNZ_OK) Stop = true; + + ProgressCancelEnable(true); + + while (!Stop) + { + if (unzGetCurrentFileInfo(File, &cur_file_info, filename, sizeof(filename), NULL, 0, NULL, 0) != UNZ_OK) Stop + = true; + + if (!Stop && filename[strlen(filename) - 1] != '/') + { + u32 uncompressed_size = cur_file_info.uncompressed_size; + + u32 done = 0; + char *pointer = NULL; + + ret = unzOpenCurrentFile(File); + + snprintf(writepath, sizeof(writepath), "%s/%s", dest, filename); + + pointer = strrchr(writepath, '/'); + int position = pointer - writepath + 2; + + char temppath[strlen(writepath)]; + snprintf(temppath, position, "%s", writepath); + + CreateSubfolder(temppath); + + if (ret == UNZ_OK) + { + FILE *pfile = fopen(writepath, "wb"); + + do + { + if(ProgressCanceled()) { + Stop = true; + break; + } + ShowProgress(tr( "Extracting files..." ), 0, pointer + 1, done, uncompressed_size, true, false); + + if (uncompressed_size - done < blocksize) blocksize = uncompressed_size - done; + + ret = unzReadCurrentFile(File, buffer, blocksize); + + if (ret == 0) break; + + fwrite(buffer, 1, blocksize, pfile); + + done += ret; + + } while (done < uncompressed_size); + + fclose(pfile); + unzCloseCurrentFile(File); + } + } + if (unzGoToNextFile(File) != UNZ_OK) Stop = true; + } + + delete[] buffer; + buffer = NULL; + + ProgressStop(); + ProgressCancelEnable(false); + + return true; +} diff --git a/source/ZipFile.h b/source/ZipFile.h new file mode 100644 index 0000000..980e047 --- /dev/null +++ b/source/ZipFile.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2009 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * ZipFile.cpp + * + * for Wii-FileXplorer 2009 + ***************************************************************************/ +#ifndef _ZIPFILE_H_ +#define _ZIPFILE_H_ + +#include +#include + +typedef struct +{ + u64 offset; // ZipFile offset + u64 length; // uncompressed file length in 64 bits for sizes higher than 4GB + bool isdir; // 0 - file, 1 - directory + char filename[256]; // full filename +} FileStructure; + +class ZipFile +{ + public: + //!Constructor + ZipFile(const char *filepath); + //!Destructor + ~ZipFile(); + //!Extract all files from a zip file to a directory + //!\param dest Destination path to where to extract + bool ExtractAll(const char *dest); + //!Find a file inside the zip and return if it is existent or not + bool FindFile(const char *filename); + //!Only needed a part of a filename to find the real one + bool FindFilePart(const char *partfilename, std::string &realname); + protected: + bool LoadList(); + unzFile File; + unz_file_info cur_file_info; + FileStructure *FileList; +}; + +#endif diff --git a/source/audio.cpp b/source/audio.cpp new file mode 100644 index 0000000..8d0b885 --- /dev/null +++ b/source/audio.cpp @@ -0,0 +1,35 @@ +/**************************************************************************** + * libwiigui Template + * Tantric 2009 + * + * audio.cpp + * Audio support + ***************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * InitAudio + * + * Initializes the Wii's audio subsystem + ***************************************************************************/ +void InitAudio() +{ + AUDIO_Init(NULL); + ASND_Init(); + ASND_Pause(0); +} + +/**************************************************************************** + * ShutdownAudio + * + * Shuts down audio subsystem. Useful to avoid unpleasant sounds if a + * crash occurs during shutdown. + ***************************************************************************/ +void ShutdownAudio() +{ + ASND_Pause(1); + ASND_End(); +} diff --git a/source/audio.h b/source/audio.h new file mode 100644 index 0000000..6efdf6d --- /dev/null +++ b/source/audio.h @@ -0,0 +1,15 @@ +/**************************************************************************** + * libwiigui Template + * Tantric 2009 + * + * audio.h + * Audio support + ***************************************************************************/ + +#ifndef _AUDIO_H_ +#define _AUDIO_H_ + +void InitAudio(); +void ShutdownAudio(); + +#endif diff --git a/source/banner/Animator.cpp b/source/banner/Animator.cpp new file mode 100644 index 0000000..573f5f3 --- /dev/null +++ b/source/banner/Animator.cpp @@ -0,0 +1,260 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include +#include "Animator.h" +#include "Layout.h" + +// load keyframes from a brlan file +u32 Animator::LoadAnimators(const RLAN_Header *header, Layout& layout, u8 key_set) +{ + u32 frame_count = 0; + + if (!header || header->magic != MAGIC_ANIMATION || header->endian != 0xFEFF || header->version != 0x0008) + return 0; // bad header + + // first section + const u8 *position = ((const u8 *) header) + header->offset; + + for(u32 i = 0; i < header->section_count; ++i) + { + section_t *section = (section_t *) position; + position += section->size; + + if (section->magic == MAGIC_PANE_ANIMATION_INFO) + { + const PAI1_Header *pai = (const PAI1_Header *) section; + u16 animator_count = pai->animator_count; + frame_count += pai->frame_count; + + // read animation file names + const u32 *nameOffsets = (const u32 *)(pai + 1); + for(u32 i = 0; i < pai->file_count; i++) + { + const char* name = (((const char *) nameOffsets) + nameOffsets[i]); + layout.AddPalette(name, key_set); + } + + const u32 *offsets = (const u32 *) (((const u8 *)section) + pai->entry_offset); + // read each animator + for(u32 n = 0; n < animator_count; n++) + { + const AnimatorHeader *animHdr = (const AnimatorHeader *) (((const u8 *)section) + offsets[n]); + std::string anim_name(animHdr->name, 0, 20); + + Animator* animator = animHdr->is_material ? + (Animator*) layout.FindMaterial(anim_name) : + (Animator*) layout.FindPane(anim_name); + + if (animator) + animator->LoadKeyFrames((const u8 *) animHdr, animHdr->tag_count, sizeof(AnimatorHeader), key_set); + } + } + else + { + gprintf("Unknown: %c%c%c%c\n", position[0], position[1], position[2], position[3]); + } + } + + return frame_count; +} + +void Animator::LoadKeyFrames(const u8 *file, u8 tag_count, u32 offset, u8 key_set) +{ + const u32 *tag_offsets = (const u32 *) (file + offset); + + for(u32 tag = 0; tag < tag_count; tag++) + { + const Anim_Header *animHdr = (const Anim_Header *) (file + tag_offsets[tag]); + + u32 animation_type = animHdr->animation_type; + u8 frame_count = animHdr->frame_count; + + const u32 *frame_offsets = (const u32 *) (animHdr + 1); + + for(u32 frame = 0; frame < frame_count; frame++) + { + const KeyFrame_Header *keyFrame = (const KeyFrame_Header *)(((const u8 *) animHdr) + frame_offsets[frame]); + const KeyType frame_type(static_cast(animation_type), keyFrame->index, keyFrame->target); + + switch (keyFrame->data_type) + { + // step key frame + case 0x01: + keys[key_set].step_keys[frame_type].Load((const u8 *) (keyFrame+1), keyFrame->key_count); + break; + + // hermite key frame + case 0x02: + keys[key_set].hermite_keys[frame_type].Load((const u8 *) (keyFrame+1), keyFrame->key_count); + break; + + default: + break; + } + } + } +} + +void Animator::SetFrame(FrameNumber frame_number, u8 key_set) +{ + std::map::iterator itr; + for(itr = keys[key_set].hermite_keys.begin(); itr != keys[key_set].hermite_keys.end(); itr++) + { + const KeyType& frame_type = itr->first; + const float frame_value = itr->second.GetFrame(frame_number); + + ProcessHermiteKey(frame_type, frame_value); + } + + std::map::iterator itr2; + for(itr2 = keys[key_set].step_keys.begin(); itr2 != keys[key_set].step_keys.end(); itr2++) + { + const KeyType& frame_type = itr2->first; + StepKeyHandler::KeyData const frame_data = itr2->second.GetFrame(frame_number); + + ProcessStepKey(frame_type, frame_data); + } +} + +void StepKeyHandler::Load(const u8 *file, u16 count) +{ + while (count--) + { + FrameNumber frame; + frame = *((FrameNumber *) file); + file += 4; + + KeyData& data = keys[frame]; + data.data1 = *file; + file++; + data.data2 = *file; + file++; + + file += 2; + } +} + +void HermiteKeyHandler::Load(const u8 *file, u16 count) +{ + while (count--) + { + std::pair pair; + + // read the frame number, value and slope + pair.first = *((FrameNumber *) file); + file += 4; + pair.second.value = *((float *) file); + file += 4; + pair.second.slope = *((float *) file); + file += 4; + + keys.insert(pair); + + //std::cout << "\t\t\t" "frame: " << frame << ' ' << keys[frame] << '\n'; + } +} + +StepKeyHandler::KeyData StepKeyHandler::GetFrame(FrameNumber frame_number) const +{ + // assuming not empty, a safe assumption currently + + // find the current frame, or the one after it + std::map::const_iterator frame_it = keys.lower_bound(frame_number); + + // current frame is higher than any keyframe, use the last keyframe + if (keys.end() == frame_it) + --frame_it; + + // if this is after the current frame and not the first keyframe, use the previous one + if (frame_number < frame_it->first && keys.begin() != frame_it) + --frame_it; + + return frame_it->second; +} + +float HermiteKeyHandler::GetFrame(FrameNumber frame_number) const +{ + // assuming not empty, a safe assumption currently + + // find the current keyframe, or the one after it + std::multimap::const_iterator next = keys.lower_bound(frame_number); + + // current frame is higher than any keyframe, use the last keyframe + if (keys.end() == next) + --next; + + std::multimap::const_iterator prev = next; + + // if this is after the current frame and not the first keyframe, use the previous one + if (frame_number < prev->first && keys.begin() != prev) + --prev; + + const float nf = next->first - prev->first; + if (fabs(nf) < 0.01) + { + // same frame numbers, just return the first's value + return prev->second.value; + } + else + { + // different frames, blend them together + // this is a "Cubic Hermite spline" apparently + + frame_number = (frame_number < prev->first) ? prev->first : + ((frame_number > next->first) ? next->first : frame_number); + + const float t = (frame_number - prev->first) / nf; + + // old curve-less code + //return prev->second.value + (next->second.value - prev->second.value) * t; + + // curvy code from marcan, :p + return + prev->second.slope * nf * (t + powf(t, 3) - 2 * powf(t, 2)) + + next->second.slope * nf * (powf(t, 3) - powf(t, 2)) + + prev->second.value * (1 + (2 * powf(t, 3) - 3 * powf(t, 2))) + + next->second.value * (-2 * powf(t, 3) + 3 * powf(t, 2)); + } +} + +void Animator::ProcessHermiteKey(const KeyType& type, float value) +{ +// std::cout << "unhandled key (" << GetName() << "): type: " << FourCC(type.type) +// << " index: " << (int)type.index +// << " target: " << (int)type.target +// << " value: " << value +// << '\n'; + gprintf("Animator::ProcessHermiteKey\n"); +} + +void Animator::ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data) +{ +// std::cout << "unhandled key (" << GetName() << "): type: " << FourCC(type.type) +// << " index: " << (int)type.index +// << " target: " << (int)type.target +// << " data:" << (int)data.data1 << " " << (int)data.data2 +// << '\n'; + gprintf("Animator::ProcessStepKey\n"); +} diff --git a/source/banner/Animator.h b/source/banner/Animator.h new file mode 100644 index 0000000..333c6ef --- /dev/null +++ b/source/banner/Animator.h @@ -0,0 +1,171 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef WII_BNR_ANIMATOR_H_ +#define WII_BNR_ANIMATOR_H_ + +#include +#include +#include +#include "BannerTools.h" + +typedef float FrameNumber; + +enum AnimationType +{ + ANIMATION_TYPE_PANE = MAKE_FOURCC('R', 'L', 'P', 'A'), + ANIMATION_TYPE_TEXTURE_SRT = MAKE_FOURCC('R', 'L', 'T', 'S'), + ANIMATION_TYPE_VISIBILITY = MAKE_FOURCC('R', 'L', 'V', 'I'), + ANIMATION_TYPE_VERTEX_COLOR = MAKE_FOURCC('R', 'L', 'V', 'C'), + ANIMATION_TYPE_MATERIAL_COLOR = MAKE_FOURCC('R', 'L', 'M', 'C'), + ANIMATION_TYPE_TEXTURE_PALETTE = MAKE_FOURCC('R', 'L', 'T', 'P'), + ANIMATION_TYPE_IND_MATERIAL = MAKE_FOURCC('R', 'L', 'I', 'M'), +}; + +struct RLAN_Header +{ + u32 magic; + u16 endian; + u16 version; + u32 file_size; + u16 offset; + u16 section_count; +} __attribute__((packed)); + +struct PAI1_Header +{ + u32 magic; + u32 section_size; + u16 frame_count; + u8 loop; + u8 pad; + u16 file_count; + u16 animator_count; + u32 entry_offset; +} __attribute__((packed)); + +struct AnimatorHeader +{ + char name[20]; + u8 tag_count; + u8 is_material; + u16 apad; +} __attribute__((packed)); + +struct Anim_Header +{ + u32 animation_type; + u8 frame_count; + u8 pad[3]; +} __attribute__((packed)); + +struct KeyFrame_Header +{ + u8 index; + u8 target; + u8 data_type; + u8 pad; + u16 key_count; + u16 pad1; + u32 offset; +} __attribute__((packed)); + +struct KeyType +{ + KeyType(AnimationType _type, u8 _index, u8 _target) + : type(_type) + , index(_index) + , target(_target) + {} + + bool operator<(const KeyType& rhs) const + { + return memcmp(this, &rhs, sizeof(*this)) < 0; + } + + const AnimationType type; + const u8 index, target; +}; + +class StepKeyHandler +{ +public: + void Load(const u8* file, u16 count); + + struct KeyData + { + u8 data1, data2; + }; + + KeyData GetFrame(FrameNumber frame_number) const; + +private: + std::map keys; +}; + +class HermiteKeyHandler +{ +public: + void Load(const u8* file, u16 count); + + struct KeyData + { + float value, slope; + }; + + float GetFrame(FrameNumber frame_number) const; + +private: + std::multimap keys; +}; + +class Layout; +class Animator +{ +public: + virtual ~Animator() {} + + static const u32 MAGIC_ANIMATION = MAKE_FOURCC('R', 'L', 'A', 'N'); + static const u32 MAGIC_PANE_ANIMATION_INFO = MAKE_FOURCC('p', 'a', 'i', '1'); + + static u32 LoadAnimators(const RLAN_Header *header, Layout& layout, u8 key_set); + + void LoadKeyFrames(const u8 *file, u8 tag_count, u32 offset, u8 key_set); + virtual void SetFrame(FrameNumber frame, u8 key_set); + +protected: + Animator() {} + + virtual void ProcessHermiteKey(const KeyType& type, float value); + virtual void ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data); +private: + + struct + { + std::map step_keys; + std::map hermite_keys; + } keys[2]; +}; + +#endif diff --git a/source/banner/Banner.cpp b/source/banner/Banner.cpp new file mode 100644 index 0000000..3aeabcc --- /dev/null +++ b/source/banner/Banner.cpp @@ -0,0 +1,175 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include +#include "SystemMenu/SystemMenuResources.h" +#include "utils/U8Archive.h" +#include "utils/LanguageCode.h" +#include "Banner.h" + +Banner::Banner() + : banner_bin(NULL) + , icon_bin(NULL) + , sound_bin(NULL) + , banner_bin_size(0) + , icon_bin_size(0) + , sound_bin_size(0) + , layout_banner(NULL) + , layout_icon(NULL) +{ +} + +Banner::~Banner() +{ + delete layout_banner; + delete layout_icon; + + if(banner_bin) + free(banner_bin); + if(icon_bin) + free(icon_bin); + if(sound_bin) + free(sound_bin); +} + +bool Banner::LoadBanner(const u8 *opening_bnr, u32 len) +{ + delete layout_banner; + if(banner_bin) + free(banner_bin); + + U8Archive openingArchive(opening_bnr, len); + + banner_bin = openingArchive.GetFileAllocated("/meta/banner.bin", &banner_bin_size); + if(!banner_bin) { + return false; + } + + layout_banner = LoadLayout(U8Archive(banner_bin, banner_bin_size), "banner", CONF_GetLanguageString()); + + return (layout_banner != NULL); +} + +bool Banner::LoadIcon(const u8 *opening_bnr, u32 len) +{ + delete layout_icon; + if(icon_bin) + free(icon_bin); + + U8Archive openingArchive(opening_bnr, len); + + icon_bin = openingArchive.GetFileAllocated("/meta/icon.bin", &icon_bin_size); + if(!icon_bin) { + return false; + } + + layout_icon = LoadLayout(U8Archive(icon_bin, icon_bin_size), "icon", CONF_GetLanguageString()); + + return (layout_icon != NULL); +} + +bool Banner::LoadSound(const u8 *opening_bnr, u32 len) +{ + if(sound_bin) + free(sound_bin); + + U8Archive openingArchive(opening_bnr, len); + + sound_bin = openingArchive.GetFileAllocated("/meta/sound.bin", &sound_bin_size); + if(!sound_bin) { + return false; + } + return true; +} + +Layout* Banner::LoadLayout(const U8Archive &archive, const std::string& lyt_name, const std::string &language) +{ + const u8 *brlyt = archive.GetFile("/arc/blyt/" + lyt_name + ".brlyt"); + if(!brlyt) { + return NULL; + } + + Layout *layout = new Layout; + layout->Load(brlyt); + + u32 length_start = 0, length_loop = 0; + + const u8 *brlan_start = archive.GetFile("/arc/anim/" + lyt_name + "_Start.brlan"); + const u8 *brlan_loop = 0; + + // try the alternative file + if(!brlan_start) + brlan_start = archive.GetFile("/arc/anim/" + lyt_name + "_In.brlan"); + + if (brlan_start) + length_start = Animator::LoadAnimators((const RLAN_Header *)brlan_start, *layout, 0); + + brlan_loop = archive.GetFile("/arc/anim/" + lyt_name + ".brlan"); + if(!brlan_loop) + brlan_loop = archive.GetFile("/arc/anim/" + lyt_name + "_Loop.brlan"); + if(!brlan_loop) + brlan_loop = archive.GetFile("/arc/anim/" + lyt_name + "_Rso0.brlan");// added for "artstyle" wiiware + + if (brlan_loop) + length_loop = Animator::LoadAnimators((const RLAN_Header *)brlan_loop, *layout, 1); + + // load textures after loading the animations so we get the list of tpl filenames from the brlans + layout->LoadTextures(archive); + layout->LoadFonts(archive); + layout->SetLanguage(language); + layout->SetLoopStart(length_start); + layout->SetLoopEnd(length_start + length_loop); + layout->SetFrame(0); + + return layout; +} + +void Banner::swap(Banner &ban) +{ + u8 *tmp_banner_bin = this->banner_bin; + u8 *tmp_icon_bin = this->icon_bin; + u8 *tmp_sound_bin = this->sound_bin; + u32 tmp_banner_bin_size = this->banner_bin_size; + u32 tmp_icon_bin_size = this->icon_bin_size; + u32 tmp_sound_bin_size = this->sound_bin_size; + Layout *tmp_layout_banner = this->layout_banner; + Layout *tmp_layout_icon = this->layout_icon; + + this->banner_bin = ban.banner_bin; + this->icon_bin = ban.icon_bin; + this->sound_bin = ban.sound_bin; + this->banner_bin_size = ban.banner_bin_size; + this->icon_bin_size = ban.icon_bin_size; + this->sound_bin_size = ban.sound_bin_size; + this->layout_banner = ban.layout_banner; + this->layout_icon = ban.layout_icon; + + ban.banner_bin = tmp_banner_bin; + ban.icon_bin = tmp_icon_bin; + ban.sound_bin = tmp_sound_bin; + ban.banner_bin_size = tmp_banner_bin_size; + ban.icon_bin_size = tmp_icon_bin_size; + ban.sound_bin_size = tmp_sound_bin_size; + ban.layout_banner = tmp_layout_banner; + ban.layout_icon = tmp_layout_icon; +} diff --git a/source/banner/Banner.h b/source/banner/Banner.h new file mode 100644 index 0000000..3b781c8 --- /dev/null +++ b/source/banner/Banner.h @@ -0,0 +1,55 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef _BANNER_H_ +#define _BANNER_H_ + +#include "Layout.h" + +class Banner +{ +public: + Banner(); + virtual ~Banner(); + + bool LoadBanner(const u8 *opening_bnr, u32 len); + bool LoadIcon(const u8 *opening_bnr, u32 len); + bool LoadSound(const u8 *opening_bnr, u32 len); + + Layout *getBanner() const { return layout_banner; } + Layout *getIcon() const { return layout_icon; } + const u8 *getSound() const { return sound_bin; } + u32 getSoundSize() const { return sound_bin_size; } + + void swap(Banner &ban); + +protected: + Layout* LoadLayout(const U8Archive &banner_file, const std::string& lyt_name, const std::string &language); + + u8 *banner_bin, *icon_bin, *sound_bin; + u32 banner_bin_size, icon_bin_size, sound_bin_size; + Layout *layout_banner, *layout_icon; +}; + +#endif diff --git a/source/banner/BannerAsync.cpp b/source/banner/BannerAsync.cpp new file mode 100644 index 0000000..163d1f7 --- /dev/null +++ b/source/banner/BannerAsync.cpp @@ -0,0 +1,234 @@ +/* +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include +#include +#include +#include +#include "settings/CSettings.h" +#include "OpeningBNR.hpp" +#include "BannerAsync.h" + +vector BannerAsync::List; +queue BannerAsync::DeleteList; +lwp_t BannerAsync::Thread = LWP_THREAD_NULL; +mutex_t BannerAsync::ListLock = LWP_THREAD_NULL; +BannerAsync * BannerAsync::InUse = NULL; +bool BannerAsync::SleepThread = false; +bool BannerAsync::CloseThread = false; + + +BannerAsync::BannerAsync(const discHdr *hdr) + : header(hdr) +{ + ThreadInit(); + ThreadAdd(this); +} + +BannerAsync::~BannerAsync() +{ + ThreadRemove(this); + while(InUse == this) + usleep(100); +} + +void BannerAsync::ThreadAdd(BannerAsync *banner) +{ + LWP_MutexLock(ListLock); + List.push_back(banner); + LWP_MutexUnlock(ListLock); + LWP_ResumeThread(Thread); +} + +void BannerAsync::ThreadRemove(BannerAsync *banner) +{ + LWP_MutexLock(ListLock); + for(u32 i = 0; i < List.size(); ++i) + { + if(List[i] == banner) + { + List.erase(List.begin()+i); + break; + } + } + LWP_MutexUnlock(ListLock); +} + +void BannerAsync::RemoveBanner(BannerAsync *banner) +{ + LWP_MutexLock(ListLock); + DeleteList.push(banner); + LWP_MutexUnlock(ListLock); + LWP_ResumeThread(Thread); +} + +void BannerAsync::ClearQueue() +{ + LWP_MutexLock(ListLock); + List.clear(); + LWP_MutexUnlock(ListLock); +} + +void BannerAsync::PushFront(BannerAsync *banner) +{ + if(banner == InUse) + return; + + LWP_MutexLock(ListLock); + for(u32 i = 0; i < List.size(); ++i) + { + if(List[i] == banner) + { + List.erase(List.begin()+i); + break; + } + } + List.insert(List.begin(), banner); + LWP_MutexUnlock(ListLock); + LWP_ResumeThread(Thread); +} + +void * BannerAsync::BannerAsyncThread(void *arg) +{ + while(!CloseThread) + { + while(!List.empty() && !CloseThread && !SleepThread) + { + LWP_MutexLock(ListLock); + //! Delete the delete queue + while(!DeleteList.empty()) + { + delete DeleteList.front(); + DeleteList.pop(); + } + //! Check if there is still something to do + if(List.empty()) + { + LWP_MutexUnlock(ListLock); + continue; + } + + //! Get first entry and pop + InUse = List.front(); + List.erase(List.begin()); + LWP_MutexUnlock(ListLock); + + if (!InUse || !InUse->header) + continue; + + const u8 * banner = NULL; + u32 bannerSize = 0; + + if((InUse->header->type == TYPE_GAME_GC_IMG) || (InUse->header->type == TYPE_GAME_GC_DISC) || (InUse->header->type == TYPE_GAME_GC_EXTRACTED)) + { + //! first see if a cache file is present and load that if needed + if(BNRInstance::Instance()->Load(InUse->header)) + { + banner = BNRInstance::Instance()->Get(); + bannerSize = BNRInstance::Instance()->GetSize(); + } + else + { + //! load our default one + CustomBanner *gcBanner = BNRInstance::Instance()->CreateGCIcon(InUse->header); + if(gcBanner) { + InUse->swap(*gcBanner); + delete gcBanner; + } + } + } + else + { + BNRInstance::Instance()->Load(InUse->header); + banner = BNRInstance::Instance()->Get(); + bannerSize = BNRInstance::Instance()->GetSize(); + } + + if(banner != NULL && bannerSize > 0) + InUse->LoadIcon(banner, bannerSize); + + InUse = NULL; + } + + //! Delete the delete queue here as well in case list was empty + if(!DeleteList.empty()) + { + LWP_MutexLock(ListLock); + while(!DeleteList.empty()) + { + delete DeleteList.front(); + DeleteList.pop(); + } + LWP_MutexUnlock(ListLock); + } + + if(!CloseThread) + LWP_SuspendThread(Thread); + } + + return NULL; +} + +void BannerAsync::ResumeThread(void) +{ + SleepThread = false; + + if(Thread != LWP_THREAD_NULL) + LWP_ResumeThread(Thread); +} + +void BannerAsync::HaltThread(void) +{ + SleepThread = true; + + if(Thread == LWP_THREAD_NULL) + return; + + // wait for thread to finish + while (!LWP_ThreadIsSuspended(Thread)) + usleep(100); +} + +void BannerAsync::ThreadInit(void) +{ + if (Thread == LWP_THREAD_NULL) + { + LWP_MutexInit(&ListLock, false); + LWP_CreateThread(&Thread, BannerAsyncThread, NULL, NULL, 65536, 70); + } +} + +void BannerAsync::ThreadExit(void) +{ + if(Thread != LWP_THREAD_NULL) + { + ClearQueue(); + CloseThread = true; + LWP_ResumeThread(Thread); + LWP_JoinThread(Thread, NULL); + LWP_MutexUnlock(ListLock); + LWP_MutexDestroy(ListLock); + Thread = LWP_THREAD_NULL; + ListLock = LWP_MUTEX_NULL; + } +} + diff --git a/source/banner/BannerAsync.h b/source/banner/BannerAsync.h new file mode 100644 index 0000000..49ffdb2 --- /dev/null +++ b/source/banner/BannerAsync.h @@ -0,0 +1,64 @@ +/* +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef _BANNERASYNC_H_ +#define _BANNERASYNC_H_ + +#include +#include +#include +#include "usbloader/GameList.h" +#include "Banner.h" + +using namespace std; + +class BannerAsync : public Banner +{ +public: + + BannerAsync( const discHdr *header ); + virtual ~BannerAsync(); + + static void ThreadInit(void); + static void ThreadExit(void); + static void HaltThread(void); + static void ResumeThread(void); + static void RemoveBanner(BannerAsync *banner); + static void ClearQueue(); + static void PushFront(BannerAsync *banner); +private: + const discHdr *header; + + static void * BannerAsyncThread(void *arg); + static void ThreadAdd(BannerAsync* banner); + static void ThreadRemove(BannerAsync* banner); + + static vector List; + static queue DeleteList; + static lwp_t Thread; + static mutex_t ListLock; + static BannerAsync * InUse; + static bool SleepThread; + static bool CloseThread; +}; + +#endif /*_GUIIMAGEASYNC_H_*/ diff --git a/source/banner/BannerTools.h b/source/banner/BannerTools.h new file mode 100644 index 0000000..fe22c69 --- /dev/null +++ b/source/banner/BannerTools.h @@ -0,0 +1,62 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef BANNER_TOOLS_H_ +#define BANNER_TOOLS_H_ + +#include +#include "utils/gx_addons.h" +#include "gecko.h" + +#define MAKE_FOURCC(a, b, c, d) ((a) * (1 << 24) + (b) * (1 << 16) + (c) * (1 << 8) + (d) * (1 << 0)) + +typedef struct +{ + u32 magic; + u32 size; +} section_t; + +typedef struct +{ + float x, y; +} Vec2f; + +typedef struct +{ + float x, y, z; +} Vec3f; + +#define ALIGN32(x) (((x) + 31) & ~31) +#define LIMIT(x, min, max) \ + ({ \ + typeof( x ) _x = x; \ + typeof( min ) _min = min; \ + typeof( max ) _max = max; \ + ( ( ( _x ) < ( _min ) ) ? ( _min ) : ( ( _x ) > ( _max ) ) ? ( _max) : ( _x ) ); \ + }) + +#define MultiplyAlpha(a1, a2) (u8)((u16) (a1) * (u16) (a2) / 0xFF) +#define FLOAT_2_U8(x) ((u8)((x) > 255.0f ? 255.0f : ((x) < 0.0f ? 0.0f : (x) + 0.5f))) +#define FLOAT_2_S16(x) ((s16)((x) > 32767.0f ? 32767.0f : ((x) < -32768.0f ? 32768.0f : (x) + 0.5f))) + +#endif diff --git a/source/banner/CustomBanner.cpp b/source/banner/CustomBanner.cpp new file mode 100644 index 0000000..1fc1b84 --- /dev/null +++ b/source/banner/CustomBanner.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 "CustomBanner.h" +#include "ImageOperations/TextureConverter.h" +#include "utils/StringTools.h" + + +CustomBanner::CustomBanner() +{ +} + +CustomBanner::~CustomBanner() +{ + for(u32 i = 0; i < text_list.size(); i++) + delete [] text_list[i]; +} + +void CustomBanner::SetBannerTexture(const char *tex_name, const u8 *data, float width, float height, u8 fmt) +{ + if(!layout_banner) + return; + + Texture *texture = layout_banner->FindTexture( tex_name ); + if(texture != NULL && data != NULL) { + texture->LoadTextureData(data, width, height, fmt); + } +} + +void CustomBanner::SetBannerText(const char *text_name, const char *text) +{ + if(!layout_banner || !text) + return; + + Textbox *tbox = dynamic_cast(layout_banner->FindPane(text_name)); + if(tbox) + { + const wchar_t *wText = wfmt("%s", text); + int len = wcslen(wText); + u16 *text_char16 = new u16[len+1]; + + for(int i = 0; i < len; i++) + text_char16[i] = (u16) wText[i]; + text_char16[len] = 0; + + tbox->SetText(text_char16); + text_list.push_back(text_char16); + } +} + +void CustomBanner::SetIconTexture(const char *tex_name, const u8 *data, float width, float height, u8 fmt) +{ + if(!layout_icon) + return; + + Texture *texture = layout_icon->FindTexture( tex_name ); + if(texture != NULL && data != NULL) { + texture->LoadTextureData(data, width, height, fmt); + } +} + +u8 *CustomBanner::LoadTextureFromPng(const u8 * img, u32 imgSize, int *width, int *height) +{ + if(!img) + return NULL; + + // load png + gdImagePtr gdImg = gdImageCreateFromPngPtr(imgSize, (u8 *)img); + if(!gdImg) + return NULL; + + u8 *texture = GDImageToRGBA8(&gdImg, width, height); + + // free image object + gdImageDestroy( gdImg ); + + return texture; +} + +void CustomBanner::SetBannerPngImage(const char *tex_name, const u8 * img, u32 imgSize) +{ + int pngWidth; + int pngHeight; + + u8 * texData = LoadTextureFromPng(img, imgSize, &pngWidth, &pngHeight); + + if(texData) + { + SetBannerTexture(tex_name, texData, pngWidth, pngHeight, GX_TF_RGBA8); + free(texData); + } +} + +void CustomBanner::SetIconPngImage(const char *tex_name, const u8 * img, u32 imgSize) +{ + int pngWidth; + int pngHeight; + + u8 * texData = LoadTextureFromPng(img, imgSize, &pngWidth, &pngHeight); + + if(texData) + { + SetIconTexture(tex_name, texData, pngWidth, pngHeight, GX_TF_RGBA8); + free(texData); + } +} + +void CustomBanner::SetBannerTextureScale(float scale) +{ + Pane *pane = layout_banner->FindPane("HBPic"); + if(pane) + pane->SetScale(scale); + + pane = layout_banner->FindPane("HBPicSha"); + if(pane) + pane->SetScale(scale); +} + +void CustomBanner::SetBannerPaneVisible(const char *pane_name, bool visible) +{ + Pane *pane = layout_banner->FindPane(pane_name); + if(pane) + pane->SetVisible(visible); +} diff --git a/source/banner/CustomBanner.h b/source/banner/CustomBanner.h new file mode 100644 index 0000000..f3d4eea --- /dev/null +++ b/source/banner/CustomBanner.h @@ -0,0 +1,43 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 CUSTOM_BANNER_H_ +#define CUSTOM_BANNER_H_ + +#include +#include "Banner.h" + +using namespace std; + +class CustomBanner : public Banner +{ +public: + + CustomBanner(); + virtual ~CustomBanner(); + void SetBannerText(const char *text_name, const char *text); + void SetBannerPngImage(const char *tex_name, const u8 * img, u32 imgSize); + void SetIconPngImage(const char *tex_name, const u8 * img, u32 imgSize); + void SetBannerTexture(const char *tex_name, const u8 *data, float width, float height, u8 fmt); + void SetIconTexture(const char *tex_name, const u8 *data, float width, float height, u8 fmt); + void SetBannerTextureScale(float scale); + void SetBannerPaneVisible(const char *pane, bool visible); +private: + u8 *LoadTextureFromPng(const u8 * img, u32 imgSize, int *width, int *height); + vector text_list; +}; + +#endif /*CUSTOM_BANNER_H_*/ diff --git a/source/banner/Layout.cpp b/source/banner/Layout.cpp new file mode 100644 index 0000000..4cf4b91 --- /dev/null +++ b/source/banner/Layout.cpp @@ -0,0 +1,391 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include "SystemMenu/SystemMenuResources.h" +#include "Layout.h" +#include "WiiFont.h" + +Layout::Layout() + : header(0) +{ +} + +Layout::~Layout() +{ + for(u32 i = 0; i < panes.size(); ++i) + delete panes[i]; + + for(u32 i = 0; i < resources.materials.size(); ++i) + delete resources.materials[i]; + + for(u32 i = 0; i < resources.textures.size(); ++i) + delete resources.textures[i]; + + for(u32 i = 0; i < resources.fonts.size(); ++i) { + + if(resources.fonts[i] == SystemMenuResources::Instance()->GetWbf1() || + resources.fonts[i] == SystemMenuResources::Instance()->GetWbf2()) + continue; + + delete resources.fonts[i]; + } +} + +bool Layout::Load(const u8 *brlyt) +{ + if(!brlyt) + return false; + + const BRLYT_Header *brlytFile = (const BRLYT_Header *) brlyt; + + if(brlytFile->magic != BRLYT_MAGIC || brlytFile->version != BRLYT_VERSION) + return false; + + Group* last_group = NULL; + std::stack*> group_stack; + group_stack.push(&groups); + + Pane* last_pane = NULL; + std::stack*> pane_stack; + pane_stack.push(&panes); + + const u8 *position = brlyt + brlytFile->header_len; + + for(u32 i = 0; i < brlytFile->section_count; ++i) + { + section_t *section = (section_t *) position; + position += section->size; + + if(section->magic == Layout::MAGIC) + { + header = (Layout::Header *) (section + 1); + } + else if (section->magic == TextureList::MAGIC) + { + const LytItemList *txl1 = (const LytItemList *) (section+1); + const char *nameoffset = ((const char *)(txl1+1)); + const LytStringTable *stringTable = (const LytStringTable *) (((const u8 *)(txl1+1))+txl1->offset_to_first); + + for(u32 i = 0; i < txl1->num_items; ++i) + { + const char *name = nameoffset+stringTable[i].offset_filename; + + Texture *texture = new Texture; + texture->setName(name); + resources.textures.push_back(texture); + } + } + else if (section->magic == MaterialList::MAGIC) + { + const LytItemList *mat1 = (const LytItemList *) (section+1); + const u32 *mat_offsets = (const u32 *) (((const u8 *)(mat1+1))+mat1->offset_to_first); + + for(u32 i = 0; i < mat1->num_items; ++i) + { + Material *material = new Material; + material->Load((Material::Header *) (((const u8 *) section)+mat_offsets[i])); + resources.materials.push_back(material); + } + } + else if (section->magic == FontList::MAGIC) + { + // load font list + const LytItemList *fnl1 = (const LytItemList *) (section+1); + const char *nameoffset = ((const char *)(fnl1+1)); + const LytStringTable *stringTable = (const LytStringTable *) (((const u8 *)(fnl1+1))+fnl1->offset_to_first); + + for(u32 i = 0; i < fnl1->num_items; i++) + { + const char *name = nameoffset+stringTable[i].offset_filename; + + WiiFont *font; + + if(strcmp(name, "wbf1.brfna") == 0 || strcmp(name, "RevoIpl_RodinNTLGPro_DB_32_I4.brfnt") == 0) { + //! 1st system font or alias for it + font = SystemMenuResources::Instance()->GetWbf1(); + if(!font) continue; + } + else if(strcmp(name, "wbf2.brfna") == 0) { + //! 2nd system font + font = SystemMenuResources::Instance()->GetWbf2(); + if(!font) continue; + } + else { + //! font from banner + font = new WiiFont; + font->SetName(name); + } + resources.fonts.push_back(font); + } + } + else if (section->magic == Pane::MAGIC) + { + Pane* pane = new Pane; + pane->Load((Pane::Header *) section); + pane_stack.top()->push_back(last_pane = pane); + } + else if (section->magic == Bounding::MAGIC) + { + Bounding* pane = new Bounding; + pane->Load((Pane::Header *) section); + pane_stack.top()->push_back(last_pane = pane); + } + else if (section->magic == Picture::MAGIC) + { + Picture* pane = new Picture; + pane->Load((Pane::Header *) section); + pane_stack.top()->push_back(last_pane = pane); + } + else if (section->magic == Window::MAGIC) + { + Window* pane = new Window; + pane->Load((Pane::Header *) section); + pane_stack.top()->push_back(last_pane = pane); + } + else if (section->magic == Textbox::MAGIC) + { + Textbox* pane = new Textbox; + pane->Load((Pane::Header *) section); + pane_stack.top()->push_back(last_pane = pane); + } + else if (section->magic == Layout::MAGIC_PANE_PUSH) + { + if (last_pane) + pane_stack.push(&last_pane->panes); + } + else if (section->magic == Layout::MAGIC_PANE_POP) + { + if (pane_stack.size() > 1) + pane_stack.pop(); + } + else if (section->magic == Group::MAGIC) + { + const char *grp = (const char *) (section + 1); + std::string group_name(grp, 0, Layout::Group::NAME_LENGTH); + Group& group_ref = (*group_stack.top())[group_name]; + grp += Layout::Group::NAME_LENGTH; + + u16 sub_count = *(u16 *) grp; + grp += 4; // 2 bytes reserved + + while (sub_count--) + { + std::string pane_name(grp, 0, Layout::Group::NAME_LENGTH); + group_ref.panes.push_back(pane_name); + grp += Layout::Group::NAME_LENGTH; + } + + last_group = &group_ref; + } + else if (section->magic == Layout::MAGIC_GROUP_PUSH) + { + if (last_group) + group_stack.push(&last_group->groups); + } + else if (section->magic == Layout::MAGIC_GROUP_POP) + { + if (group_stack.size() > 1) + group_stack.pop(); + } + else { + gprintf("Uknown layout section: %08X\n", section->magic); + } + } + return true; +} + +bool Layout::LoadTextures(const U8Archive &banner_file) +{ + bool success = false; + + for(u32 i = 0; i < resources.textures.size(); ++i) + { + const u8 *file = banner_file.GetFile("/arc/timg/" + resources.textures[i]->getName()); + if (file) + resources.textures[i]->Load(file); + else + success = false; + } + + return success; +} + +bool Layout::LoadFonts(const U8Archive &banner_file) +{ + bool success = false; + + for(u32 i = 0; i < resources.fonts.size(); ++i) + { + if(resources.fonts[i]->IsLoaded()) + continue; + + const u8 *file = banner_file.GetFile("/arc/font/" + resources.fonts[i]->getName()); + if (file) + resources.fonts[i]->Load(file); + else + success = false; + } + + return success; +} + +void Layout::Render(Mtx &modelview, const Vec2f &ScreenProps, bool widescreen, u8 render_alpha) const +{ + if(!header) + return; + + Mtx mv; + // we draw inverse + guMtxScaleApply(modelview, mv, 1.0f, -1.0f, 1.0f); + + // centered draw + if(header->centered) + guMtxTransApply(mv, mv, ScreenProps.x * 0.5f, ScreenProps.y * 0.5f, 0.f); + + // render all panes + for(u32 i = 0; i < panes.size(); ++i) + panes[i]->Render(resources, render_alpha, mv, widescreen); +} + +void Layout::SetFrame(FrameNumber frame_number) +{ + frame_current = frame_number; + + const u8 key_set = (frame_current >= frame_loop_start); + if (key_set) + frame_number -= frame_loop_start; + + resources.cur_set = key_set; + + for(u32 i = 0; i < panes.size(); ++i) + panes[i]->SetFrame(frame_number, key_set); + + for(u32 i = 0; i < resources.materials.size(); ++i) + resources.materials[i]->SetFrame(frame_number, key_set); +} + +void Layout::AdvanceFrame() +{ + ++frame_current; + + if (frame_current >= frame_loop_end) + frame_current = frame_loop_start; + + SetFrame(frame_current); +} + +void Layout::SetLanguage(const std::string& language) +{ + if(!header) + return; + + // check if that language is found + bool lang_found = false; + + // hide panes of non-matching languages + std::map::iterator itr; + for(itr = groups["RootGroup"].groups.begin(); itr != groups["RootGroup"].groups.end(); itr++) + { + // check if that language exists + if(!lang_found && itr->first == language) + lang_found = true; + + // some hax, there are some odd "Rso0" "Rso1" groups that shouldn't be hidden + // only the 3 character language groups should be + if (itr->first != language && itr->first.length() == 3) + { + std::list::iterator itr2; + for(itr2 = itr->second.panes.begin(); itr2 != itr->second.panes.end(); itr2++) + { + Pane* const found = FindPane(*itr2); + if (found) + found->SetHide(true); + } + } + } + + // show english if langauge is not found + if(!lang_found && language != "ENG") + { + SetLanguage("ENG"); + return; + } + + // unhide panes of matching language, some banners list language specific panes in multiple language groups + std::list::iterator itr2; + for(itr2 = groups["RootGroup"].groups[language].panes.begin(); itr2 != groups["RootGroup"].groups[language].panes.end(); itr2++) + { + Pane* const found = FindPane(*itr2); + if (found) + { + found->SetHide(false); + found->SetVisible(true); // all games with languages start as visible + } + } +} + +void Layout::AddPalette(const std::string &name, u8 key_set) +{ + resources.palettes[key_set].push_back(name); + + if(FindTexture(name) != 0) + return; + + Texture *texture = new Texture; + texture->setName(name); + resources.textures.push_back(texture); +} + +Pane* Layout::FindPane(const std::string& find_name) +{ + for(u32 i = 0; i < panes.size(); ++i) + { + Pane* found = panes[i]->FindPane(find_name); + if(found) + return found; + } + + return NULL; +} + +Material* Layout::FindMaterial(const std::string& find_name) +{ + for(u32 i = 0; i < resources.materials.size(); ++i) + { + if (find_name.compare(0, 20, resources.materials[i]->getName()) == 0) + return resources.materials[i]; + } + + return NULL; +} + +Texture* Layout::FindTexture(const std::string& find_name) +{ + for(u32 i = 0; i < resources.textures.size(); ++i) + { + if (find_name == resources.textures[i]->getName()) + return resources.textures[i]; + } + + return NULL; +} diff --git a/source/banner/Layout.h b/source/banner/Layout.h new file mode 100644 index 0000000..a1cac47 --- /dev/null +++ b/source/banner/Layout.h @@ -0,0 +1,144 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef LAYOUT_H_ +#define LAYOUT_H_ + +#include +#include +#include +#include +#include + +#include "Texture.h" +#include "Material.h" +#include "Pane.h" +#include "Picture.h" +#include "Window.h" +#include "WiiFont.h" +#include "Textbox.h" +#include "utils/U8Archive.h" + +typedef std::vector PaletteList; + +struct BannerResources +{ + MaterialList materials; + TextureList textures; + FontList fonts; + PaletteList palettes[2]; + u8 cur_set; +}; + +class Layout +{ +public: + Layout(); + virtual ~Layout(); + + static const u32 BRLYT_MAGIC = MAKE_FOURCC('R', 'L', 'Y', 'T'); + static const u32 BRLYT_VERSION = 0xFEFF0008; + static const u32 MAGIC = MAKE_FOURCC('l', 'y', 't', '1'); + static const u32 MAGIC_PANE_PUSH = MAKE_FOURCC('p', 'a', 's', '1'); + static const u32 MAGIC_PANE_POP = MAKE_FOURCC('p', 'a', 'e', '1'); + static const u32 MAGIC_GROUP_PUSH = MAKE_FOURCC('g', 'r', 's', '1'); + static const u32 MAGIC_GROUP_POP = MAKE_FOURCC('g', 'r', 'e', '1'); + + bool Load(const u8 *brlyt); + bool LoadTextures(const U8Archive &banner_file); + bool LoadFonts(const U8Archive &banner_file); + + void Render(Mtx &modelview, const Vec2f &ScreenProps, bool widescreen, u8 render_alpha = 0xFF) const; + + FrameNumber GetFrame() const { return frame_current; } + void SetFrame(FrameNumber frame_number); + void AdvanceFrame(); + + void SetLoopStart(FrameNumber loop_start) { frame_loop_start = loop_start; } + void SetLoopEnd(FrameNumber loop_end) { frame_loop_end = loop_end; } + + float GetWidth() const { return header->width; } + void SetWidth(float _width) { header->width = _width; } + + float GetHeight() const { return header->height; } + void SetHeight(float _height) { header->height = _height; } + + bool isCentered() const { return header->centered; } + + void SetLanguage(const std::string& language); + + Pane* FindPane(const std::string& name); + Material* FindMaterial(const std::string& name); + Texture *FindTexture(const std::string &name); + + void AddPalette(const std::string &name, u8 key_set); +protected: + struct BRLYT_Header + { + u32 magic; + u32 version; + u32 filesize; + u16 header_len; + u16 section_count; + } __attribute__((packed)); + + struct Header + { + u8 centered; + u8 pad[3]; + float width; + float height; + } __attribute__((packed)); + + struct LytItemList + { + u16 num_items; + u16 offset_to_first; + } __attribute__((packed)); + + struct LytStringTable + { + u32 offset_filename; + u32 pad; + } __attribute__((packed)); + + struct Group + { + static const u32 MAGIC = MAKE_FOURCC('g', 'r', 'p', '1'); + static const u32 NAME_LENGTH = 0x10; + + std::map groups; + std::list panes; + }; + + Layout::Header *header; + + BannerResources resources; + PaneList panes; + + FrameNumber frame_current, frame_loop_start, frame_loop_end; + + std::map groups; +}; + +#endif diff --git a/source/banner/Material.cpp b/source/banner/Material.cpp new file mode 100644 index 0000000..e114322 --- /dev/null +++ b/source/banner/Material.cpp @@ -0,0 +1,591 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok and giantpune + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include +#include +#include "Layout.h" +#include "Material.h" + +Material::Material() + : flags(0) + , texture_maps(0) + , texture_srts(0) + , texture_coord_gens(0) + , chan_control(0) + , mat_color(0) + , tev_swap_table(0) + , ind_srt(0) + , ind_stage(0) + , tev_stages(0) + , alpha_compare(0) + , blend_mode(0) + , header(0) +{ + for( int i = 0; i < 8; i++ ) + palette_texture[i] = DEFAULT_PALETTE; +} + +void Material::Load(Material::Header *file) +{ + header = file; + + // Flags + flags = (MatFlags *) &header->flags; + + flags->texture_map = std::min((int)MAX_TEX_MAP, (int)flags->texture_map); + flags->texture_srt = std::min((int)MAX_TEX_SRT, (int)flags->texture_srt); + flags->texture_coord_gen = std::min((int)MAX_TEX_GEN, (int)flags->texture_coord_gen); + flags->ind_srt = flags->ind_srt; + flags->ind_stage = std::min((int)MAX_IND_STAGES, (int)flags->ind_stage); + flags->tev_stages = std::min((int)MAX_TEV_STAGES, (int)flags->tev_stages); + + u8 *buf_offset = (u8 *) (header+1); + + // texture map + if(flags->texture_map) + { + texture_maps = (TextureMap *) buf_offset; + buf_offset += sizeof(TextureMap) * flags->texture_map; + } + + // texture srt + if(flags->texture_srt) + { + texture_srts = (TextureSrt *) buf_offset; + buf_offset += sizeof(TextureSrt) * flags->texture_srt; + } + + // texture coord gen + if(flags->texture_coord_gen) + { + texture_coord_gens = (TextureCoordGen *) buf_offset; + buf_offset += sizeof(TextureCoordGen) * flags->texture_coord_gen; + } + + // channel control + if (flags->channel_control) + { + chan_control = (ChannelControl *) buf_offset; + buf_offset += sizeof(ChannelControl); + } + + // material color + if (flags->material_color) + { + mat_color = (GXColor *) buf_offset; + buf_offset += sizeof(GXColor); + } + //else Default to 0xFFFFFFFF + + // tev swap table + if (flags->tev_swap_table) + { + tev_swap_table = (TevSwap *) buf_offset; + buf_offset += sizeof(TevSwap) * 4; + } + + // ind srt + if(flags->ind_srt) + { + ind_srt = (IndSrt *) buf_offset; + buf_offset += sizeof(IndSrt) * flags->ind_srt; + } + + // ind stage + if(flags->ind_stage) + { + ind_stage = (IndStage *) buf_offset; + buf_offset += sizeof(IndStage) * flags->ind_stage; + } + + // tev stage + if(flags->tev_stages) + { + tev_stages = (TevStage *) buf_offset; + buf_offset += sizeof(TevStage) * flags->tev_stages; + } + + // alpha compare + if (flags->alpha_compare) + { + alpha_compare = (AlphaCompareModes *) buf_offset; + buf_offset += sizeof(AlphaCompareModes); + } + + // blend mode + if (flags->blend_mode) + { + blend_mode = (BlendModes *) buf_offset; + buf_offset += sizeof(BlendModes); + } +} + +inline void Material::ApplyChannelControl(u8 render_alpha, bool &modulate_colors) const +{ + if(flags->channel_control) + { + GX_SetChanCtrl(0, 0, 0, chan_control->color_matsrc, 0, 0, 2 ); + GX_SetChanCtrl(2, 0, 0, chan_control->alpha_matsrc, 0, 0, 2 ); + + if(chan_control->alpha_matsrc != 1 && chan_control->color_matsrc != 1) + modulate_colors = false; + + if(!chan_control->alpha_matsrc || !chan_control->color_matsrc) + { + GXColor matColor = (GXColor){0xff, 0xff, 0xff, MultiplyAlpha(0xff, render_alpha) }; + + if(flags->material_color) + matColor = (GXColor){ mat_color->r, mat_color->g, mat_color->b, + MultiplyAlpha(mat_color->a, render_alpha) }; + + GX_SetChanMatColor(4, matColor); + + if((*(u32 *)&matColor) == 0xFFFFFFFF) + modulate_colors = true; + } + } + else + { + GX_SetChanCtrl(4, 0, 0, 1, 0, 0, 2); + } + + GX_SetNumChans(1); +} + +inline void Material::ApplyTexCoordGens(void) const +{ + // texture coord gen + for(u32 i = 0; i != flags->texture_coord_gen; ++i) + { + const TextureCoordGen &tcg = texture_coord_gens[i]; + GX_SetTexCoordGen(GX_TEXCOORD0 + i, tcg.tgen_typ, tcg.tgen_src, tcg.mtxsrc); + + const u8 mtrx = (tcg.mtxsrc - GX_TEXMTX0) / 3; + + if (tcg.tgen_typ == 1 && tcg.mtxsrc != GX_IDENTITY && mtrx < flags->texture_srt) + { + const TextureSrt& srt = texture_srts[mtrx]; + + const float rotate_rad = DegToRad(srt.rotate); + const float cosF = cosf(rotate_rad); + const float sinF = sinf(rotate_rad); + + // setup texture matrix + Mtx m; + m[0][0] = srt.scale_x * cosF; + m[0][1] = srt.scale_y * -sinF; + m[0][2] = 0.0f; + m[0][3] = -0.5f * (m[0][0] + m[0][1]) + srt.translate_x + 0.5f; + m[1][0] = srt.scale_x * sinF; + m[1][1] = srt.scale_y * cosF; + m[1][2] = 0.0f; + m[1][3] = -0.5f * (m[1][0] + m[1][1]) + srt.translate_y + 0.5f; + m[2][0] = 0.0f; + m[2][1] = 0.0f; + m[2][2] = 1.0f; + m[2][3] = 0.0f; + + GX_LoadTexMtxImm(m, tcg.mtxsrc, GX_MTX3x4); + } + } + + GX_SetNumTexGens(flags->texture_coord_gen); +} + +inline void Material::ApplyTevSwapTable(void) const +{ + if (flags->tev_swap_table) + { + for(int i = 0; i < 4; i++) + GX_SetTevSwapModeTable(GX_TEV_SWAP0 + i, + tev_swap_table[i].r, tev_swap_table[i].g, + tev_swap_table[i].b, tev_swap_table[i].a); + } + else + { + GX_SetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA); + } +} + +inline void Material::ApplyTevStages(bool modulate_colors) const +{ + u32 tev_stages_cnt = 0; + + if(flags->tev_stages) + { + // tev stages + for(u32 i = 0; i < flags->tev_stages; ++i) + { + const TevStage &ts = tev_stages[i]; + + GX_SetTevOrder(i, ts.texcoord, ts.tex_map | (ts.lowBit << 8), ts.color ); + GX_SetTevSwapMode(i, ts.ras_sel, ts.tex_sel); + + GX_SetTevColorIn(i, ts.color_in.a, ts.color_in.b, ts.color_in.c, ts.color_in.d); + GX_SetTevColorOp(i, ts.color_in.tevop, ts.color_in.tevbias, ts.color_in.tevscale, ts.color_in.clamp, ts.color_in.tevregid ); + GX_SetTevKColorSel(i, ts.color_in.sel ); + + GX_SetTevAlphaIn(i, ts.alpha_in.a, ts.alpha_in.b, ts.alpha_in.c, ts.alpha_in.d); + GX_SetTevAlphaOp(i, ts.alpha_in.tevop, ts.alpha_in.tevbias, ts.alpha_in.tevscale, ts.alpha_in.clamp, ts.alpha_in.tevregid ); + GX_SetTevKAlphaSel(i, ts.alpha_in.sel ); + + GX_SetTevIndirect(i, ts.ind.indtexid, ts.ind.format, ts.ind.bias, ts.ind.mtxid, + ts.ind.wrap_s, ts.ind.wrap_t, ts.ind.addprev, ts.ind.utclod, ts.ind.a); + + tev_stages_cnt++; + } + } + else + { + if(flags->texture_map == 0) + { + // 1st stage + GX_SetTevOrder(GX_TEVSTAGE0, 0xFF, 0xFF, 4); + GX_SetTevColorIn(GX_TEVSTAGE0, 0xF, 4, 0xA, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0, 0x7, 2, 0x5, 0x7); + tev_stages_cnt++; + } + else if(flags->texture_map == 1) + { + // 1st stage + GX_SetTevOrder(GX_TEVSTAGE0, 0, 0, 0xFF); + GX_SetTevColorIn(GX_TEVSTAGE0, 2, 4, 8, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0, 1, 2, 4, 7); + tev_stages_cnt++; + + // 2nd stage + if(modulate_colors) + { + GX_SetTevOrder(GX_TEVSTAGE0 + tev_stages_cnt, 0xFF, 0xFF, 4); + GX_SetTevColorIn(GX_TEVSTAGE0 + tev_stages_cnt, 0xF, 0, 0xA, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0 + tev_stages_cnt, 7, 0, 5, 7); + tev_stages_cnt++; + } + } + else if(flags->texture_map == 2) + { + // 1st stage + GX_SetTevOrder(GX_TEVSTAGE0, 0, 0, 0xFF); + GX_SetTevColorIn(GX_TEVSTAGE0, 0xF, 0xF, 0xF, 8); + GX_SetTevAlphaIn(GX_TEVSTAGE0, 7, 7, 7, 4); + tev_stages_cnt++; + + // 2nd stage + GX_SetTevOrder(GX_TEVSTAGE0 + tev_stages_cnt, 1, 1, 0xFF); + GX_SetTevColorIn(GX_TEVSTAGE0 + tev_stages_cnt, 8, 0, 0xE, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0 + tev_stages_cnt, 4, 0, 6, 7); + GX_SetTevKColorSel(GX_TEVSTAGE0 + tev_stages_cnt, 0x1f); + GX_SetTevKAlphaSel(GX_TEVSTAGE0 + tev_stages_cnt, 0x1f); + tev_stages_cnt++; + + // 3rd stage + if(modulate_colors) + { + GX_SetTevOrder(GX_TEVSTAGE0 + tev_stages_cnt, 0xFF, 0xFF, 4); + GX_SetTevColorIn(GX_TEVSTAGE0 + tev_stages_cnt, 0xF, 0, 0xA, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0 + tev_stages_cnt, 7, 0, 5, 7); + tev_stages_cnt++; + } + } + else + { + u32 TevKDefault[] = { 0x1F, 0x1B, 0x17, 0x13, 0x1E, 0x1A, 0x16, 0x12 }; + + for(int i = 0; i < flags->texture_map; i++) + { + GX_SetTevOrder(i, i, i, 0xff ); + + GX_SetTevColorIn(i, 0xf, 8, 0xe, i ? 0xf : 0 ); + GX_SetTevAlphaIn(i, 7, 4, 6, i ? 7 : 0 ); + GX_SetTevKColorSel(i, TevKDefault[i] ); + GX_SetTevKAlphaSel(i, TevKDefault[i] ); + tev_stages_cnt++; + } + + GX_SetTevOrder(GX_TEVSTAGE0 + tev_stages_cnt, 0xff, 0xff, 0xff ); + GX_SetTevColorIn(GX_TEVSTAGE0 + tev_stages_cnt, 2, 4, 0, 0xf ); + GX_SetTevAlphaIn(GX_TEVSTAGE0 + tev_stages_cnt, 1, 2, 0, 7 ); + tev_stages_cnt++; + + if(modulate_colors) + { + GX_SetTevOrder(GX_TEVSTAGE0 + tev_stages_cnt, 0xFF, 0xFF, 4); + GX_SetTevColorIn(GX_TEVSTAGE0 + tev_stages_cnt, 0xF, 0, 0xA, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0 + tev_stages_cnt, 7, 0, 5, 7); + tev_stages_cnt++; + } + } + + for(u32 i = 0; i < tev_stages_cnt; i++) + { + GX_SetTevColorOp(GX_TEVSTAGE0 + i, 0, 0, 0, 1, 0); + GX_SetTevAlphaOp(GX_TEVSTAGE0 + i, 0, 0, 0, 1, 0); + GX_SetTevDirect(GX_TEVSTAGE0 + i); + GX_SetTevSwapMode(GX_TEVSTAGE0 + i, 0, 0); + } + } + + // enable correct number of tev stages + GX_SetNumTevStages(tev_stages_cnt); +} + +inline void Material::ApplyIndStages(void) const +{ + for( int i = 0; i < flags->ind_srt; i++ ) + { + const IndSrt &ind = ind_srt[i]; + + const float rotate_rad = DegToRad(ind.rotate); + // maybe add a look up table + float cosF = cosf(rotate_rad); + float sinF = sinf(rotate_rad); + + int scale_exp = 0; + f32 mtx23[2][3]; + f32 mtxabs23[2][3]; + + mtx23[0][0] = ind.scale_x * cosF; + mtx23[0][1] = ind.scale_y * -sinF; + mtx23[0][2] = ind.translate_x; + + mtx23[1][0] = ind.scale_x * sinF; + mtx23[1][1] = ind.scale_y * cosF; + mtx23[1][2] = ind.translate_y; + + // create matrix with abs values + // compiler will optimize the loops + for(int n = 0; n < 2; n++) + for(int m = 0; m < 3; m++) + mtxabs23[n][m] = fabs(mtx23[n][m]); + + // hardcore clamping going on here + if( (mtxabs23[0][0] >= 1.0f) + || (mtxabs23[0][1] >= 1.0f) + || (mtxabs23[0][2] >= 1.0f) + || (mtxabs23[1][0] >= 1.0f) + || (mtxabs23[1][1] >= 1.0f) + || (mtxabs23[1][2] >= 1.0f)) + { + while( scale_exp < 0x2E + && ((mtxabs23[0][0] >= 1.0f) + || (mtxabs23[0][1] >= 1.0f) + || (mtxabs23[0][2] >= 1.0f) + || (mtxabs23[1][0] >= 1.0f) + || (mtxabs23[1][1] >= 1.0f) + || (mtxabs23[1][2] >= 1.0f))) + { + for(int n = 0; n < 2; n++) + { + for(int m = 0; m < 3; m++) + { + mtx23[n][m] *= 0.5f; + mtxabs23[n][m] *= 0.5f; + } + } + + scale_exp++; + } + } + else if( (mtxabs23[0][0] < 0.5f) + && (mtxabs23[0][1] < 0.5f) + && (mtxabs23[0][2] < 0.5f) + && (mtxabs23[1][0] < 0.5f) + && (mtxabs23[1][1] < 0.5f) + && (mtxabs23[1][2] < 0.5f)) + { + while( scale_exp > -0x11 + && (mtxabs23[0][0] < 0.5f) + && (mtxabs23[0][1] < 0.5f) + && (mtxabs23[0][2] < 0.5f) + && (mtxabs23[1][0] < 0.5f) + && (mtxabs23[1][1] < 0.5f) + && (mtxabs23[1][2] < 0.5f)) + { + for(int n = 0; n < 2; n++) + { + for(int m = 0; m < 3; m++) + { + mtx23[n][m] *= 2.0f; + mtxabs23[n][m] *= 2.0f; + } + } + + scale_exp--; + } + } + + GX_SetIndTexMatrix(GX_ITM_0 + i, mtx23, scale_exp); + } + + for( int i = 0; i < flags->ind_stage; i++ ) + { + const IndStage &stage = ind_stage[i]; + GX_SetIndTexOrder(i, stage.texcoord, stage.tex_map); + GX_SetIndTexCoordScale(i, stage.scale_s, stage.scale_t); + } + + GX_SetNumIndStages(flags->ind_stage); +} + +inline void Material::ApplyTextures(const BannerResources& resources) const +{ + u8 tlut_name = 0; + + for(u32 i = 0; i < flags->texture_map; ++i) + { + const TextureMap &tr = texture_maps[i]; + + if(palette_texture[i] == DEFAULT_PALETTE) + { + if (tr.tex_index < resources.textures.size()) + resources.textures[tr.tex_index]->Apply(tlut_name, i, tr.wrap_s, tr.wrap_t); + } + else + { + // find texture from palette + if(palette_texture[i] >= resources.palettes[resources.cur_set].size()) + { + gprintf( "palette index is out of range %i\n", palette_texture[i]); + return; + } + for(u32 n = 0; n < resources.textures.size(); n++) + { + if(resources.textures[n]->getName() == resources.palettes[resources.cur_set][palette_texture[i]]) + { + resources.textures[n]->Apply(tlut_name, i, tr.wrap_s, tr.wrap_t); + break; + } + } + } + } + + // invalidate texture cache + GX_InvalidateTexAll(); +} + +void Material::Apply(const BannerResources& resources, u8 render_alpha, bool modulate_colors) const +{ + // channel control and material color + ApplyChannelControl(render_alpha, modulate_colors); + + // texture coordinates gen + ApplyTexCoordGens(); + + // bind textures + ApplyTextures(resources); + + for (u32 i = 0; i < 4; ++i) + { + // tev reg colors + if(i < 3) + GX_SetTevColorS10(GX_TEVREG0 + i, header->color_regs[i]); + + // tev k colors + GX_SetTevKColor(GX_KCOLOR0 + i, header->color_constants[i]); + } + + // tev swap colors + ApplyTevSwapTable(); + + // tev stages + ApplyTevStages(modulate_colors); + + // ind stages + ApplyIndStages(); + + // alpha compare + if(flags->alpha_compare) + GX_SetAlphaCompare(alpha_compare->compare & 0xf, alpha_compare->ref0, + alpha_compare->op, alpha_compare->compare >> 4, alpha_compare->ref1); + else + GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + + // blend mode + if (flags->blend_mode) + GX_SetBlendMode(blend_mode->type, blend_mode->src_factor, blend_mode->dst_factor, blend_mode->logical_op); + else + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET); +} + +void Material::ProcessHermiteKey(const KeyType& type, float value) +{ + if (type.type == ANIMATION_TYPE_TEXTURE_SRT) // texture scale/rotate/translate + { + if (type.target < 5 && type.index < flags->texture_srt) + { + (&texture_srts[type.index].translate_x)[type.target] = value; + return; + } + // TODO: Something is still here: target 0-4 and index 1-9 while texture_srt is 1, value is always 0 or 1 + return; // TODO remove this + } + else if (type.type == ANIMATION_TYPE_IND_MATERIAL) // ind texture crap + { + if (type.target < 5 && type.index < flags->ind_srt) + { + (&ind_srt[type.index].translate_x)[type.target] = value; + return; + } + return; // TODO remove this + } + else if (type.type == ANIMATION_TYPE_MATERIAL_COLOR) // material color + { + if (type.target < 4) + { + // mat_color + if(flags->material_color) + (&mat_color->r)[type.target] = FLOAT_2_U8(value); + return; + } + else if (type.target < 0x10) + { + (&header->color_regs->r)[type.target - 4] = FLOAT_2_S16(value); + return; + } + else if (type.target < 0x20) + { + (&header->color_constants->r)[type.target - 0x10] = FLOAT_2_U8(value); + return; + } + } + + Base::ProcessHermiteKey(type, value); +} + +void Material::ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data) +{ + if (type.type == ANIMATION_TYPE_TEXTURE_PALETTE) // tpl palette + { + if(type.index < MAX_TEX_MAP) + { + palette_texture[type.index] = data.data2; + return; + } + } + + Base::ProcessStepKey(type, data); +} diff --git a/source/banner/Material.h b/source/banner/Material.h new file mode 100644 index 0000000..4e5b547 --- /dev/null +++ b/source/banner/Material.h @@ -0,0 +1,254 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok and giantpune + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef WII_BNR_MATERIAL_H_ +#define WII_BNR_MATERIAL_H_ + +#include "Animator.h" +#include "Texture.h" + +struct BannerResources; + +class Material : public Animator +{ +public: + typedef Animator Base; + + struct Header + { + char name[20]; + GXColorS10 color_regs[3]; + GXColor color_constants[4]; + u32 flags; + } __attribute__((packed)); + + Material(); + virtual ~Material() {} + + void Load(Material::Header *mat); + void Apply(const BannerResources& resources, u8 render_alpha, bool modulate) const; + const char *getName() const { return header->name; } + + const Material::Header *GetHeader() const { return header; } +protected: + void ProcessHermiteKey(const KeyType& type, float value); + void ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data); + +private: + void ApplyChannelControl(u8 render_alpha, bool &modulate_colors) const; + void ApplyTevSwapTable(void) const; + void ApplyTexCoordGens(void) const; + void ApplyTevStages(bool modulate_colors) const; + void ApplyIndStages(void) const; + void ApplyTextures(const BannerResources& resources) const; + + enum + { + MAX_TEX_MAP = 8, + MAX_TEX_SRT = 10, + MAX_TEX_GEN = 8, + MAX_IND_STAGES = 4, + MAX_TEV_STAGES = 16, + DEFAULT_PALETTE = 0xFF, + }; + + struct MatFlags + { + u32 pad2 : 4; + u32 material_color : 1; + u32 pad : 1; + u32 channel_control : 1; + u32 blend_mode : 1; + u32 alpha_compare : 1; + u32 tev_stages : 5; + u32 ind_stage : 3; + u32 ind_srt : 2; + u32 tev_swap_table : 1; + u32 texture_coord_gen : 4; + u32 texture_srt : 4; + u32 texture_map : 4; + } __attribute__((packed)); + + struct TextureMap + { + u16 tex_index; + u8 wrap_s; + u8 wrap_t; + } __attribute__((packed)); + + struct TextureSrt + { + f32 translate_x; + f32 translate_y; + f32 rotate; + f32 scale_x; + f32 scale_y; + } __attribute__((packed)); + + struct TextureCoordGen + { + u8 tgen_typ; + u8 tgen_src; + u8 mtxsrc; + u8 pad; + } __attribute__((packed)); + + struct ChannelControl + { + u8 color_matsrc; + u8 alpha_matsrc; + u16 pad; + } __attribute__((packed)); + + struct IndSrt + { + f32 translate_x; + f32 translate_y; + f32 rotate; + f32 scale_x; + f32 scale_y; + } __attribute__((packed)); + + struct IndStage + { + u8 texcoord; + u8 tex_map; + u8 scale_s; + u8 scale_t; + } __attribute__((packed)); + + struct BlendModes + { + u8 type, src_factor, dst_factor, logical_op; + + } __attribute__((packed)); + + struct AlphaCompareModes + { + u8 compare, op, ref0, ref1; + + } __attribute__((packed)); + + struct TevSwap + { + u32 a : 2; + u32 b : 2; + u32 g : 2; + u32 r : 2; + } __attribute__((packed)); + + struct TevStage + { + u32 texcoord : 8; + u32 color : 8; + u32 tex_map : 8; + + u32 unk : 3; + u32 tex_sel : 2; + u32 ras_sel : 2; + u32 lowBit : 1; + + struct + { + u32 b : 4; + u32 a : 4; + + u32 d : 4; + u32 c : 4; + + u32 tevscale : 2; + u32 tevbias : 2; + u32 tevop : 4; + + u32 sel : 5; + u32 tevregid : 2; + u32 clamp : 1; + + } __attribute__((packed)) color_in, __attribute__((packed)) alpha_in; + + struct + { + u32 unk1 : 6; + u32 indtexid : 2; + + u32 unk2 : 1; + u32 mtxid : 4; + u32 bias : 3; + + u32 unk3 : 2; + u32 wrap_t : 3; + u32 wrap_s : 3; + + u32 unk4 : 2; + u32 a : 2; + u32 utclod : 1; + u32 addprev : 1; + u32 format : 2; + + } __attribute__((packed)) ind; + } __attribute__((packed)); + + // Material flags + MatFlags *flags; + + // Texture + TextureMap *texture_maps; + TextureSrt *texture_srts; + TextureCoordGen *texture_coord_gens; + + // Color channels + ChannelControl *chan_control; + + // Material colors + GXColor *mat_color; + + // Tev color swap + TevSwap *tev_swap_table; + + // Indirect textures + IndSrt *ind_srt; + IndStage *ind_stage; + + // Texture environment + TevStage *tev_stages; + + // Blending and alpha compare + AlphaCompareModes *alpha_compare; + BlendModes *blend_mode; + + // palette animation + u8 palette_texture[MAX_TEX_MAP]; + + //! Material header + Material::Header *header; +}; + +class MaterialList : public std::vector +{ +public: + static const u32 MAGIC = MAKE_FOURCC('m', 'a', 't', '1'); +}; + + +#endif diff --git a/source/banner/OpeningBNR.cpp b/source/banner/OpeningBNR.cpp new file mode 100644 index 0000000..7a56849 --- /dev/null +++ b/source/banner/OpeningBNR.cpp @@ -0,0 +1,488 @@ +/* +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include +#include +#include "Channels/channels.h" +#include "GameCube/GCGames.h" +#include "libs/libwbfs/gcdisc.h" +#include "FileOperations/fileops.h" +#include "language/gettext.h" +#include "usbloader/disc.h" +#include "usbloader/wbfs.h" +#include "usbloader/wdvd.h" +#include "usbloader/wbfs/wbfs_rw.h" +#include "utils/uncompress.h" +#include "themes/CTheme.h" +#include "settings/GameTitles.h" +#include "wstring.hpp" +#include "OpeningBNR.hpp" + +BNRInstance * BNRInstance::instance = NULL; + +OpeningBNR::OpeningBNR() + : imetHdr(0), filesize(0) +{ + memset(gameID, 0, sizeof(gameID)); +} + +OpeningBNR::~OpeningBNR() +{ + if(imetHdr) + free(imetHdr); +} + +bool OpeningBNR::LoadCachedBNR(const char *id) +{ + char path[255]; + snprintf(path, sizeof(path), "%s%.6s.bnr", Settings.BNRCachePath, id); + if((filesize = FileSize(path)) == 0) + { + snprintf(path, sizeof(path), "%s%.3s.bnr", Settings.BNRCachePath, id); + if((filesize = FileSize(path)) == 0) + return false; + } + + FILE *f = fopen(path, "rb"); + if(!f) + return false; + + imetHdr = (IMETHeader *) malloc(filesize); + if(!imetHdr) + { + fclose(f); + return false; + } + + fread(imetHdr, 1, filesize, f); + fclose(f); + + if (imetHdr->fcc != 'IMET') + { + //! check if it's a channel .app file + IMETHeader *channelImet = (IMETHeader *)(((u8 *)imetHdr) + 0x40); + if(channelImet->fcc != 'IMET') + { + free(imetHdr); + imetHdr = NULL; + return false; + } + //! just move it 0x40 bytes back, the rest 0x40 bytes will just be unused + //! as it's a temporary file usually it's not worth to reallocate + filesize -= 0x40; + memcpy(imetHdr, channelImet, filesize); + } + + return true; +} + +void OpeningBNR::WriteCachedBNR(const char *id, const u8 *buffer, u32 size) +{ + char path[255]; + snprintf(path, sizeof(path), "%s%.6s.bnr", Settings.BNRCachePath, id); + + CreateSubfolder(Settings.BNRCachePath); + + FILE *f = fopen(path, "wb"); + if(!f) + return; + + fwrite(buffer, 1, size, f); + fclose(f); +} + +bool OpeningBNR::Load(const discHdr * header) +{ + if(!header) + return false; + + if(memcmp(gameID, header->id, 6) == 0) + return true; + + memcpy(gameID, header->id, 6); + + if(imetHdr) + free(imetHdr); + imetHdr = NULL; + + switch(header->type) + { + case TYPE_GAME_WII_IMG: + case TYPE_GAME_WII_DISC: + return LoadWiiBanner(header); + case TYPE_GAME_NANDCHAN: + case TYPE_GAME_EMUNANDCHAN: + return LoadChannelBanner(header); + case TYPE_GAME_GC_IMG: + case TYPE_GAME_GC_DISC: + case TYPE_GAME_GC_EXTRACTED: + if(!Settings.CacheBNRFiles) + return false; + return LoadCachedBNR((char *)header->id); + default: + break; + } + + return false; +} + +bool OpeningBNR::LoadWiiBanner(const discHdr * header) +{ + if(!header || ( (header->type != TYPE_GAME_WII_IMG) + && (header->type != TYPE_GAME_WII_DISC))) + return false; + + + if(Settings.CacheBNRFiles && LoadCachedBNR((const char *)header->id)) + return true; + + if(header->type == TYPE_GAME_WII_DISC) + { + wiidisc_t *wdisc = wd_open_disc(__ReadDVD, 0); + if (!wdisc) + return false; + + imetHdr = (IMETHeader*) wd_extract_file(wdisc, ALL_PARTITIONS, (char *) "opening.bnr"); + + filesize = wdisc->extracted_size; + + wd_close_disc(wdisc); + } + else + { + wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) gameID); + if (!disc) + return false; + + wiidisc_t *wdisc = wd_open_disc((s32(*)(void *, u32, u32, void *)) wbfs_disc_read, disc); + if (!wdisc) + { + WBFS_CloseDisc(disc); + return false; + } + + imetHdr = (IMETHeader*) wd_extract_file(wdisc, ALL_PARTITIONS, (char *) "opening.bnr"); + + filesize = wdisc->extracted_size; + + wd_close_disc(wdisc); + WBFS_CloseDisc(disc); + } + + if(!imetHdr) + return false; + + if (imetHdr->fcc != 'IMET') + { + free(imetHdr); + imetHdr = NULL; + return false; + } + + if(Settings.CacheBNRFiles) + WriteCachedBNR((const char *) header->id, (u8 *) imetHdr, filesize); + + return true; +} + +bool OpeningBNR::LoadChannelBanner(const discHdr *header) +{ + if(!header || (header->tid == 0) || ( (header->type != TYPE_GAME_NANDCHAN) + && (header->type != TYPE_GAME_EMUNANDCHAN))) + return false; + + if(Settings.CacheBNRFiles && LoadCachedBNR((char *) header->id)) + return true; + + const u64 &tid = header->tid; + const char *pathPrefix = (header->type == TYPE_GAME_EMUNANDCHAN) ? Settings.NandEmuChanPath : ""; + + imetHdr = (IMETHeader*) Channels::GetOpeningBnr(tid, &filesize, pathPrefix); + if(!imetHdr) + return false; + + if (imetHdr->fcc != 'IMET') + { + free(imetHdr); + imetHdr = NULL; + return false; + } + + if(Settings.CacheBNRFiles) + WriteCachedBNR((char *) header->id, (u8 *) imetHdr, filesize); + + return true; +} + +const u16 * OpeningBNR::GetIMETTitle(int lang) +{ + if(!imetHdr || lang < 0 || lang >= 10) + return NULL; + + if (imetHdr->fcc != 'IMET') + return NULL; + + if(imetHdr->names[lang][0] == 0) + lang = CONF_LANG_ENGLISH; + + return imetHdr->names[lang]; +} + +static s32 GC_Disc_Read(void *fp, u32 offset, u32 count, void*iobuf) +{ + if(fp) + { + fseek((FILE *)fp, offset, SEEK_SET); + return fread(iobuf, 1, count, (FILE *)fp); + } + + return __ReadDVDPlain(iobuf, count, offset); +} + +u8 *OpeningBNR::LoadGCBNR(const discHdr * header, u32 *len) +{ + if(!header || ( (header->type != TYPE_GAME_GC_IMG) + && (header->type != TYPE_GAME_GC_DISC) + && (header->type != TYPE_GAME_GC_EXTRACTED))) + return NULL; + + const char *path = GCGames::Instance()->GetPath((char *) header->id); + if(!path) + return NULL; + + FILE *file = NULL; + GC_OpeningBnr *openingBnr = NULL; + + // read from file + if((header->type == TYPE_GAME_GC_IMG) || (header->type == TYPE_GAME_GC_DISC)) + { + //! open iso file if it's iso + if(header->type == TYPE_GAME_GC_IMG) + { + file = fopen(path, "rb"); + if(!file) + return NULL; + } + + gcdisc_t *disc = gc_open_disc(GC_Disc_Read, file); + if(!disc) { + fclose(file); + return NULL; + } + + if(!strcmp(Settings.db_language, "JA")) { + bool loaded = gc_extract_file(disc, "openingJA.bnr"); + if(!loaded) + loaded = gc_extract_file(disc, "opening.bnr"); + if(!loaded) + loaded = gc_extract_file(disc, "openingUS.bnr"); + if(!loaded) + loaded = gc_extract_file(disc, "openingEU.bnr"); + } + else if(!strcmp(Settings.db_language, "EN")) { + bool loaded = gc_extract_file(disc, "openingUS.bnr"); + if(!loaded) + loaded = gc_extract_file(disc, "opening.bnr"); + if(!loaded) + loaded = gc_extract_file(disc, "openingEU.bnr"); + if(!loaded) + loaded = gc_extract_file(disc, "openingJA.bnr"); + } + else { + bool loaded = gc_extract_file(disc, "openingEU.bnr"); + if(!loaded) + loaded = gc_extract_file(disc, "opening.bnr"); + if(!loaded) + loaded = gc_extract_file(disc, "openingUS.bnr"); + if(!loaded) + loaded = gc_extract_file(disc, "openingJA.bnr"); + } + + openingBnr = (GC_OpeningBnr *) disc->extracted_buffer; + if(len) + *len = disc->extracted_size; + + gc_close_disc(disc); + } + else if(header->type == TYPE_GAME_GC_EXTRACTED) + { + string gamePath = path; + gamePath += "root/"; + //! open default file first + file = fopen((gamePath + "opening.bnr").c_str(), "rb"); + + // if not found try the region specific ones + if(!strcmp(Settings.db_language, "JA")) { + if(!file) + file = fopen((gamePath + "openingJA.bnr").c_str(), "rb"); + if(!file) + file = fopen((gamePath + "openingUS.bnr").c_str(), "rb"); + if(!file) + file = fopen((gamePath + "openingEU.bnr").c_str(), "rb"); + } + else if(!strcmp(Settings.db_language, "EN")) { + if(!file) + file = fopen((gamePath + "openingUS.bnr").c_str(), "rb"); + if(!file) + file = fopen((gamePath + "openingEU.bnr").c_str(), "rb"); + if(!file) + file = fopen((gamePath + "openingJA.bnr").c_str(), "rb"); + } + else { + if(!file) + file = fopen((gamePath + "openingEU.bnr").c_str(), "rb"); + if(!file) + file = fopen((gamePath + "openingUS.bnr").c_str(), "rb"); + if(!file) + file = fopen((gamePath + "openingJA.bnr").c_str(), "rb"); + } + + // file not found + if(!file) + return NULL; + + fseek(file, 0, SEEK_END); + int size = ftell(file); + rewind(file); + + openingBnr = (GC_OpeningBnr *) malloc(size); + if(openingBnr) + { + if(len) + *len = size; + fread(openingBnr, 1, size, file); + } + + } + + if(file) + fclose(file); + + if(!openingBnr) + return NULL; + + // check magic of the opening bnr + if(openingBnr->magic != 'BNR1' && openingBnr->magic != 'BNR2') { + free(openingBnr); + return NULL; + } + + return (u8 *) openingBnr; +} + +CustomBanner *OpeningBNR::CreateGCBanner(const discHdr * header) +{ + int language = 0; + u32 openingBnrSize; + GC_OpeningBnr *openingBnr = (GC_OpeningBnr *) LoadGCBNR(header, &openingBnrSize); + + CustomBanner *banner = new CustomBanner; + banner->LoadBanner(Resources::GetFile("custom_banner.bnr"), Resources::GetFileSize("custom_banner.bnr")); + banner->SetBannerPngImage("bg.tpl", Resources::GetFile("gc_banner_bg.png"), Resources::GetFileSize("gc_banner_bg.png")); + + banner->SetBannerText("T_PF", tr("GameCube")); + + if(openingBnr) + { + banner->SetBannerTexture("HBPic.tpl", openingBnr->tpl_data, 96, 32, GX_TF_RGB5A3); + + // European opening bnr file + if(openingBnr->magic == 'BNR2') + { + if(!strcmp(Settings.db_language, "DE")) { + language = 1; + } + else if(!strcmp(Settings.db_language, "FR")) { + language = 2; + } + else if(!strcmp(Settings.db_language, "ES")) { + language = 3; + } + else if(!strcmp(Settings.db_language, "IT")) { + language = 4; + } + else if(!strcmp(Settings.db_language, "NL")) { + language = 5; + } + + if((0x1820 + sizeof(openingBnr->description[0]) * language) > openingBnrSize) { + language = 0; + } + } + + wString str; + str.resize(strlen((char *) openingBnr->description[language].developer)); + for(u32 i = 0; i < str.size(); i++) + str[i] = *(openingBnr->description[language].developer + i); + + banner->SetBannerText("T_Coded_by", tr("Developer:")); + banner->SetBannerText("T_coder", str.toUTF8().c_str()); + + str.resize(strlen((char *) openingBnr->description[language].long_description)); + for(u32 i = 0; i < str.size(); i++) + str[i] = *(openingBnr->description[language].long_description + i); + + banner->SetBannerText("T_short_descript", str.toUTF8().c_str()); + + // free buffer + free(openingBnr); + } + else + { + banner->SetBannerPngImage("HBPic.tpl", Resources::GetFile("gc_icon_bg.png"), Resources::GetFileSize("gc_icon_bg.png")); + banner->SetBannerText("T_Coded_by", tr("Developer:")); + banner->SetBannerText("T_coder", tr("Unknown")); + banner->SetBannerText("T_short_descript", " "); + } + + banner->SetBannerText("T_name", GameTitles.GetTitle(header)); + banner->SetBannerPaneVisible("Line1", false); + banner->SetBannerPaneVisible("Line2", false); + banner->SetBannerPaneVisible("T_Released", false); + banner->SetBannerPaneVisible("T_release_date", false); + banner->SetBannerPaneVisible("T_versiontext", false); + banner->SetBannerPaneVisible("T_version", false); + banner->SetBannerTextureScale(Settings.GCBannerScale); + + return banner; +} + +CustomBanner *OpeningBNR::CreateGCIcon(const discHdr * header) +{ + GC_OpeningBnr *openingBnr = (GC_OpeningBnr *) LoadGCBNR(header); + + CustomBanner *newBanner = new CustomBanner; + newBanner->LoadIcon(Resources::GetFile("custom_banner.bnr"), Resources::GetFileSize("custom_banner.bnr")); + + if(openingBnr) + newBanner->SetIconTexture("Iconpng.tpl", openingBnr->tpl_data, 96, 32, GX_TF_RGB5A3); + else + newBanner->SetIconPngImage("Iconpng.tpl", Resources::GetFile("gc_icon_bg.png"), Resources::GetFileSize("gc_icon_bg.png")); + + newBanner->SetIconPngImage("HBLogo.tpl", Resources::GetFile("gc_icon_bg.png"), Resources::GetFileSize("gc_icon_bg.png")); + + // free buffer + if(openingBnr) + free(openingBnr); + + return newBanner; +} diff --git a/source/banner/OpeningBNR.hpp b/source/banner/OpeningBNR.hpp new file mode 100644 index 0000000..3c25a8b --- /dev/null +++ b/source/banner/OpeningBNR.hpp @@ -0,0 +1,134 @@ +/* +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef OPENING_BNR_HPP_ +#define OPENING_BNR_HPP_ + +#include +#include "usbloader/disc.h" +#include "CustomBanner.h" + +typedef struct _GC_OpeningBnr +{ + u32 magic; // BNR1 or BNR2 + u8 pad[0x1C]; + u8 tpl_data[0x1800]; // 96x32 pixel format GX_TF_RGB5A3 + struct + { + u8 disc_title[0x20]; // Gamename + u8 developer_short[0x20]; // Company/Developer + u8 full_title[0x40]; // Full Game Title + u8 developer[0x40]; // Company/Developer Full name, or description + u8 long_description[0x80]; // Game Description + } description[6]; // 6 only on BNR2 => English, German, French, Spanish, Italian, Dutch ?? +} GC_OpeningBnr; + +typedef struct _IMETHeader +{ + u8 zeroes[64]; + u32 fcc; + u8 unk[8]; + u32 iconSize; + u32 bannerSize; + u32 soundSize; + u32 flag1; + u16 names[10][42]; // 10 languages (thanks dkosmari for the info) + u16 zeroes_2[7*42]; // padding for 7 more languages (thanks dkosmari for the info) + u8 crypto[16]; +} __attribute__((packed)) IMETHeader; + +typedef struct _IMD5Header +{ + u32 fcc; + u32 filesize; + u8 zeroes[8]; + u8 crypto[16]; +} __attribute__((packed)) IMD5Header; + +typedef struct _U8Header +{ + u32 fcc; + u32 rootNodeOffset; + u32 headerSize; + u32 dataOffset; + u8 zeroes[16]; +} __attribute__((packed)) U8Header; + +typedef struct _U8Entry +{ + struct + { + u32 fileType :8; + u32 nameOffset :24; + }; + u32 fileOffset; + union + { + u32 fileLength; + u32 numEntries; + }; +} __attribute__( ( packed ) ) U8Entry; + + +static inline const char * u8Filename(const U8Entry *fst, int i) +{ + return (char *) (fst + fst[0].numEntries) + fst[i].nameOffset; +} + +class OpeningBNR +{ + public: + OpeningBNR(); + ~OpeningBNR(); + bool Load(const discHdr * header); + bool LoadWiiBanner(const discHdr * header); + bool LoadChannelBanner(const discHdr *header); + CustomBanner *CreateGCBanner(const discHdr * header); + CustomBanner *CreateGCIcon(const discHdr * header); + + const u8 * Get() const { return (const u8*) imetHdr; } + u32 GetSize() const { return filesize; } + + bool LoadCachedBNR(const char *id); + void WriteCachedBNR(const char *id, const u8 *buffer, u32 size); + + const u16 * GetIMETTitle(int lang); + const u16 * GetIMETTitle(const discHdr * header, int lang) { Load(header); return GetIMETTitle(lang); } + private: + u8 *LoadGCBNR(const discHdr * header, u32 *len = 0); + IMETHeader *imetHdr; + u32 filesize; + char gameID[7]; +}; + +class BNRInstance : public OpeningBNR +{ + public: + static BNRInstance * Instance() { if(!instance) instance = new BNRInstance; return instance; } + static void DestroyInstance() { delete instance; instance = NULL; } + private: + BNRInstance() { } + ~BNRInstance() { } + static BNRInstance * instance; +}; + +#endif diff --git a/source/banner/Pane.cpp b/source/banner/Pane.cpp new file mode 100644 index 0000000..8413960 --- /dev/null +++ b/source/banner/Pane.cpp @@ -0,0 +1,165 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "Pane.h" +#include "Layout.h" + +void Pane::Load(Pane::Header *pan) +{ + if(!pan) + return; + + header = pan; + hide = false; + RootPane = !strcmp( header->name, "RootPane" ); + AlignHor = header->origin % 3; + AlignVer = 2 - header->origin / 3; +} + +Pane::~Pane() +{ + // delete children + for(u32 i = 0; i < panes.size(); ++i) + delete panes[i]; +} + +void Pane::SetFrame(FrameNumber frame, u8 key_set) +{ + // setframe on self + Animator::SetFrame(frame, key_set); + + // setframe on children + for(u32 i = 0; i < panes.size(); ++i) + panes[i]->SetFrame(frame, key_set); +} + +void Pane::Render(const BannerResources& resources, u8 parent_alpha, Mtx &modelview, + bool widescreen, bool modify_alpha) const +{ + if (!header || !GetVisible() || GetHide()) + return; + + u8 render_alpha = header->alpha; + + if(RootPane && parent_alpha != 0xFF) + { + modify_alpha = true; + render_alpha = MultiplyAlpha(header->alpha, parent_alpha); + } + if(!RootPane && modify_alpha) + { + render_alpha = MultiplyAlpha(header->alpha, parent_alpha); + } + else if(GetInfluencedAlpha() && header->alpha != 0xff) + { + modify_alpha = true; + parent_alpha = MultiplyAlpha(header->alpha, parent_alpha); + } + + float ws_scale = 1.0f; + + if(widescreen && GetWidescren()) + { + ws_scale *= 0.82f; // should actually be 0.75? + widescreen = false; + } + + Mtx m1,m2,m3,m4, mv; + guMtxIdentity (m1); + + // Scale + guMtxScaleApply(m1,m1, header->scale.x * ws_scale, header->scale.y, 1.f); + + // Rotate + guMtxRotDeg ( m2, 'x', header->rotate.x ); + guMtxRotDeg ( m3, 'y', header->rotate.y ); + guMtxRotDeg ( m4, 'z', header->rotate.z ); + guMtxConcat(m2, m3, m2); + guMtxConcat(m2, m4, m2); + guMtxConcat(m1, m2, m1); + + // Translate + guMtxTransApply(m1,m1, header->translate.x, header->translate.y, header->translate.z); + + guMtxConcat (modelview, m1, mv); + + // render self + Draw(resources, render_alpha, ws_scale, mv); + + // render children + for(u32 i = 0; i < panes.size(); ++i) + panes[i]->Render(resources, render_alpha, mv, widescreen, modify_alpha); +} + +Pane* Pane::FindPane(const std::string& find_name) +{ + if(!header) + return NULL; + + if (find_name.compare(0, 0x10, getName()) == 0) + return this; + + for(u32 i = 0; i < panes.size(); ++i) + { + Pane *found = panes[i]->FindPane(find_name); + if (found) + return found; + } + + return NULL; +} + +void Pane::ProcessHermiteKey(const KeyType& type, float value) +{ + if (type.type == ANIMATION_TYPE_VERTEX_COLOR) // vertex color + { + // only alpha is supported for Panes afaict + if (0x10 == type.target) + { + header->alpha = FLOAT_2_U8(value); + return; + } + } + else if (type.type == ANIMATION_TYPE_PANE) // pane animation + { + if (type.target < 10) + { + (&header->translate.x)[type.target] = value; + return; + } + } + + Base::ProcessHermiteKey(type, value); +} + +void Pane::ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data) +{ + if (type.type == ANIMATION_TYPE_VISIBILITY) // visibility + { + SetVisible(!!data.data2); + return; + } + + Base::ProcessStepKey(type, data); +} diff --git a/source/banner/Pane.h b/source/banner/Pane.h new file mode 100644 index 0000000..b0374bf --- /dev/null +++ b/source/banner/Pane.h @@ -0,0 +1,143 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef WII_BNR_PANE_H_ +#define WII_BNR_PANE_H_ + +#include +#include + +#include "Animator.h" + +struct BannerResources; + +class Pane; +typedef std::vector PaneList; + +class Pane : public Animator +{ +public: + typedef Animator Base; + + static const u32 MAGIC = MAKE_FOURCC('p', 'a', 'n', '1'); + + struct Header + { + u32 magic; + u32 size_section; + u8 flags; + u8 origin; + u8 alpha; + u8 padding; + char name [0x10]; + char user_data [0x08]; + Vec3f translate; + Vec3f rotate; + Vec2f scale; + float width; + float height; + } __attribute__((packed)); + + Pane() : header(NULL) {} + virtual ~Pane(); + + void Load(Pane::Header *file); + + const char *getName() const { if(!header) return ""; return header->name; } + + void Render(const BannerResources& resources, u8 parent_alpha, Mtx &modelview, + bool widescreen, bool modify_alpha = false) const; + + void SetFrame(FrameNumber frame, u8 key_set); + + void SetScale(float scale) { if(header) header->scale.x = header->scale.y = scale; } + + bool GetHide() const { return hide; } + void SetHide(bool _hide) { hide = _hide; } + + bool GetVisible() const { if(!header) return false; return ((header->flags & (1 << FLAG_VISIBLE)) != 0); } + void SetVisible(bool visible) + { + if(!header) + return; + + if(visible) + header->flags |= (1 << FLAG_VISIBLE); + else + header->flags &= ~(1 << FLAG_VISIBLE); + } + + u8 GetOriginX() const { return AlignHor; } + u8 GetOriginY() const { return AlignVer; } + + float GetWidth() const { if(!header) return 0.f; return header->width; } + float GetHeight() const { if(!header) return 0.f; return header->height; } + + bool GetInfluencedAlpha() const { if(!header) return false; return ((header->flags & (1 << FLAG_INFLUENCED_ALPHA)) != 0); } + void SetInfluencedAlpha(bool influenced) + { + if(!header) + return; + + if(influenced) + header->flags |= (1 << FLAG_INFLUENCED_ALPHA); + else + header->flags &= ~(1 << FLAG_INFLUENCED_ALPHA); + } + + bool GetWidescren() const { return ((header->flags & (1 << FLAG_WIDESCREEN)) != 0); } + + Pane* FindPane(const std::string& name); // recursive + + PaneList panes; + +protected: + void ProcessHermiteKey(const KeyType& type, float value); + void ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data); + +private: + virtual void Draw(const BannerResources&, u8, const float, Mtx&) const {} + + enum + { + FLAG_VISIBLE = 0x00, + FLAG_INFLUENCED_ALPHA = 0x01, + FLAG_WIDESCREEN = 0x02 + }; + + Pane::Header *header; + bool hide; // used by the groups + bool RootPane; + u8 AlignVer; + u8 AlignHor; +}; + +// apparently Bounding is just a regular pane +class Bounding : public Pane +{ +public: + static const u32 MAGIC = MAKE_FOURCC('b', 'n', 'd', '1'); +}; + +#endif diff --git a/source/banner/Picture.cpp b/source/banner/Picture.cpp new file mode 100644 index 0000000..1583899 --- /dev/null +++ b/source/banner/Picture.cpp @@ -0,0 +1,34 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "Picture.h" + +void Picture::Load(Pane::Header * file) +{ + if(!file) + return; + + Pane::Load(file); + QuadPane::Load((QuadPane::Header *) (file+1)); +} diff --git a/source/banner/Picture.h b/source/banner/Picture.h new file mode 100644 index 0000000..9c957c2 --- /dev/null +++ b/source/banner/Picture.h @@ -0,0 +1,40 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef WII_BNR_PICTURE_H_ +#define WII_BNR_PICTURE_H_ + +#include "QuadPane.h" + +class Picture : public QuadPane +{ +public: + typedef QuadPane Base; + + static const u32 MAGIC = MAKE_FOURCC('p', 'i', 'c', '1'); + + void Load(Pane::Header *hdr); +}; + +#endif diff --git a/source/banner/QuadPane.cpp b/source/banner/QuadPane.cpp new file mode 100644 index 0000000..c889099 --- /dev/null +++ b/source/banner/QuadPane.cpp @@ -0,0 +1,126 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include "QuadPane.h" +#include "Layout.h" + +void QuadPane::Load(QuadPane::Header* file) +{ + if(!file) + return; + + header = file; + tex_coords = (const TexCoords *) (header+1); +} + +inline void QuadPane::SetVertex(int ind, float x, float y, u8 render_alpha) const +{ + // position + GX_Position3f32(x, y, 0.f); + + const GXColor &vertex_color = header->vertex_colors[ind]; + // color + GX_Color4u8(vertex_color.r, vertex_color.g, vertex_color.b, + MultiplyAlpha(vertex_color.a, render_alpha)); + + // texture coord + for(u32 i = 0; i < header->tex_coord_count; i++) + GX_TexCoord2f32(tex_coords[i].coords[ind].s, tex_coords[i].coords[ind].t); +} + +static inline bool IsModulateColor(GXColor *colors, u8 render_alpha) +{ + if(render_alpha != 0xFF) + return true; + + u32 *colorPtr = (u32 *) colors; + + for(int i = 0; i < 4; ++i) + { + if(colorPtr[i] != 0xFFFFFFFF) + return true; + } + + return false; +} + +void QuadPane::Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &modelview, u16 material_index, u8 texture_flip) const +{ + if(!header) + return; + + if (material_index < resources.materials.size()) + { + bool modulate_color = IsModulateColor(header->vertex_colors, render_alpha); + resources.materials[material_index]->Apply(resources, render_alpha, modulate_color); + } + + Mtx m, mv; + guMtxIdentity (m); + + guMtxTransApply(m,m, -0.5f * GetOriginX(), -0.5f * GetOriginY(), 0.f); + guMtxScaleApply(m,m, GetWidth(), GetHeight(), 1.f); + + guMtxConcat (modelview, m, mv); + + GX_LoadPosMtxImm (mv, GX_PNMTX0); + + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + for(u32 i = 0; i < header->tex_coord_count; i++) + GX_SetVtxDesc(GX_VA_TEX0+i, GX_DIRECT); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + if(texture_flip) + { + SetVertex(0, 0.f, 0.f, render_alpha); + SetVertex(1, 1.f, 0.f, render_alpha); + SetVertex(3, 1.f, 1.f, render_alpha); + SetVertex(2, 0.f, 1.f, render_alpha); + } + else + { + SetVertex(2, 0.f, 0.f, render_alpha); + SetVertex(3, 1.f, 0.f, render_alpha); + SetVertex(1, 1.f, 1.f, render_alpha); + SetVertex(0, 0.f, 1.f, render_alpha); + } + GX_End(); +} + +void QuadPane::ProcessHermiteKey(const KeyType& type, float value) +{ + if (type.type == ANIMATION_TYPE_VERTEX_COLOR) // vertex color + { + if (type.target < 0x10) + { + // vertex colors + (&header->vertex_colors->r)[type.target] = FLOAT_2_U8(value); + return; + } + } + + Base::ProcessHermiteKey(type, value); +} diff --git a/source/banner/QuadPane.h b/source/banner/QuadPane.h new file mode 100644 index 0000000..c030244 --- /dev/null +++ b/source/banner/QuadPane.h @@ -0,0 +1,73 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef _QUAD_PANE_H_ +#define _QUAD_PANE_H_ + +#include "Pane.h" + +// used by Picture and Window +class QuadPane : public Pane +{ +public: + typedef Pane Base; + + struct Header + { + GXColor vertex_colors[4]; + u16 material_index; + u8 tex_coord_count; + u8 pad; + } __attribute__((packed)); + + QuadPane() : header(NULL) {} + void Load(QuadPane::Header *file); + +protected: + void ProcessHermiteKey(const KeyType& type, float value); + //! overload + void Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &view, + u16 material_index, u8 texture_flip) const; + //! main virtual draw function + void Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &view) const { + Draw(resources, render_alpha, ws_scale, view, header->material_index, 0); + } + +private: + void SetVertex(int ind, float x, float y, u8 render_alpha) const; + + struct TexCoords + { + struct TexCoord + { + float s; + float t; + + } coords[4]; + }; + + QuadPane::Header *header; + const TexCoords *tex_coords; +}; + +#endif diff --git a/source/banner/Textbox.cpp b/source/banner/Textbox.cpp new file mode 100644 index 0000000..e51a245 --- /dev/null +++ b/source/banner/Textbox.cpp @@ -0,0 +1,287 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - giantpune +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include "Textbox.h" +#include "Layout.h" + +void Textbox::Load(Pane::Header *file) +{ + if(!file) + return; + + Pane::Load(file); + header = (Textbox::Header *) (file + 1); + text = (const u16 *) (header + 1); + + textAlignVer = (header->text_alignment / 3); + textAlignHor = (header->text_alignment % 3); +} + +void Textbox::SetTextWidth(WiiFont *font) +{ + lineWidths.clear(); + frameWidth = 0.f; + frameHeight = header->font_size; + float currentLine = 0.f; + float scale = header->font_size /(float)font->CharacterHeight(); + + for(const u16 *txtString = text; *txtString != 0; txtString++) + { + if(*txtString == '\n') + { + currentLine *= scale; + lineWidths.push_back(currentLine); + frameWidth = MAX(frameWidth, currentLine); + frameHeight += header->font_size + header->space_line; + currentLine = 0.f; + continue; + } + + const WiiFont::CharInfo *charInfo = font->GetCharInfo(*txtString); + if(!charInfo) + continue; + + if(charInfo->unk) + currentLine += (float) charInfo->advanceKerning; + + currentLine += (float) charInfo->advanceGlyphX; + } + + currentLine *= scale; + lineWidths.push_back(currentLine); + frameWidth = MAX(frameWidth, currentLine); +} + +void Textbox::SetupGX(const BannerResources& resources) const +{ + GX_ClearVtxDesc(); + GX_InvVtxCache(); + + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + // channel control + GX_SetNumChans(1); + GX_SetChanCtrl(GX_COLOR0A0,GX_DISABLE,GX_SRC_REG,GX_SRC_VTX,GX_LIGHTNULL,GX_DF_NONE,GX_AF_NONE); + + // texture gen. + GX_SetNumTexGens(1); + GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + // texture environment + GX_SetNumTevStages(1); + GX_SetNumIndStages(0); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GX_SetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0); + GX_SetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_1_4); + GX_SetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_1); + GX_SetTevDirect(GX_TEVSTAGE0); + // swap table + GX_SetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA); + // alpha compare and blend mode + GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET); + + if(header->material_index < resources.materials.size()) + { + const Material::Header *matHead = resources.materials[header->material_index]->GetHeader(); + if(!matHead) + return; + + //GX_SetFog(0, 0.0f, 0.0f, 0.0f, 0.0f, (GXColor){0xff, 0xff, 0xff, 0xff}); + GX_SetTevSwapModeTable(0, 0, 1, 2, 3); + //GX_SetZTexture(0, 0x11, 0); + GX_SetNumChans(1 ); + GX_SetChanCtrl(4, 0, 0, 1, 0, 0, 2); + GX_SetChanCtrl(5, 0, 0, 0, 0, 0, 2); + GX_SetNumTexGens(1); + GX_SetTexCoordGen2(0, 1, 4, 0x3c, 0, 0x7D); + GX_SetNumIndStages(0); + GX_SetBlendMode(1, 4, 5, 0xf); + GX_SetNumTevStages(2); + GX_SetTevDirect(0); + GX_SetTevDirect(1); + GX_SetTevSwapMode(0, 0, 0); + GX_SetTevSwapMode(1, 0, 0); + GX_SetTevOrder(0, 0, 0, 0xff); + + for( int i = 0; i < 2; i++ ) + { + // Devkitppc_r27 internal compiler error + //GX_SetTevColor(i + 1, (GXColor){ LIMIT(matHead->color_regs[i].r, 0, 0xFF), + // LIMIT(matHead->color_regs[i].g, 0, 0xFF), + // LIMIT(matHead->color_regs[i].b, 0, 0xFF), + // LIMIT(matHead->color_regs[i].a, 0, 0xFF) }); + + u8 r = (u8) LIMIT(matHead->color_regs[i].r, 0, 0xFF); + u8 g = (u8) LIMIT(matHead->color_regs[i].g, 0, 0xFF); + u8 b = (u8) LIMIT(matHead->color_regs[i].b, 0, 0xFF); + u8 a = (u8) LIMIT(matHead->color_regs[i].a, 0, 0xFF); + GX_SetTevColor((u8) (i + 1), (GXColor){r,g,b,a}); + } + + GX_SetTevColorIn(0, 2, 4, 8, 0xf); + GX_SetTevAlphaIn(0, 1, 2, 4, 7); + GX_SetTevColorOp(0, 0, 0, 0, 1, 0); + GX_SetTevAlphaOp(0, 0, 0, 0, 1, 0); + GX_SetTevOrder(1, 0xff, 0xff, 4); + GX_SetTevColorIn(1, 0xf, 0, 0xa, 0xf); + GX_SetTevAlphaIn(1, 7, 0, 5, 7); + GX_SetTevColorOp(1, 0, 0, 0, 1, 0); + GX_SetTevAlphaOp(1, 0, 0, 0, 1, 0); + } +} + +void Textbox::Draw(const BannerResources& resources, u8 parent_alpha, const float ws_scale, Mtx &modelview) const +{ + if(!text) + return; + + if(header->font_index >= resources.fonts.size()) + return; + + WiiFont *font = resources.fonts[header->font_index]; + if(!font->IsLoaded()) + return; + + // Ugly...but doing it by going through all panes is more ugly + // TODO: move it to somewhere else + if(lineWidths.empty()) + ((Textbox *) this)->SetTextWidth(font); + + if(lineWidths.empty()) + return; + + SetupGX(resources); + + GX_LoadPosMtxImm(modelview, GX_PNMTX0); + + // Setup text color + GXColor color0 = { header->color[0].r, + header->color[0].g, + header->color[0].b, + MultiplyAlpha(header->color[0].a, parent_alpha) }; + + GXColor color1 = { header->color[1].r, + header->color[1].g, + header->color[1].b, + MultiplyAlpha(header->color[1].a, parent_alpha) }; + + u32 lastSheetIdx = 0xffff; + float scale = header->font_size /(float)font->CharacterHeight(); + + // use complete text width if not aligned to middle + float textWidth = (GetAlignHor() == 1) ? lineWidths[0] : frameWidth; + + // position offset calculation for first line...why the hell is it that complex? + float xPos = -0.5f * ( GetOriginX() * GetWidth() * ws_scale + + GetAlignHor() * (-GetWidth() * ws_scale + textWidth) ); + float yPos = -0.5f * ( GetAlignVer() * -frameHeight + + GetHeight() * (GetAlignVer() - (2 - GetOriginY())) ) + - header->font_size; + + // store the character width here for later use, it's constant over the text + float charWidth = scale * (float)font->CharacterWidth(); + int lineNumber = 0; + + for(const u16 *txtString = text; *txtString != 0; txtString++) + { + if(*txtString == '\n') + { + lineNumber++; + // use complete text width if not aligned to middle + textWidth = (GetAlignHor() == 1) ? lineWidths[lineNumber] : frameWidth; + // calculate text position depending on line width + xPos = -0.5f * (GetOriginX() * GetWidth() * ws_scale + + GetAlignHor() * (-GetWidth() * ws_scale + textWidth)); + // go one line down + yPos -= (header->font_size + header->space_line); + continue; + } + + const WiiFont::CharInfo *charInfo = font->GetCharInfo(*txtString); + if(!charInfo) + continue; + + if(charInfo->sheetIdx != lastSheetIdx) + { + lastSheetIdx = charInfo->sheetIdx; + + if(!font->Apply(charInfo->sheetIdx)) + continue; + } + + if(charInfo->unk) + xPos += scale * (float)charInfo->advanceKerning; + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + + GX_Position3f32(xPos, yPos, 0.f); + GX_Color4u8(color1.r, color1.g, color1.b, color1.a); + GX_TexCoord2f32(charInfo->s1, charInfo->t2); + + GX_Position3f32(xPos + charWidth, yPos, 0.f); + GX_Color4u8(color1.r, color1.g, color1.b, color1.a); + GX_TexCoord2f32(charInfo->s2, charInfo->t2); + + GX_Position3f32(xPos + charWidth, yPos + header->font_size, 0.f); + GX_Color4u8(color0.r, color0.g, color0.b, color0.a); + GX_TexCoord2f32(charInfo->s2, charInfo->t1); + + GX_Position3f32(xPos, yPos + header->font_size, 0.f); + GX_Color4u8(color0.r, color0.g, color0.b, color0.a); + GX_TexCoord2f32(charInfo->s1, charInfo->t1); + + GX_End(); + + xPos += scale * (float)charInfo->advanceGlyphX; + } +} + +void Textbox::ProcessHermiteKey(const KeyType& type, float value) +{ + if (type.type == ANIMATION_TYPE_VERTEX_COLOR) // vertex color + { + if(type.target < 4) + { + (&header->color[0].r)[type.target] = FLOAT_2_U8(value); + return; + } + else if(type.target >= 8 && type.target < 12) + { + (&header->color[1].r)[type.target - 8] = FLOAT_2_U8(value); + return; + } + } + Base::ProcessHermiteKey(type, value); +} + +void Textbox::ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data) +{ + Base::ProcessStepKey(type, data); +} diff --git a/source/banner/Textbox.h b/source/banner/Textbox.h new file mode 100644 index 0000000..96c815f --- /dev/null +++ b/source/banner/Textbox.h @@ -0,0 +1,85 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - giantpune +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef WII_BNR_TEXTBOX_H_ +#define WII_BNR_TEXTBOX_H_ + +#include "Pane.h" + +class WiiFont; + +class Textbox : public Pane +{ +public: + typedef Pane Base; + + Textbox() : header(NULL), text(NULL), frameWidth(0.f), frameHeight(0.f) + { } + + static const u32 MAGIC = MAKE_FOURCC('t', 'x', 't', '1'); + + void Load(Pane::Header *file); + + u8 GetAlignHor() const { return textAlignHor; } + u8 GetAlignVer() const { return textAlignVer; } + + void SetText(const u16 *t) { text = t; lineWidths.clear(); } + +protected: + void ProcessHermiteKey(const KeyType& type, float value); + void ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data); + +private: + void Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &view) const; + void SetupGX(const BannerResources& resources) const; + void SetTextWidth(WiiFont *font); + + struct Header + { + u16 text_buf_bytes; + u16 text_str_bytes; + u16 material_index; + u16 font_index; + u8 text_alignment; + u8 pad1; // ? + u8 pad2[2]; + u32 text_str_offset; + GXColor color[2]; + float font_size; + float height; // seems to work better for offset calculation + float space_char; + float space_line; + } __attribute__((packed)); + + Textbox::Header *header; + const u16 *text; + float frameWidth; + float frameHeight; + u8 textAlignVer; + u8 textAlignHor; + std::vector lineWidths; +}; + +#endif diff --git a/source/banner/Texture.cpp b/source/banner/Texture.cpp new file mode 100644 index 0000000..6d5db07 --- /dev/null +++ b/source/banner/Texture.cpp @@ -0,0 +1,149 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok +Copyright (c) 2012 - giantpune + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include +#include +#include +#include "Texture.h" +#include "video.h" + +Texture::~Texture() +{ + if(texture_data) + free(texture_data); +} + +void Texture::Load(const u8 *file ) +{ + if(!file) + return; + + header = (Texture::Header *) file; + + if (header->magic != MAGIC) { + header = NULL; + return; // bad header + } + + u32 texture_count = header->num_textures; + // only support a single texture + if (texture_count > 1) + { + // Never saw it happen + texture_count = 1; + gprintf("texture count > 1\n"); + } + + // read textures + const TPL_Texture *tpl_list = (const TPL_Texture *) (file + header->header_size); + + for(u32 i = 0; i < texture_count; i++) + { + // seek to texture header + const TPL_Texture_Header *texture = (const TPL_Texture_Header *) (file + tpl_list[i].texture_offset); + + u8 mipmap = 0; + u8 bias_clamp = 0; + + if(texture->max_lod > 0) + mipmap = GX_TRUE; + if(texture->lod_bias > 0.0f) + bias_clamp = GX_ENABLE; + + // texture data + u8 *texture_data = (u8 *) (file + texture->offset); + + // seek to/read palette header + if (tpl_list[i].palette_offset != 0) + { + palette = (TPL_Palette_Header *) (file + tpl_list[i].palette_offset); + + // load the texture + GX_InitTexObjCI(&texobj, texture_data, texture->width, texture->height, texture->format, + texture->wrap_s, texture->wrap_t, mipmap, 0); + } + else + { + // load the texture + GX_InitTexObj(&texobj, texture_data, texture->width, texture->height, texture->format, + texture->wrap_s, texture->wrap_t, mipmap); + } + + // filter mode + if(mipmap) + { + GX_InitTexObjLOD(&texobj, texture->min, texture->mag, texture->min_lod, texture->max_lod, + texture->lod_bias, bias_clamp, bias_clamp, texture->edge_lod); + } + } +} + +//! This function is to load custom texture data and replace the original one. +void Texture::LoadTextureData(const u8 *data, u16 width, u16 height, u8 fmt) +{ + if(texture_data) + free(texture_data); + + int tex_size = GX_GetTexBufferSize(width, height, fmt, GX_FALSE, 0); + texture_data = (u8*) memalign(32, tex_size); + if(!texture_data) + return; + + memcpy(texture_data, data, tex_size); + DCFlushRange(texture_data, tex_size); + + GX_InitTexObj(&texobj, texture_data, width, height, fmt, 0, 0, GX_FALSE); +} + +void Texture::Apply(u8 &tlutName, u8 map_id, u8 wrap_s, u8 wrap_t) const +{ + if(!header) + return; + + if(tlutName >= 20 || map_id >= 8) + return; + + // create a temporary texture object to not modify the original with the wrap_s and wrap_t parameters + GXTexObj tmpTexObj; + for(int i = 0; i < 8; ++i) + tmpTexObj.val[i] = texobj.val[i]; + + // assume that if there is a palette header, then this format is a CIx one + if(palette) + { + // seek to/read palette data + u8 *tlut_data = (u8 *) (((u8 *) header) + palette->offset); + + // load tlut + GXTlutObj tlutobj; + GX_InitTlutObj(&tlutobj, tlut_data, palette->format, palette->num_items ); + GX_LoadTlut(&tlutobj, tlutName); + GX_InitTexObjTlut((GXTexObj *) &tmpTexObj, tlutName); + tlutName++; + } + + GX_InitTexObjWrapMode((GXTexObj *) &tmpTexObj, wrap_s, wrap_t); + GX_LoadTexObj((GXTexObj *) &tmpTexObj, map_id); +} diff --git a/source/banner/Texture.h b/source/banner/Texture.h new file mode 100644 index 0000000..de6cfa7 --- /dev/null +++ b/source/banner/Texture.h @@ -0,0 +1,102 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok +Copyright (c) 2012 - giantpune + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef TEXTURE_H_ +#define TEXTURE_H_ + +#include +#include +#include +#include "BannerTools.h" + +class Texture +{ +public: + static const u32 MAGIC = MAKE_FOURCC(0x00, ' ', 0xAF, 0x30); + + Texture() : header(NULL), palette(NULL), texture_data(NULL) {} + virtual ~Texture(); + + void Load(const u8 *texture); + const std::string &getName() const { return name; } + void setName(const std::string& _name) { name = _name; } + + // load custom data into the texture object + void LoadTextureData(const u8 *data, u16 width, u16 height, u8 fmt); + + void Apply(u8 &tlutName, u8 map_id, u8 wrap_s, u8 wrap_t) const; +private: + struct Header + { + u32 magic; + u32 num_textures; + u32 header_size; + } __attribute__((packed)) ; + + struct TPL_Texture + { + u32 texture_offset; + u32 palette_offset; + } __attribute__((packed)) ; + + struct TPL_Texture_Header + { + u16 height; + u16 width; + u32 format; + u32 offset; + u32 wrap_s; + u32 wrap_t; + u32 min; + u32 mag; + f32 lod_bias; + u8 edge_lod; + u8 min_lod; + u8 max_lod; + u8 unpacked; + } __attribute__((packed)); + + struct TPL_Palette_Header + { + u16 num_items; + u8 unpacked; + u8 pad; + u32 format; + u32 offset; + } __attribute__((packed)); + + Texture::Header *header; + TPL_Palette_Header *palette; + u8 *texture_data; + GXTexObj texobj; + std::string name; +}; + +class TextureList : public std::vector +{ + public: + static const u32 MAGIC = MAKE_FOURCC('t', 'x', 'l', '1'); +}; + +#endif diff --git a/source/banner/WiiFont.cpp b/source/banner/WiiFont.cpp new file mode 100644 index 0000000..c9b4bf6 --- /dev/null +++ b/source/banner/WiiFont.cpp @@ -0,0 +1,387 @@ +/* +Copyright (c) 2012 - giantpune +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include +#include "WiiFont.h" + +WiiFont::WiiFont() + : header(NULL) + , finf(NULL) + , tglp(NULL) + , cwdh(NULL) + , font_loaded(false) +{ +} + +WiiFont::~WiiFont() +{ + std::map::iterator itr; + + for (itr = textureMap.begin(); itr != textureMap.end(); itr++) + { + if(itr->second.allocated && itr->second.texture_data) + free(itr->second.texture_data); + } +} + +bool WiiFont::Load(const u8 *file) +{ + if(!file) + return false; + + header = (WiiFont::Header *) file; + + if((header->magic != MAGIC_FONT && header->magic != MAGIC_FONT_ARCHIVE) + || header->version != MAGIC_VERSION) + { + header = NULL; + return false; + } + + const u8 *position = ((const u8 *)header) + header->header_len; + + for(u32 i = 0; i < header->section_count; ++i) + { + section_t *section = (section_t *) position; + position += section->size; + + switch( section->magic ) + { + case MAGIC_GLYPH_GROUP: + glgr = (GlgrHeader *) section; + break; + case MAGIC_FONT_INFORMATION: + finf = (FinfHeader *) section; + break; + case MAGIC_TEXTURE_GLYPH: + tglp = (TglpHeader *) section; + break; + case MAGIC_CHARACTER_WIDTH: + cwdh = (CwdhHeader *) section; + break; + case MAGIC_CHARACTER_CODE_MAP: + ParseCmap((CmapEntry *) (section + 1)); + break; + default: + // ignore + gprintf("Uknown section %.4s\n", (char *) §ion->magic); + break; + } + } + + // Some sanity checks + if(!finf || !tglp || !cwdh) + return false; + + if(finf->tglpOffset > header->filesize || finf->cwdhOffset > header->filesize + || finf->cmapOffset > header->filesize) + return false; + + font_loaded = true; + + return true; +} + +inline bool WiiFont::CheckCmap(u16 charCode, u16 mapValue) +{ + std::map::iterator it = cmap.find(charCode); + if(it != cmap.end()) + { + if((*it).second != mapValue) + { + gprintf("Duplicate characters\n"); + return false; + } + } + return true; +} + +bool WiiFont::ParseCmap(CmapEntry *cmapEntry) +{ + if(!cmapEntry) + return false; + + while(true) + { + switch(cmapEntry->type) + { + case 0: + { + for(u16 i = cmapEntry->charCode, j = cmapEntry->start; j < cmapEntry->end; j++, i++) + { + if(!CheckCmap(j, i)) + return false; + cmap[j] = i; + } + break; + } + case 1: + { + u16 idx = 0; + u16 *idxPointer = &cmapEntry->charCode; + for(u32 i = cmapEntry->start; i < cmapEntry->end; i++) + { + u16 m_idx = idxPointer[idx++]; + if(m_idx == 0xffff) + continue; + + if(!CheckCmap(i, m_idx)) + return false; + + cmap[i] = m_idx; + } + break; + } + case 2: + { + u16 ind, character; + u16 *charData = (u16 *) (cmapEntry + 1); + for(u32 i = 0; i < cmapEntry->charCode; i++) + { + character = charData[0]; + ind = charData[1]; + charData += 2; + + if(!CheckCmap(character, ind)) + return false; + + cmap[character] = ind; + } + break; + } + default: + gprintf( "unknown cmap type\n" ); + return false; + } + + if(cmapEntry->pos == 0) + return true; + + cmapEntry = (CmapEntry *)(((u8 *)header) + cmapEntry->pos); + } +} + +const WiiFont::CharInfo *WiiFont::GetCharInfo(u16 charCode) +{ + if(!finf || !tglp || !cwdh) + return NULL; + + // see if the character already exists in our cache + std::map::iterator itr = charInfoMap.find(charCode); + if(itr != charInfoMap.end()) + return &itr->second; + + u16 idx = CharToIdx(charCode); + if(idx > cwdh->endIdx) + { + gprintf( "idx > cwdh->endIdx" ); + return NULL; + } + + Cwdh *cwdh2 = (Cwdh*) (((u8 *)header) + finf->cwdhOffset + 8); + + u32 chars_per_texture = (tglp->charColumns * tglp->charRows); + u32 tex_idx = idx / chars_per_texture; + u32 row = (idx - chars_per_texture * tex_idx) / tglp->charColumns; + u32 col = (idx - chars_per_texture * tex_idx) - ( tglp->charColumns * row ); + + f32 _s1 = ((tglp->cellWidth + 1) * col) / (f32)tglp->width; + f32 _s2 = _s1 + CharacterWidth() / (f32)tglp->width; + + // this is good vertically but horizontal without it it looks clearer + f32 _t1 = ((tglp->cellHeight + 1) * row + 0.5f * (CharacterHeight() - (tglp->cellHeight + 1))) / (f32)tglp->height; + f32 _t2 = _t1 + CharacterHeight() / (f32)tglp->height; + + CharInfo charInfo; + charInfo.sheetIdx = tex_idx; + charInfo.s1 = _s1; + charInfo.s2 = _s2; + charInfo.t1 = _t1; + charInfo.t2 = _t2; + charInfo.advanceGlyphX = cwdh2[idx].advanceGlyphX; + charInfo.unk = cwdh2[idx].unk; + charInfo.advanceKerning = cwdh2[idx].advanceKerning; + + charInfoMap[charCode] = charInfo; + return &charInfoMap[charCode]; +} + +GXTexObj *WiiFont::LoadTextureObj(u16 tex_idx) +{ + if(!font_loaded || tex_idx >= tglp->texCnt) + return NULL; + + // init texture and add it to the list + TextureCache chacheStruct; + + if(header->magic == MAGIC_FONT_ARCHIVE) + { + chacheStruct.texture_data = GetUnpackedTexture(tex_idx); + chacheStruct.allocated = true; + } + else + { + chacheStruct.texture_data = ((u8 *) header) + tglp->dataOffset + tex_idx * tglp->texSize; + chacheStruct.allocated = false; + } + + if(!chacheStruct.texture_data) + return NULL; + + GX_InitTexObj( &chacheStruct.texObj, chacheStruct.texture_data, tglp->width, tglp->height, 0, 0, 0, true ); + GX_InitTexObjLOD( &chacheStruct.texObj, GX_LINEAR,GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_DISABLE, GX_FALSE, GX_ANISO_1 ); + + textureMap[tex_idx] = chacheStruct; + return &textureMap[tex_idx].texObj; +} + +bool WiiFont::Apply(u16 tex_indx) +{ + if(!font_loaded) + return false; + + if(tex_indx >= tglp->texCnt) + return false; + + GXTexObj *tex_obj; + + // Load character texture from cache if available otherwise create cache + std::map::iterator itr = textureMap.find(tex_indx); + if(itr != textureMap.end()) + tex_obj = &itr->second.texObj; + else + tex_obj = LoadTextureObj(tex_indx); + + // no texture for this character found + if(!tex_obj) + return false; + + GX_LoadTexObj(tex_obj, GX_TEXMAP0); + GX_InvalidateTexAll(); + return true; +} + +// giantpunes little magic function +bool WiiFont::Decompress_0x28( unsigned char *outBuf, u32 outLen, const unsigned char *inBuf, u32 inLen ) +{ + if( outLen & 3 )// this copies 32 bits at a time, so it probably needs to be aligned + { + gprintf( "length not aligned to 32 bits\n" ); + return false; + } + const u32 root_offset = 5; + u32 symbol = 0; + u32 counter = 0; + u32 inIdx = 0; + u32 outIdx = 0; + u32 *in32 = (u32*)( ( inBuf + 6 ) + ( ( inBuf[ 4 ] << 1 ) ) ); + u32 *out32 = (u32*)outBuf; + u8 *p = (u8*)inBuf + root_offset; + + outLen >>= 2; //we are copying 4 bytes at a time + while( outLen ) + { + for( u32 i = 0, leaf = p[ 0 ], bits = __builtin_bswap32( in32[ inIdx ] ) + ; i < 0x20 && outLen + ; i++, leaf = p[ 0 ], bits <<= 1 ) + { + u32 topBit = bits >> 31; + u8 d = 2 - ((u64)p & 1); + p += topBit + ( ( leaf << 1 ) & 0x7e ) + d; + + if( !( p > (u8*)inBuf ) && ( p < (u8*)inBuf + inLen ) ) + { + gprintf( "out of range 1\n" ); + return false; + } + + if( ( ( leaf << ( topBit ) ) & ( 1 << 7 ) ) ) // p->isLeaf + { + symbol = ( ( p[ 0 ] << 0x18 ) | ( symbol >> 8 ) ); + p = (u8*)inBuf + root_offset; // p = root + if( counter++ > 2 ) + { + out32[ outIdx++ ] = __builtin_bswap32( symbol );// buf[bufcur++] = p->symbol + counter = 0; // reset counter + outLen--; // decrease amount to copy + } + } + } + if( inIdx++ >= ( inLen >> 2 ) ) + { + gprintf( "out of range 2\n" ); + return false; + } + } + return true; +} + +u8 *WiiFont::GetUnpackedTexture(u16 sheetNo) +{ + u8 *data = (u8 *) header; + u32 compressedSize; + u32 off = 0; + + // skip over all the sheets till we get the one we want + for( u32 i = 0; i < sheetNo; i++ ) + { + compressedSize = *(u32*)( data + tglp->dataOffset + off ); + off += compressedSize + 4; + } + + compressedSize = *(u32*)( data + tglp->dataOffset + off ); + + u32 uncompressedSize = *(u32*)( data + tglp->dataOffset + off + 4 ); + if( (uncompressedSize & 0xff000000) != 0x28000000 )// looks like all the sheets in wbf1 and wbf2.brfna are 0x28 + { + gprintf( "Brfna::LoadSheets(): unknown data type\n" ); + return NULL; + } + uncompressedSize = ( __builtin_bswap32( uncompressedSize ) >> 8 ); + if( !uncompressedSize )// is this right? it looks like it is. but it SHOULD only happen for files over 0xffffff bytes + { + uncompressedSize = __builtin_bswap32(*(u32*)( data + tglp->dataOffset + off + 8 )); + } + if( uncompressedSize != glgr->sheet_size ) + { + gprintf( "uncompressedSize != glgr->sheet_size %08x\n", uncompressedSize ); + return NULL; + } + + // decompress + u8* sheetData = (u8*)memalign( 32, uncompressedSize );// buffer needs to be 32bit aligned + if( !sheetData ) + return NULL; + + if( !Decompress_0x28( sheetData, uncompressedSize, ( data + tglp->dataOffset + off + 4 ), compressedSize ) ) + { + free( sheetData ); + return NULL; + } + + // Flush cache + DCFlushRange(sheetData, uncompressedSize); + + return sheetData; +} diff --git a/source/banner/WiiFont.h b/source/banner/WiiFont.h new file mode 100644 index 0000000..3861c08 --- /dev/null +++ b/source/banner/WiiFont.h @@ -0,0 +1,226 @@ +/* +Copyright (c) 2012 - giantpune +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef __WII_FONT_H_ +#define __WII_FONT_H_ + +#include +#include + +#include "Pane.h" + +class WiiFont +{ +public: + static const u32 MAGIC_FONT = MAKE_FOURCC('R', 'F', 'N', 'T'); + static const u32 MAGIC_FONT_ARCHIVE = MAKE_FOURCC('R', 'F', 'N', 'A'); + static const u32 MAGIC_VERSION = 0xFEFF0104; + static const u32 MAGIC_GLYPH_GROUP = MAKE_FOURCC('G', 'L', 'G', 'R'); + static const u32 MAGIC_FONT_INFORMATION = MAKE_FOURCC('F', 'I', 'N', 'F'); + static const u32 MAGIC_TEXTURE_GLYPH = MAKE_FOURCC('T', 'G', 'L', 'P'); + static const u32 MAGIC_CHARACTER_CODE_MAP = MAKE_FOURCC('C', 'M', 'A', 'P'); + static const u32 MAGIC_CHARACTER_WIDTH = MAKE_FOURCC('C', 'W', 'D', 'H'); + + WiiFont(); + ~WiiFont(); + + // load the file + bool Load(const u8 *file); + + // apply texture, non-const because we load texture on demand + bool Apply(u16 tex_idx); + + // struct to hold info for a character to keep from searching and calculating it all every frame + struct CharInfo + { + u32 sheetIdx; + f32 s1; + f32 t1; + f32 s2; + f32 t2; + s8 advanceKerning; + u8 unk; + s8 advanceGlyphX; + }; + + // get the character information + const CharInfo *GetCharInfo(u16 charCode); + + // check if the font was loaded correctly + bool IsLoaded() const { return font_loaded; } + + // get some parameters from the FINF header + u8 CharacterWidth() const { return finf ? finf->charWidth : 0; } + u8 CharacterHeight() const { return finf ? finf->height : 0; } + + const std::string& getName() const { return name; } + void SetName(const std::string& _name) { name = _name; } + +private: + struct Header + { + u32 magic; + u32 version; + u32 filesize; + u16 header_len; + u16 section_count; + } __attribute__((packed)); + + struct GlgrHeader + { + u32 magic; + u32 sectionSize; + u32 sheet_size; + u16 glyphs_per_sheet; + u16 set_count; + u16 sheet_count; + u16 cwdh_count; + u16 cmap_count; + }__attribute__(( packed )); + + struct FinfHeader + { + u32 magic; + u32 headerSize; // finf size + u8 unk8_1; // font type? + u8 leading; // + u16 defaultChar; + u8 leftMargin; + u8 charWidth; + u8 fullWidth; + u8 encoding; + u32 tglpOffset; // TLGP offset + u32 cwdhOffset; // CWDH offset + u32 cmapOffset; // CMAP offset + u8 height; + u8 width; + u8 ascent; + u8 unk8_10; + } __attribute__(( packed )); + + struct TglpHeader + { + u32 magic; + u32 tglpSize; // TGLP size + + u8 cellWidth; // font width - 1 + u8 cellHeight; // font heigh - 1 + u8 baselinePos; + u8 maxCharWidth; + + u32 texSize; // length of 1 image + + u16 texCnt; // number of images + u16 texType; // + u16 charColumns; // character per row + u16 charRows; // characters per column + u16 width; // width of image + u16 height; // height of image + u32 dataOffset; // data offset + } __attribute__(( packed )); + + struct CwdhHeader + { + u32 magic; + u32 length; // section length? + u16 startIdx; // + u16 endIdx; // + u32 next; // + + } __attribute__(( packed )); + + struct CmapEntry + { + u16 start; + u16 end; + u16 type; + u16 pad; + u32 pos; + u16 charCode; + } __attribute__(( packed )); + + struct Cwdh + { + s8 advanceKerning; + u8 unk; + s8 advanceGlyphX; + } __attribute__(( packed )); + + // font texture decompress functions + static bool Decompress_0x28( unsigned char *outBuf, u32 outLen, const unsigned char *inBuf, u32 inLen ); + u8 *GetUnpackedTexture(u16 sheetNo); + + // load a GX texture from index + GXTexObj *LoadTextureObj(u16 texture_idx); + + // cmap parser + bool ParseCmap(CmapEntry *cmapEntry); + + // just a duplicate check + bool CheckCmap(u16 charCode, u16 mapValue); + + // get index of a character + u16 CharToIdx(u16 charCode) + { + std::map::iterator itr = cmap.find(charCode); + if(itr != cmap.end()) + return itr->second; + + return finf->defaultChar; + } + + WiiFont::Header *header; + + // pointers to each sections + FinfHeader *finf; + TglpHeader *tglp; + CwdhHeader *cwdh; + GlgrHeader *glgr; + + // struct to contain a decompressed texture caches + struct TextureCache + { + u8* texture_data; + bool allocated; + GXTexObj texObj; + }; + std::map textureMap; + + // character info cache map + std::map charInfoMap; + + // holds all the character codes and their index within the font + std::map cmap; + + std::string name; + bool font_loaded; +}; + +class FontList : public std::vector +{ +public: + static const u32 MAGIC = MAKE_FOURCC('f', 'n', 'l', '1'); +}; + +#endif diff --git a/source/banner/Window.cpp b/source/banner/Window.cpp new file mode 100644 index 0000000..d3a89e1 --- /dev/null +++ b/source/banner/Window.cpp @@ -0,0 +1,51 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include "Window.h" + +void Window::Load(Pane::Header *file) +{ + if(!file) + return; + + const u8 *section_start = (const u8 *)file; + + Pane::Load(file); + header = (Window::Header *) (file+1); + + // read content + QuadPane::Load((QuadPane::Header *)(section_start + header->content_offset)); + + // read frames + const u32 *frame_offsets = (const u32 *) (section_start + header->frame_table_offset); + for(u32 i = 0; i < header->frame_count; i++) + frames.push_back((Frame *) (section_start + frame_offsets[i])); +} + +void Window::Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &view) const +{ + // TODO: handle "inflation" + // TODO: handle "frames" and "texture_flip" + + QuadPane::Draw(resources, render_alpha, ws_scale, view); +} diff --git a/source/banner/Window.h b/source/banner/Window.h new file mode 100644 index 0000000..9788081 --- /dev/null +++ b/source/banner/Window.h @@ -0,0 +1,65 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef WII_BNR_WINDOW_H_ +#define WII_BNR_WINDOW_H_ + +#include "QuadPane.h" + +class Window : public QuadPane +{ +public: + typedef QuadPane Base; + + static const u32 MAGIC = MAKE_FOURCC('w', 'n', 'd', '1'); + + void Load(Pane::Header *file); + +private: + void Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &view) const; + + struct inflation + { + float l, r, t, b; + }; + + struct Header + { + inflation infl; + u8 frame_count; + u8 pad[3]; + u32 content_offset; + u32 frame_table_offset; + } __attribute__((packed)); + + struct Frame + { + u16 material_index; + u8 texture_flip; + } __attribute__((packed)); + + Header *header; + std::vector frames; +}; + +#endif diff --git a/source/cheats/cheatmenu.cpp b/source/cheats/cheatmenu.cpp new file mode 100644 index 0000000..5981913 --- /dev/null +++ b/source/cheats/cheatmenu.cpp @@ -0,0 +1,216 @@ +#include +#include + +#include "GUI/gui.h" +#include "GUI/gui_optionbrowser.h" +#include "prompts/PromptWindows.h" +#include "language/gettext.h" +#include "themes/CTheme.h" +#include "FileOperations/fileops.h" +#include "menu.h" +#include "sys.h" +#include "gct.h" + +/**************************************************************************** + * CheatMenu + ***************************************************************************/ +int CheatMenu(const char * gameID) +{ + int choice = 0; + bool exit = false; + int ret = 1; + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData settingsbg(Resources::GetFile("settings_background.png"), Resources::GetFileSize("settings_background.png")); + GuiImage settingsbackground(&settingsbg); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + GuiText backBtnTxt(tr( "Back" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + backBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30); + GuiImage backBtnImg(&btnOutline); + GuiButton backBtn(&backBtnImg, &backBtnImg, 2, 3, -195, 400, &trigA, NULL, btnSoundClick2, 1); + backBtn.SetLabel(&backBtnTxt); + backBtn.SetTrigger(&trigB); + + GuiText updateBtnTxt(tr( "Update" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + updateBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30); + GuiImage updateBtnImg(&btnOutline); + GuiButton updateBtn(&updateBtnImg, &updateBtnImg, 2, 3, 0, 400, &trigA, NULL, btnSoundClick2, 1); + updateBtn.SetLabel(&updateBtnTxt); + + GuiText createBtnTxt(tr( "Create" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + createBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30); + GuiImage createBtnImg(&btnOutline); + GuiButton createBtn(&createBtnImg, &createBtnImg, 2, 3, 195, 400, &trigA, NULL, btnSoundClick2, 1); + createBtn.SetLabel(&createBtnTxt); + + char txtfilename[55]; + snprintf(txtfilename, sizeof(txtfilename), "%s%s.txt", Settings.TxtCheatcodespath, gameID); + + GCTCheats gctCheats; + int check = gctCheats.openTxtfile(txtfilename); + + int download = 0; + int blankchoice = 0; + + switch (check) + { + case -1: + blankchoice = WindowPrompt(tr( "Error" ), tr( "Cheatfile is blank" ), tr( "Delete" ), tr( "OK" )); + if(blankchoice) + { + char gctPath[200]; + snprintf(gctPath, sizeof(gctPath), "%s%.6s.TXT", Settings.TxtCheatcodespath, gameID); + RemoveFile(gctPath); + } + break; + case 0: + download = WindowPrompt(tr( "Error" ), tr( "No Cheatfile found" ), tr( "Download Now" ), tr( "Cancel" )); + if (download == 1) + { + download = CodeDownload(gameID); + if (download < 0 || gctCheats.openTxtfile(txtfilename) != 1) + break; + } + else + break; + case 1: + int cntcheats = gctCheats.getCnt(); + OptionList cheatslst; + GuiOptionBrowser chtBrowser(400, 280, &cheatslst, "bg_options_settings.png"); + chtBrowser.SetPosition(0, 90); + chtBrowser.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + chtBrowser.SetClickable(true); + + GuiText titleTxt(gctCheats.getGameName().c_str(), 28, ( GXColor ) {0, 0, 0, 255}); + titleTxt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt.SetMaxWidth(350, SCROLL_HORIZONTAL); + titleTxt.SetPosition(12, 40); + + char gctPath[200]; + snprintf(gctPath, sizeof(gctPath), "%s%.6s.gct", Settings.Cheatcodespath, gameID); + u8 *gctBuf = NULL; + u32 gctSize = 0; + LoadFileToMem(gctPath, &gctBuf, &gctSize); + + for (int i = 0; i < cntcheats; i++) + { + cheatslst.SetValue(i, "%s", gctCheats.getCheatName(i).c_str()); + // search after header and before footer + if(gctBuf && gctCheats.IsCheatIncluded(i, gctBuf, gctSize)) + cheatslst.SetName(i, tr("ON")); + else + cheatslst.SetName(i, tr("OFF")); + } + + HaltGui(); + GuiWindow w(screenwidth, screenheight); + w.Append(&settingsbackground); + w.Append(&titleTxt); + w.Append(&backBtn); + w.Append(&updateBtn); + w.Append(&createBtn); + w.Append(&chtBrowser); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&w); + ResumeGui(); + + while (!exit) + { + usleep(100000); + + ret = chtBrowser.GetClickedOption(); + if (ret >= 0) + { + const char *strCheck = cheatslst.GetName(ret); + if (strCheck && strcmp(strCheck, tr("ON")) == 0) + { + cheatslst.SetName(ret, "%s", tr("OFF")); + } + else if (strCheck && strcmp(strCheck, tr("OFF")) == 0) + { + cheatslst.SetName(ret, "%s", tr("ON")); + } + } + + if (createBtn.GetState() == STATE_CLICKED) + { + if (cntcheats > 0) + { + vector vActiveCheats; + for (int i = 0; i < cntcheats; i++) + { + const char *strCheck = cheatslst.GetName(i); + if (strCheck && strcmp(strCheck, tr("ON")) == 0) + vActiveCheats.push_back(i); + } + if (vActiveCheats.size() == 0) + { + if(WindowPrompt(tr( "Error" ), tr( "No cheats were selected! Should the GCT file be deleted?" ), tr("Yes"), tr("Cancel"))) + { + RemoveFile(gctPath); + w.Remove(&chtBrowser); + for (int i = 0; i < gctCheats.getCnt(); i++) + cheatslst.SetName(i, tr("OFF")); + w.Append(&chtBrowser); + } + } + else + { + CreateSubfolder(Settings.Cheatcodespath); + gctCheats.createGCT(vActiveCheats, gctPath); + WindowPrompt(tr( "GCT File created" ), NULL, tr( "OK" )); + } + } + else + WindowPrompt(tr( "Error" ), tr( "Could not create GCT file" ), tr( "OK" )); + + mainWindow->SetState(STATE_DISABLED); + w.SetState(STATE_DEFAULT); + createBtn.ResetState(); + } + + if (backBtn.GetState() == STATE_CLICKED) + { + backBtn.ResetState(); + exit = true; + break; + } + + if(updateBtn.GetState() == STATE_CLICKED) + { + download = CodeDownload(gameID); + if (download >= 0 && gctCheats.openTxtfile(txtfilename) == 1) + { + w.Remove(&chtBrowser); + cheatslst.ClearList(); + cntcheats = gctCheats.getCnt(); + for (int i = 0; i < cntcheats; i++) + { + cheatslst.SetValue(i, "%s", gctCheats.getCheatName(i).c_str()); + // search after header and before footer + if(gctBuf && gctCheats.IsCheatIncluded(i, gctBuf, gctSize)) + cheatslst.SetName(i, tr("ON")); + else + cheatslst.SetName(i, tr("OFF")); + } + w.Append(&chtBrowser); + } + updateBtn.ResetState(); + } + } + if(gctBuf) + free(gctBuf); + HaltGui(); + mainWindow->SetState(STATE_DEFAULT); + mainWindow->Remove(&w); + ResumeGui(); + break; + } + + return choice; +} diff --git a/source/cheats/cheatmenu.h b/source/cheats/cheatmenu.h new file mode 100644 index 0000000..d087d9c --- /dev/null +++ b/source/cheats/cheatmenu.h @@ -0,0 +1,13 @@ +/**************************************************************************** + * Cheat Menu + * USB Loader GX 2009 + * + * cheatmenu.h + ***************************************************************************/ + +#ifndef _CHEATMENU_H_ +#define _CHEATMENU_H_ + +int CheatMenu(const char * gameID); + +#endif diff --git a/source/cheats/gct.cpp b/source/cheats/gct.cpp new file mode 100644 index 0000000..26283bb --- /dev/null +++ b/source/cheats/gct.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** + * Copyright (C) 2009 nIxx + * Copyright (C) 2012 Dimok + * + * 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 +#include "gct.h" + +#define ERRORRANGE "Error: CheatNr out of range" + +//Header and Footer +static const char GCT_Header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde }; +static const char GCT_Footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +GCTCheats::GCTCheats(void) +{ +} + +GCTCheats::~GCTCheats(void) +{ +} + +void GCTCheats::Clear(void) +{ + cheatList.clear(); + sGameID.clear(); + sGameTitle.clear(); + +} + +string GCTCheats::getGameName(void) +{ + return sGameTitle; +} + +string GCTCheats::getGameID(void) +{ + return sGameID; +} + +vector GCTCheats::getCheat(int nr) +{ + if((unsigned int)nr >= cheatList.size()) + return vector(); + + return cheatList[nr].sCheats; +} + +string GCTCheats::getCheatName(int nr) +{ + if((unsigned int)nr >= cheatList.size()) + return ERRORRANGE; + + return cheatList[nr].sCheatName; +} + +string GCTCheats::getCheatComment(int nr) +{ + if((unsigned int)nr >= cheatList.size()) + return ERRORRANGE; + + return cheatList[nr].sCheatComment; +} + +int GCTCheats::createGCT(const vector &vCheats, const char * filename) +{ + if (vCheats.size() == 0 || !filename) + return 0; + + FILE *pFile = fopen(filename, "wb"); + + if (!pFile) + return 0; + + fwrite(GCT_Header, sizeof(GCT_Header), 1, pFile); + + int cnt = vCheats.size(); + int c = 0; + while (c < cnt) + { + if((unsigned int)vCheats[c] >= cheatList.size()) + continue; + + vector &cheatBuf = cheatList[vCheats[c]].sCheats; + if(cheatBuf.size() > 0) + fwrite((char*)&cheatBuf[0], cheatBuf.size() * sizeof(unsigned int), 1, pFile); + + c++; + } + + fwrite(GCT_Footer, sizeof(GCT_Footer), 1, pFile); + fclose(pFile); + return 1; +} + +static inline void RemoveLineEnds(char *str) +{ + const char *strPtr = str; + while(*strPtr != 0) + { + if(*strPtr == '\n' || *strPtr == '\r') + { + strPtr++; + continue; + } + + *str = *strPtr; + str++; + strPtr++; + } + *str = 0; +} + +int GCTCheats::openTxtfile(const char * filename) +{ + //! clear already loaded things + Clear(); + + FILE *pFile = fopen(filename, "rb"); + if (!pFile) + return 0; + + fseek(pFile, 0, SEEK_END); + int size = ftell(pFile); + fseek(pFile, 0, SEEK_SET); + + if (size <= 0) { + fclose(pFile); + return -1; + } + + const int max_line_size = 4096; + char *line = new (std::nothrow) char[max_line_size]; + if(!line) return -1; + + fgets(line, max_line_size, pFile); + RemoveLineEnds(line); + sGameID = line; + fgets(line, max_line_size, pFile); + RemoveLineEnds(line); + sGameTitle = line; + + while (fgets(line, max_line_size, pFile)) + { + RemoveLineEnds(line); + + if(*line == 0) + continue; + + // first line is the cheat name + CheatEntry cheatEntry; + cheatEntry.sCheatName = line; + + while (fgets(line, max_line_size, pFile)) + { + RemoveLineEnds(line); + + if(*line == 0) // empty line means start of new cheat + break; + + if (IsCode(line)) + { + // remove any garbage (comment) after code + line[8] = 0; + line[17] = 0; + + cheatEntry.sCheats.push_back(strtoul(&line[0], 0, 16)); + cheatEntry.sCheats.push_back(strtoul(&line[9], 0, 16)); + } + else + { + cheatEntry.sCheatComment = line; + } + } + + if(!cheatEntry.sCheats.empty()) + cheatList.push_back(cheatEntry); + } + fclose(pFile); + delete [] line; + return 1; +} + +bool GCTCheats::IsCode(const char *str) +{ + if (strlen(str) >= 17 && str[8] == ' ') + { + // accept strings longer than 17 in case there is a comment on the same line as the code + char part1[9]; + char part2[9]; + snprintf(part1, sizeof(part1), "%c%c%c%c%c%c%c%c", str[0], str[1], str[2], str[3], str[4], str[5], str[6], + str[7]); + snprintf(part2, sizeof(part2), "%c%c%c%c%c%c%c%c", str[9], str[10], str[11], str[12], str[13], str[14], + str[15], str[16]); + if ((strtok(part1, "0123456789ABCDEFabcdef") == NULL) && (strtok(part2, "0123456789ABCDEFabcdef") == NULL)) + { + return true; + } + } + return false; +} + +bool GCTCheats::IsCheatIncluded(int iCheat, const unsigned char *gctBuf, unsigned int gctSize) +{ + if(!gctBuf || (unsigned int)iCheat >= cheatList.size()) + return false; + + vector &Cheat = cheatList[iCheat].sCheats; + int len = Cheat.size() * sizeof(unsigned int); + + for(unsigned int i = sizeof(GCT_Header); i + len <= gctSize - sizeof(GCT_Footer); i += 4) + { + if(memcmp(&Cheat[0], &gctBuf[i], len) == 0) + return true; + } + return false; +} diff --git a/source/cheats/gct.h b/source/cheats/gct.h new file mode 100644 index 0000000..cfeac9d --- /dev/null +++ b/source/cheats/gct.h @@ -0,0 +1,81 @@ +/**************************************************************************** + * Copyright (C) 2009 nIxx + * Copyright (C) 2012 Dimok + * + * 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 _GCT_H +#define _GCT_H + +#include +#include + +using namespace std; + +//!Handles Ocarina TXT Cheatfiles +class GCTCheats +{ + private: + string sGameID; + string sGameTitle; + struct CheatEntry + { + string sCheatName; + string sCheatComment; + vector sCheats; + }; + vector cheatList; + public: + //!Constructor + GCTCheats(void); + //!Destructor + ~GCTCheats(void); + //!Open txt file with cheats + //!\param filename name of TXT file + //!\return error code + int openTxtfile(const char * filename); + //!Creates GCT file + //!\param nr[] array of selected Cheat Numbers + //!\param cnt size of array + //!\param filename name of GCT file + //!\return error code + int createGCT(const vector &vCheats, const char * filename); + //!Gets Count cheats + //!\return Count cheats + int getCnt() const { return cheatList.size(); } + //!Gets Game Name + //!\return Game Name + string getGameName(void); + //!Gets GameID + //!\return GameID + string getGameID(void); + //!Gets cheat data + //!\return cheat data + vector getCheat(int nr); + //!Gets Cheat Name + //!\return Cheat Name + string getCheatName(int nr); + //!Gets Cheat Comment + //!\return Cheat Comment + string getCheatComment(int nr); + //!Clear all loaded cheats + void Clear(void); + //!Check if string is a code + //!\return true/false + bool IsCode(const char *s); + //!Check if cheat is included in GCT buffer + bool IsCheatIncluded(int iCheat, const unsigned char *gctBuf, unsigned int gctSize); +}; + +#endif /* _GCT_H */ diff --git a/source/gecko.c b/source/gecko.c new file mode 100644 index 0000000..3256aa1 --- /dev/null +++ b/source/gecko.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include + +// #define DEBUG_TO_FILE +// #define WIFI_GECKO // don't keep this for released build + +#ifdef WIFI_GECKO +#include +#endif + +/* init-globals */ +static bool geckoinit = false; + +void gprintf(const char *format, ...) +{ + #ifndef DEBUG_TO_FILE + #ifndef WIFI_GECKO + if (!geckoinit) + return; + #endif + #endif + + static char stringBuf[4096]; + int len; + va_list va; + va_start(va, format); + if((len = vsnprintf(stringBuf, sizeof(stringBuf), format, va)) > 0) + { + #ifdef DEBUG_TO_FILE + FILE *debugF = fopen("sd:/debug.txt", "a"); + if(!debugF) + debugF = fopen("sd:/debug.txt", "w"); + if(debugF) + { + fwrite(stringBuf, 1, strlen(stringBuf), debugF); + fclose(debugF); + } + #else + usb_sendbuffer(1, stringBuf, len); + #endif + + #ifdef WIFI_GECKO + wifi_printf(stringBuf); + #endif + } + va_end(va); +} + +bool InitGecko() +{ + u32 geckoattached = usb_isgeckoalive(EXI_CHANNEL_1); + if (geckoattached) + { + usb_flush(EXI_CHANNEL_1); + geckoinit = true; + return true; + } + + return false; +} + +char ascii(char s) +{ + if (s < 0x20) return '.'; + if (s > 0x7E) return '.'; + return s; +} + +void hexdump(void *d, int len) +{ + u8 *data; + int i, off; + data = (u8*) d; + + gprintf("\n 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF"); + gprintf("\n==== =============================================== ================\n"); + + for (off = 0; off < len; off += 16) + { + gprintf("%04x ", off); + for (i = 0; i < 16; i++) + if ((i + off) >= len) + gprintf(" "); + else gprintf("%02x ", data[off + i]); + + gprintf(" "); + for (i = 0; i < 16; i++) + if ((i + off) >= len) + gprintf(" "); + else gprintf("%c", ascii(data[off + i])); + gprintf("\n"); + } +} + +static ssize_t __out_write(struct _reent *r, void *fd, const char *ptr, size_t len) +{ + if(len > 0) + usb_sendbuffer(1, ptr, len); + + return len; +} + +static const devoptab_t gecko_out = { + "stdout", // device name + 0, // size of file structure + NULL, // device open + NULL, // device close + __out_write,// device write + NULL, // device read + NULL, // device seek + NULL, // device fstat + NULL, // device stat + NULL, // device link + NULL, // device unlink + NULL, // device chdir + NULL, // device rename + NULL, // device mkdir + 0, // dirStateSize + NULL, // device diropen_r + NULL, // device dirreset_r + NULL, // device dirnext_r + NULL, // device dirclose_r + NULL, // device statvfs_r + NULL, // device ftruncate_r + NULL, // device fsync_r + NULL, // device deviceData + NULL, // device chmod_r + NULL, // device fchmod_r + NULL, // device rmdir_r +}; + +void USBGeckoOutput() +{ + devoptab_list[STD_OUT] = &gecko_out; + devoptab_list[STD_ERR] = &gecko_out; +} diff --git a/source/gecko.h b/source/gecko.h new file mode 100644 index 0000000..c2228cf --- /dev/null +++ b/source/gecko.h @@ -0,0 +1,29 @@ + +#ifndef _GECKO_H_ +#define _GECKO_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + + char ascii(char s); + +#ifndef NO_DEBUG + //use this just like printf(); + void gprintf(const char *str, ...); + bool InitGecko(); + void hexdump(void *d, int len); + void USBGeckoOutput(); +#else +#define gprintf(...) +#define InitGecko() false +#define hexdump( x, y ) +#endif /* NO_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/homebrewboot/BootHomebrew.cpp b/source/homebrewboot/BootHomebrew.cpp new file mode 100644 index 0000000..532d769 --- /dev/null +++ b/source/homebrewboot/BootHomebrew.cpp @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Controls/DeviceHandler.hpp" +#include "settings/CSettings.h" +#include "system/IosLoader.h" +#include "lstub.h" +#include "sys.h" +#include "gecko.h" + +#define EXECUTE_ADDR ((u8 *) 0x92000000) +#define BOOTER_ADDR ((u8 *) 0x93000000) +#define ARGS_ADDR ((u8 *) 0x93200000) + +extern const u8 app_booter_bin[]; +extern const u32 app_booter_bin_size; + +typedef void (*entrypoint) (void); +extern "C" { void __exception_closeall(); } + +static u8 *homebrewbuffer = EXECUTE_ADDR; +static u32 homebrewsize = 0; +static std::vector Arguments; + +void AddBootArgument(const char *argv) +{ + std::string arg(argv); + Arguments.push_back(arg); +} + +void AddBootArgument(const char *argv, unsigned int size) +{ + std::string arg(argv, size); + Arguments.push_back(arg); +} + +int CopyHomebrewMemory(u8 *temp, u32 pos, u32 len) +{ + homebrewsize += len; + memcpy((homebrewbuffer) + pos, temp, len); + + return 1; +} + +void FreeHomebrewBuffer() +{ + homebrewbuffer = EXECUTE_ADDR; + homebrewsize = 0; + + Arguments.clear(); +} + +static inline bool IsDollZ (const u8 *buf) +{ + return (buf[0x100] == 0x3C); +} + +static int SetupARGV(struct __argv * args) +{ + if (!args) return -1; + + bzero(args, sizeof(struct __argv)); + args->argvMagic = ARGV_MAGIC; + + u32 argc = 0; + u32 position = 0; + u32 stringlength = 1; + + /** Append Arguments **/ + for (u32 i = 0; i < Arguments.size(); i++) + { + stringlength += Arguments[i].size() + 1; + } + + args->length = stringlength; + //! Put the argument into mem2 too, to avoid overwriting it + args->commandLine = (char *) ARGS_ADDR + sizeof(struct __argv); + + /** Append Arguments **/ + for (u32 i = 0; i < Arguments.size(); i++) + { + memcpy(&args->commandLine[position], Arguments[i].c_str(), Arguments[i].size() +1); + position += Arguments[i].size() + 1; + argc++; + } + + args->argc = argc; + + args->commandLine[args->length - 1] = '\0'; + args->argv = &args->commandLine; + args->endARGV = args->argv + 1; + + Arguments.clear(); + + return 0; +} + +static int RunAppbooter() +{ + if (homebrewsize == 0) return -1; + + ExitApp(); + + // Reload IOS 58 if available, else reload Entry IOS + s32 ret = IosLoader::ReloadIosSafe(58); + if(ret < 0 && Settings.EntryIOS != IOS_GetVersion()) + IosLoader::ReloadIosKeepingRights(Settings.EntryIOS); + gprintf("Reloaded to IOS%d\n", IOS_GetVersion()); + + struct __argv args; + SetupARGV(&args); + + u32 cpu_isr; + + DCFlushRange(homebrewbuffer, homebrewsize); + + memcpy(BOOTER_ADDR, app_booter_bin, app_booter_bin_size); + DCFlushRange(BOOTER_ADDR, app_booter_bin_size); + ICInvalidateRange(BOOTER_ADDR, app_booter_bin_size); + + entrypoint entry = (entrypoint) BOOTER_ADDR; + + if (!IsDollZ(homebrewbuffer)) + memcpy(ARGS_ADDR, &args, sizeof(struct __argv)); + else + memset(ARGS_ADDR, 0, sizeof(struct __argv)); + + DCFlushRange(ARGS_ADDR, sizeof(struct __argv) + args.length); + + u64 currentStub = getStubDest(); + loadStub(); + + if (Set_Stub_Split(0x00010001, "UNEO") < 0) + { + if (Set_Stub_Split(0x00010001, "ULNR") < 0) + { + if (!currentStub) currentStub = 0x100000002ULL; + + Set_Stub(currentStub); + } + } + + gprintf("Exiting USBLoaderGX...\n\n"); + + SYS_ResetSystem(SYS_SHUTDOWN, 0, 0); + _CPU_ISR_Disable( cpu_isr ); + __exception_closeall(); + entry(); + _CPU_ISR_Restore( cpu_isr ); + + return 0; +} + +int BootHomebrew(const char * filepath) +{ + FILE *file = fopen(filepath, "rb"); + if (!file) return -1; + + fseek(file, 0, SEEK_END); + u32 filesize = ftell(file); + rewind(file); + + if (fread(homebrewbuffer, 1, filesize, file) != filesize) + { + fclose(file); + DeviceHandler::DestroyInstance(); + Sys_BackToLoader(); + } + + homebrewsize = filesize; + + fclose(file); + + AddBootArgument(filepath); + return RunAppbooter(); +} + +int BootHomebrewFromMem() +{ + return RunAppbooter(); +} diff --git a/source/homebrewboot/BootHomebrew.h b/source/homebrewboot/BootHomebrew.h new file mode 100644 index 0000000..9ed854c --- /dev/null +++ b/source/homebrewboot/BootHomebrew.h @@ -0,0 +1,11 @@ +#ifndef _BOOTHOMEBREW_H_ +#define _BOOTHOMEBREW_H_ + +int BootHomebrew(const char * filepath); +int BootHomebrewFromMem(); +int CopyHomebrewMemory(u8 *temp, u32 pos, u32 len); +void AddBootArgument(const char * argv); +void AddBootArgument(const char * argv, unsigned int size); +void FreeHomebrewBuffer(); + +#endif diff --git a/source/homebrewboot/HomebrewBrowser.cpp b/source/homebrewboot/HomebrewBrowser.cpp new file mode 100644 index 0000000..b33167e --- /dev/null +++ b/source/homebrewboot/HomebrewBrowser.cpp @@ -0,0 +1,472 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "HomebrewBrowser.hpp" +#include "themes/CTheme.h" +#include "prompts/PromptWindows.h" +#include "prompts/HomebrewPrompt.hpp" +#include "language/gettext.h" +#include "network/networkops.h" +#include "utils/minizip/miniunz.h" +#include "prompts/TitleBrowser.h" +#include "homebrewboot/BootHomebrew.h" +#include "FileOperations/fileops.h" +#include "prompts/ProgressWindow.h" +#include "utils/tools.h" +#include "wstring.hpp" +#include "HomebrewXML.h" + +extern u32 infilesize; +extern u32 uncfilesize; +extern char wiiloadVersion[2]; +extern int connection; + +HomebrewBrowser::HomebrewBrowser() + : FlyingButtonsMenu(tr( "Homebrew Launcher" )) +{ + HomebrewList = new DirList(Settings.homebrewapps_path, ".dol,.elf", DirList::Files | DirList::Dirs | DirList::CheckSubfolders); + + if (IsNetworkInit()) + ResumeNetworkWait(); + + wifiNotSet = true; + wifiImgData = Resources::GetImageData("wifi_btn.png"); + wifiToolTip = new GuiTooltip(" "); + wifiImg = new GuiImage(wifiImgData); + wifiBtn = new GuiButton(wifiImgData->GetWidth(), wifiImgData->GetHeight()); + wifiBtn->SetImage(wifiImg); + wifiBtn->SetPosition(300, 400); + wifiBtn->SetSoundOver(btnSoundOver); + wifiBtn->SetSoundClick(btnSoundClick); + wifiBtn->SetEffectGrow(); + wifiBtn->SetAlpha(80); + wifiBtn->SetTrigger(trigA); + Append(wifiBtn); + + channelImgData = Resources::GetImageData("channel_btn.png"); + channelBtnImg = new GuiImage(channelImgData); + channelBtnImg->SetWidescreen(Settings.widescreen); + channelBtn = new GuiButton(channelBtnImg->GetWidth(), channelBtnImg->GetHeight()); + channelBtn->SetPosition(240, 400); + channelBtn->SetImage(channelBtnImg); + channelBtn->SetSoundOver(btnSoundOver); + channelBtn->SetSoundClick(btnSoundClick2); + channelBtn->SetEffectGrow(); + channelBtn->SetTrigger(trigA); + if (Settings.godmode || !(Settings.ParentalBlocks & BLOCK_TITLE_LAUNCHER_MENU)) + Append(channelBtn); + + MainButtonDesc.resize(HomebrewList->GetFilecount()); + MainButtonDescOver.resize(HomebrewList->GetFilecount()); + + for(u32 i = 0; i < 4; ++i) + { + IconImgData[i] = NULL; + IconImg[i] = NULL; + } + + for(int i = 0; i < HomebrewList->GetFilecount(); ++i) + { + MainButtonDesc[i] = new GuiText((char *) NULL, 18, (GXColor) {0, 0, 0, 255}); + MainButtonDesc[i]->SetMaxWidth(MainButtonImgData->GetWidth() - 150, DOTTED); + MainButtonDesc[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + MainButtonDesc[i]->SetPosition(148, 15); + + MainButtonDescOver[i] = new GuiText((char *) NULL, 18, (GXColor) {0, 0, 0, 255}); + MainButtonDescOver[i]->SetMaxWidth(MainButtonImgData->GetWidth() - 150, SCROLL_HORIZONTAL); + MainButtonDescOver[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + MainButtonDescOver[i]->SetPosition(148, 15); + } +} + +HomebrewBrowser::~HomebrewBrowser() +{ + HaltGui(); + delete HomebrewList; + + Remove(wifiBtn); + delete wifiImgData; + delete wifiImg; + delete wifiToolTip; + delete wifiBtn; + + Remove(channelBtn); + delete channelImgData; + delete channelBtnImg; + delete channelBtn; + + for(u32 i = 0; i < MainButtonDesc.size(); ++i) + { + delete MainButtonDesc[i]; + delete MainButtonDescOver[i]; + MainButton[i]->SetLabel(NULL, 1); + MainButton[i]->SetLabelOver(NULL, 1); + } + + if (IsNetworkInit()) + HaltNetworkThread(); +} + +int HomebrewBrowser::Execute() +{ + HomebrewBrowser * Menu = new HomebrewBrowser(); + mainWindow->Append(Menu); + + Menu->ShowMenu(); + + int returnMenu = MENU_NONE; + + while((returnMenu = Menu->MainLoop()) == MENU_NONE); + + delete Menu; + + return returnMenu; +} + +void HomebrewBrowser::AddMainButtons() +{ + HaltGui(); + + for(u32 i = 0; i < 4; ++i) + { + if(IconImgData[i]) + delete IconImgData[i]; + if(IconImg[i]) + delete IconImg[i]; + IconImgData[i] = NULL; + IconImg[i] = NULL; + } + + for(u32 i = 0; i < MainButton.size(); ++i) + MainButton[i]->SetIcon(NULL); + + int FirstItem = currentPage*DISPLAY_BUTTONS; + + for(int i = FirstItem, n = 0; i < (int) MainButton.size() && i < FirstItem+DISPLAY_BUTTONS; ++i, ++n) + { + std::string iconpath = HomebrewList->GetFilepath(i); + size_t pos = iconpath.rfind('/'); + if(pos != std::string::npos && pos < iconpath.size()-1) + iconpath.erase(pos+1); + iconpath += "icon.png"; + + IconImgData[n] = new GuiImageData(iconpath.c_str()); + IconImg[n] = new GuiImage(IconImgData[n]); + IconImg[n]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + IconImg[n]->SetPosition(12, 0); + IconImg[n]->SetScale(0.95); + MainButton[i]->SetIcon(IconImg[n]); + } + + FlyingButtonsMenu::AddMainButtons(); +} + +void HomebrewBrowser::SetupMainButtons() +{ + HomebrewXML MetaXML; + + for(int i = 0; i < HomebrewList->GetFilecount(); ++i) + { + const char * HomebrewName = NULL; + std::string metapath = HomebrewList->GetFilepath(i); + size_t pos = metapath.rfind('/'); + if(pos != std::string::npos && pos < metapath.size()-1) + metapath.erase(pos+1); + metapath += "meta.xml"; + + if (MetaXML.LoadHomebrewXMLData(metapath.c_str()) > 0) + { + HomebrewName = MetaXML.GetName(); + MainButtonDesc[i]->SetText(MetaXML.GetShortDescription()); + MainButtonDescOver[i]->SetText(MetaXML.GetShortDescription()); + } + else + { + const char * shortpath = HomebrewList->GetFilepath(i); + const char * ptr = shortpath; + const char * ptr2 = NULL; + while(*ptr != '\0') + { + if(*ptr == '/') + { + shortpath = ptr2; + ptr2 = ptr; + } + + ++ptr; + } + if(!shortpath && ptr2) + shortpath = ptr2; + else if(!shortpath) + shortpath = HomebrewList->GetFilename(i); + + HomebrewName = shortpath; + MainButtonDesc[i]->SetText(" "); + MainButtonDescOver[i]->SetText(" "); + } + + SetMainButton(i, HomebrewName, MainButtonImgData, MainButtonImgOverData); + + MainButtonTxt[i]->SetFontSize(18); + MainButtonTxt[i]->SetMaxWidth(MainButtonImgData->GetWidth() - 150, DOTTED); + MainButtonTxt[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + MainButtonTxt[i]->SetPosition(148, -12); + MainButton[i]->SetLabel(MainButtonDesc[i], 1); + MainButton[i]->SetLabelOver(MainButtonDescOver[i], 1); + } +} + +int HomebrewBrowser::MainLoop() +{ + if (IsNetworkInit() && wifiNotSet) + { + wifiToolTip->SetText(GetNetworkIP()); + wifiBtn->SetAlpha(255); + wifiBtn->SetToolTip(wifiToolTip, 0, -50, 0, 5); + wifiNotSet = false; + } + + if(wifiBtn->GetState() == STATE_CLICKED) + { + if(IsNetworkInit() && WindowPrompt(tr("Do you want to re-init network?"), 0, tr("Yes"), tr("Cancel"))) + { + DeinitNetwork(); + wifiBtn->SetAlpha(80); + wifiBtn->SetToolTip(NULL, 0, -50, 0, 5); + wifiNotSet = true; + } + ResumeNetworkWait(); + wifiBtn->ResetState(); + } + else if(channelBtn->GetState() == STATE_CLICKED) + { + SetState(STATE_DISABLED); + TitleBrowser(); + SetState(STATE_DEFAULT); + channelBtn->ResetState(); + } + else if (infilesize > 0) + { + int menu = ReceiveFile(); + if(menu != MENU_NONE) + return menu; + CloseConnection(); + ResumeNetworkWait(); + } + + return FlyingButtonsMenu::MainLoop(); +} + +//! Callback for MainButton clicked +void HomebrewBrowser::MainButtonClicked(int button) +{ + HomebrewXML MetaXML; + std::string metapath = HomebrewList->GetFilepath(button); + size_t pos = metapath.rfind('/'); + if(pos != std::string::npos && pos < metapath.size()-1) + metapath.erase(pos+1); + metapath += "meta.xml"; + MetaXML.LoadHomebrewXMLData(metapath.c_str()); + + u64 filesize = HomebrewList->GetFilesize(button); + + wString HomebrewName(MainButtonTxt[button]->GetText()); + + HomebrewPrompt *HBCWindowPrompt = new HomebrewPrompt(HomebrewName.toUTF8().c_str(), MetaXML.GetCoder(), MetaXML.GetVersion(), + MetaXML.GetReleasedate(), MetaXML.GetLongDescription(), IconImgData[button % 4], filesize); + + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(HBCWindowPrompt); + + int choice = HBCWindowPrompt->MainLoop(); + + delete HBCWindowPrompt; + + mainWindow->SetState(STATE_DEFAULT); + + if (choice == 1) + { + u8 *buffer = NULL; + u32 filesize = 0; + LoadFileToMem(HomebrewList->GetFilepath(button), &buffer, &filesize); + if(!buffer) + { + WindowPrompt(tr("Error"), tr("Not enough memory."), tr("OK")); + return; + } + FreeHomebrewBuffer(); + CopyHomebrewMemory(buffer, 0, filesize); + + AddBootArgument(HomebrewList->GetFilepath(button)); + + for(u32 i = 0; i < MetaXML.GetArguments().size(); ++i) + { + AddBootArgument(MetaXML.GetArguments().at(i).c_str()); + } + + BootHomebrewFromMem(); + } +} + +int HomebrewBrowser::ReceiveFile() +{ + char filesizetxt[50]; + char temp[50]; + u32 filesize = 0; + + if (infilesize < MB_SIZE) + snprintf(filesizetxt, sizeof(filesizetxt), tr( "Incoming file %0.2fKB" ), infilesize / KB_SIZE); + else snprintf(filesizetxt, sizeof(filesizetxt), tr( "Incoming file %0.2fMB" ), infilesize / MB_SIZE); + + snprintf(temp, sizeof(temp), tr( "Load file from: %s ?" ), GetIncommingIP()); + + int choice = WindowPrompt(filesizetxt, temp, tr( "OK" ), tr( "Cancel" )); + + if (choice == 0) + return MENU_NONE; + + u32 read = 0; + int len = NETWORKBLOCKSIZE; + filesize = infilesize; + u8 * buffer = (u8 *) malloc(infilesize); + if(!buffer) + { + WindowPrompt(tr( "Not enough memory." ), 0, tr( "OK" )); + return MENU_NONE; + } + + int error = 0; + + while (read < infilesize) + { + ShowProgress(tr( "Receiving file from:" ), GetIncommingIP(), NULL, read, infilesize, true); + + if (infilesize - read < (u32) len) + len = infilesize - read; + else len = NETWORKBLOCKSIZE; + + int result = network_read(connection, buffer+read, len); + + if (result < 0) + { + WindowPrompt(tr( "Error while transfering data." ), 0, tr( "OK" )); + free(buffer); + ProgressStop(); + return MENU_NONE; + } + if (!result) + { + break; + } + + read += result; + } + + char filename[101]; + memset(filename, 0, sizeof(filename)); + + network_read(connection, (u8*) filename, 100); + + // Do we need to unzip this thing? + if (wiiloadVersion[0] > 0 || wiiloadVersion[1] > 4) + { + // We need to unzip... + if (buffer[0] == 'P' && buffer[1] == 'K' && buffer[2] == 0x03 && buffer[3] == 0x04) + { + // It's a zip file, unzip to the apps directory + // Zip archive, ask for permission to install the zip + char zippath[255]; + snprintf(zippath, sizeof(zippath), "%s%s", Settings.homebrewapps_path, filename); + + FILE *fp = fopen(zippath, "wb"); + if (!fp) + { + WindowPrompt(tr( "Error writing the data." ), 0, tr( "OK" )); + return MENU_NONE; + } + + fwrite(buffer, 1, infilesize, fp); + fclose(fp); + + free(buffer); + buffer = NULL; + + // Now unzip the zip file... + unzFile uf = unzOpen(zippath); + if (uf == NULL) + { + WindowPrompt(tr( "Error while opening the zip." ), 0, tr( "OK" )); + return MENU_NONE; + } + + extractZip(uf, 0, 1, 0, Settings.homebrewapps_path); + unzCloseCurrentFile(uf); + + remove(zippath); + + WindowPrompt(tr( "Success:" ), + tr( "Uploaded ZIP file installed to homebrew directory." ), tr( "OK" )); + + // Reload this menu here... + return MENU_HOMEBREWBROWSE; + } + else if (uncfilesize != 0) // if uncfilesize == 0, it's not compressed + { + // It's compressed, uncompress + u8 *unc = (u8 *) malloc(uncfilesize); + if(!unc) + { + ProgressStop(); + free(buffer); + CloseConnection(); + WindowPrompt(tr( "Not enough memory." ), 0, tr( "OK" )); + return MENU_NONE; + } + uLongf f = uncfilesize; + error = uncompress(unc, &f, buffer, infilesize) != Z_OK; + uncfilesize = f; + filesize = uncfilesize; + + free(buffer); + buffer = unc; + } + } + + CopyHomebrewMemory(buffer, 0, filesize); + free(buffer); + + ProgressStop(); + + if (error || read != infilesize || (strcasestr(filename, ".dol") == 0 && strcasestr(filename, ".elf") == 0)) + { + WindowPrompt(tr( "Error:" ), tr( "No data could be read." ), tr( "OK" )); + FreeHomebrewBuffer(); + return MENU_NONE; + } + + CloseConnection(); + + AddBootArgument(filename); + + return BootHomebrewFromMem(); +} diff --git a/source/homebrewboot/HomebrewBrowser.hpp b/source/homebrewboot/HomebrewBrowser.hpp new file mode 100644 index 0000000..bfeacde --- /dev/null +++ b/source/homebrewboot/HomebrewBrowser.hpp @@ -0,0 +1,64 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef HOMEBREWBROWSER_HPP_ +#define HOMEBREWBROWSER_HPP_ + +#include "settings/menus/FlyingButtonsMenu.hpp" +#include "FileOperations/DirList.h" + +#define DISPLAY_BUTTONS 4 + +class HomebrewBrowser : public FlyingButtonsMenu +{ + public: + HomebrewBrowser(); + ~HomebrewBrowser(); + static int Execute(); + virtual int MainLoop(); + protected: + void MainButtonClicked(int index); + int ReceiveFile(); + virtual void CreateSettingsMenu(int index) { MainButtonClicked(index); }; + virtual void DeleteSettingsMenu() { }; + virtual void SetupMainButtons(); + virtual void AddMainButtons(); + + DirList * HomebrewList; + GuiImageData * IconImgData[DISPLAY_BUTTONS]; + GuiImage * IconImg[DISPLAY_BUTTONS]; + std::vector MainButtonDesc; + std::vector MainButtonDescOver; + + bool wifiNotSet; + GuiTooltip * wifiToolTip; + GuiImageData * wifiImgData; + GuiImage * wifiImg; + GuiButton * wifiBtn; + + GuiImageData * channelImgData; + GuiImage * channelBtnImg; + GuiButton * channelBtn; +}; + +#endif diff --git a/source/homebrewboot/HomebrewXML.cpp b/source/homebrewboot/HomebrewXML.cpp new file mode 100644 index 0000000..5ccb09e --- /dev/null +++ b/source/homebrewboot/HomebrewXML.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** + * HomebrewXML Class + * for USB Loader GX + ***************************************************************************/ +#include +#include +#include +#include +#include "FileOperations/fileops.h" +#include "xml/tinyxml2.h" +#include "gecko.h" + +#include "HomebrewXML.h" + +using namespace tinyxml2; + +#define ENTRIE_SIZE 8192 + +/* qparam filename Filepath of the XML file */ +int HomebrewXML::LoadHomebrewXMLData(const char* filename) +{ + Name.clear(); + Coder.clear(); + Version.clear(); + ShortDescription.clear(); + LongDescription.clear(); + Releasedate.clear(); + + XMLDocument xmlDoc; + if(xmlDoc.LoadFile(filename) != 0) + return false; + + XMLElement *appNode = xmlDoc.FirstChildElement("app"); + if(!appNode) + return false; + + XMLElement *node = NULL; + + node = appNode->FirstChildElement("name"); + if(node && node->FirstChild() && node->FirstChild()->Value()) + Name = node->FirstChild()->Value(); + + node = appNode->FirstChildElement("coder"); + if(node && node->FirstChild() && node->FirstChild()->Value()) + Coder = node->FirstChild()->Value(); + + node = appNode->FirstChildElement("version"); + if(node && node->FirstChild() && node->FirstChild()->Value()) + Version = node->FirstChild()->Value(); + + node = appNode->FirstChildElement("short_description"); + if(node && node->FirstChild() && node->FirstChild()->Value()) + ShortDescription = node->FirstChild()->Value(); + + node = appNode->FirstChildElement("long_description"); + if(node && node->FirstChild() && node->FirstChild()->Value()) + LongDescription = node->FirstChild()->Value(); + + char ReleaseText[200]; + memset(ReleaseText, 0, sizeof(ReleaseText)); + + node = appNode->FirstChildElement("release_date"); + if(node && node->FirstChild() && node->FirstChild()->Value()) + snprintf(ReleaseText, sizeof(ReleaseText), node->FirstChild()->Value()); + + int len = (strlen(ReleaseText) - 6); //length of the date string without the 200000 at the end + if (len == 8) + snprintf(ReleaseText, sizeof(ReleaseText), "%c%c/%c%c/%c%c%c%c", ReleaseText[4], ReleaseText[5], ReleaseText[6], ReleaseText[7], ReleaseText[0], ReleaseText[1], ReleaseText[2], ReleaseText[3]); + else if (len == 6) + snprintf(ReleaseText, sizeof(ReleaseText), "%c%c/%c%c%c%c", ReleaseText[4], ReleaseText[5], ReleaseText[0], ReleaseText[1], ReleaseText[2], ReleaseText[3]); + else + snprintf(ReleaseText, sizeof(ReleaseText), "%s", ReleaseText); + + Releasedate = ReleaseText; + + node = appNode->FirstChildElement("arguments"); + if(!node) + return 1; + + XMLElement *argNode = node->FirstChildElement("arg"); + + while(argNode) + { + if(argNode->FirstChild() && argNode->FirstChild()->Value()) + Arguments.push_back(std::string(argNode->FirstChild()->Value())); + + argNode = argNode->NextSiblingElement(); + } + + return 1; +} + +int HomebrewXML::SaveHomebrewXMLData(const char* filename) +{ + const int max_line_size = 4096; + char *line = new (std::nothrow) char[max_line_size]; + if(!line) return 0; + + FILE *fp = fopen(filename, "wb"); + if(!fp) + { + delete [] line; + return 0; + } + + snprintf(line, max_line_size,"\n"); fputs(line, fp); + snprintf(line, max_line_size,"\n"); fputs(line, fp); + snprintf(line, max_line_size," %s\n", GetName()); fputs(line, fp); + snprintf(line, max_line_size," %s\n", GetCoder()); fputs(line, fp); + snprintf(line, max_line_size," %s\n", GetVersion()); fputs(line, fp); + snprintf(line, max_line_size," %s\n", GetReleasedate()); fputs(line, fp); + if (Arguments.size() > 0) + { + snprintf(line, max_line_size," \n"); fputs(line, fp); + for(u8 i = 0; i < Arguments.size(); i++) + { + snprintf(line, max_line_size," %s\n", Arguments[i].c_str()); fputs(line, fp); + } + snprintf(line, max_line_size," \n"); fputs(line, fp); + } + snprintf(line, max_line_size," \n"); fputs(line, fp); + snprintf(line, max_line_size," %s\n", GetShortDescription()); fputs(line, fp); + snprintf(line, max_line_size," %s\n", GetLongDescription()); fputs(line, fp); + snprintf(line, max_line_size,"\n"); fputs(line, fp); + + fclose(fp); + delete [] line; + return 1; +} + +/* Set argument */ +void HomebrewXML::SetArgument(const char* argument) +{ + // Crop value from argument, if present + char argName[strlen(argument)+1]; + strcpy(argName, argument); + char *ptr = strrchr(argName, '='); + if(ptr) *(ptr+1) = 0; + + // Check if argument already exists and edit it + bool found = false; + for(u8 i=0; i < Arguments.size(); i++) + { + size_t pos = Arguments[i].find(argName); + if(pos != std::string::npos) + { + Arguments[i] = argument; + found = true; + break; + } + } + + // if it doesn't exist, add the new argument. + if(!found) + Arguments.push_back(argument); +} + +/* Get name */ +const char * HomebrewXML::GetName() const +{ + return Name.c_str(); +} + +/* Set Name */ +void HomebrewXML::SetName(char * newName) +{ + Name = newName; +} + +/* Get coder */ +const char * HomebrewXML::GetCoder() const +{ + return Coder.c_str(); +} + +/* Get version */ +const char * HomebrewXML::GetVersion() const +{ + return Version.c_str(); +} + +/* Set version */ +void HomebrewXML::SetVersion(const char * newVer) +{ + Version = newVer; +} + +/* Get releasedate */ +const char * HomebrewXML::GetReleasedate() const +{ + return Releasedate.c_str(); +} + +/* Get shortdescription */ +const char * HomebrewXML::GetShortDescription() const +{ + return ShortDescription.c_str(); +} + +/* Get longdescription */ +const char * HomebrewXML::GetLongDescription() const +{ + return LongDescription.c_str(); +} diff --git a/source/homebrewboot/HomebrewXML.h b/source/homebrewboot/HomebrewXML.h new file mode 100644 index 0000000..b284ca0 --- /dev/null +++ b/source/homebrewboot/HomebrewXML.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * HomebrewXML Class + * for USB Loader GX + ***************************************************************************/ +#ifndef ___HOMEBREWXML_H_ +#define ___HOMEBREWXML_H_ + +#include +#include + +class HomebrewXML +{ + public: + HomebrewXML() { }; + HomebrewXML(const char* filename) { LoadHomebrewXMLData(filename); }; + + int LoadHomebrewXMLData(const char* filename); + int SaveHomebrewXMLData(const char* filename); + + const char * GetName() const; + void SetName(char * newName); + const char * GetCoder() const; + const char * GetVersion() const; + void SetVersion(const char * newVer); + const char * GetReleasedate() const; + const char * GetShortDescription() const; + const char * GetLongDescription() const; + const std::vector & GetArguments() const { return Arguments; }; + void SetArgument(const char* argument); + + protected: + std::string Name; + std::string Coder; + std::string Version; + std::string Releasedate; + std::string ShortDescription; + std::string LongDescription; + std::vector Arguments; +}; + +#endif diff --git a/source/input.cpp b/source/input.cpp new file mode 100644 index 0000000..4488d0c --- /dev/null +++ b/source/input.cpp @@ -0,0 +1,261 @@ +/**************************************************************************** + * libwiigui Template + * Tantric 2009 + * Cyan 2015 + * + * input.cpp + * Wii/GameCube controller management + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libs/libdrc/wiidrc.h" + +#include "menu.h" +#include "video.h" +#include "input.h" +#include "GUI/gui.h" +#include "sys.h" +#include "gecko.h" + +int rumbleRequest[4] = { 0, 0, 0, 0 }; +GuiTrigger userInput[4]; +static int rumbleCount[4] = { 0, 0, 0, 0 }; +extern bool isWiiVC; // in sys.cpp + +/**************************************************************************** + * UpdatePads + * + * called by postRetraceCallback in InitGCVideo - scans gcpad and wpad + ***************************************************************************/ +void UpdatePads() +{ + WPAD_ScanPads(); + PAD_ScanPads(); + + for (int i = 3; i >= 0; i--) + { + memcpy(&userInput[i].wpad, WPAD_Data(i), sizeof(WPADData)); + userInput[i].chan = i; + userInput[i].pad.btns_d = PAD_ButtonsDown(i); + userInput[i].pad.btns_u = PAD_ButtonsUp(i); + userInput[i].pad.btns_h = PAD_ButtonsHeld(i); + userInput[i].pad.stickX = PAD_StickX(i); + userInput[i].pad.stickY = PAD_StickY(i); + userInput[i].pad.substickX = PAD_SubStickX(i); + userInput[i].pad.substickY = PAD_SubStickY(i); + userInput[i].pad.triggerL = PAD_TriggerL(i); + userInput[i].pad.triggerR = PAD_TriggerR(i); + + if (Settings.rumble == ON) DoRumble(i); + + if(userInput[i].wpad.exp.type == WPAD_EXP_NUNCHUK) + { + if((userInput[i].wpad.btns_h & WPAD_NUNCHUK_BUTTON_Z) && (userInput[i].wpad.btns_d & WPAD_NUNCHUK_BUTTON_C)) + ScreenShot(); + } + if((userInput[i].pad.btns_h & PAD_TRIGGER_R) && (userInput[i].pad.btns_d & PAD_TRIGGER_Z)) + ScreenShot(); + } + + // WiiU gamepad (DRC) when using WiiVC injected WiiU channels + // Copy the drc state to Gamecube pad state + if(WiiDRC_Inited() && WiiDRC_Connected()) + { + WiiDRC_ScanPads(); + + // DRC buttons state written to gamecube pad data + userInput[0].pad.btns_d |= wiidrc_to_pad(WiiDRC_ButtonsDown()); + userInput[0].pad.btns_u |= wiidrc_to_pad(WiiDRC_ButtonsUp()); + userInput[0].pad.btns_h |= wiidrc_to_pad(WiiDRC_ButtonsHeld()); + // DRC stick state written to gamecube pad data + userInput[0].pad.stickX = WiiDRC_lStickX(); + userInput[0].pad.stickY = WiiDRC_lStickY(); + userInput[0].pad.substickX = WiiDRC_rStickX(); + userInput[0].pad.substickY = WiiDRC_rStickY(); + } +} + +/**************************************************************************** + * ScreensaverTime + ***************************************************************************/ +static inline u32 ScreensaverTime(int setting) +{ + switch (setting) + { + case 0: + return 0xFFFFFF; + case 1: + return 180; + case 2: + return 300; + case 3: + return 600; + case 4: + return 1200; + case 5: + return 1800; + case 6: + return 3600; + default: + break; + } + + return 0xFFFFFF; +} + +/**************************************************************************** + * SetWPADTimeout + ***************************************************************************/ +void SetWPADTimeout() +{ + WPAD_SetIdleTimeout(ScreensaverTime(Settings.screensaver)); +} + +/**************************************************************************** + * ControlActivityTimeOut + ***************************************************************************/ +bool ControlActivityTimeout(void) +{ + u32 minTime = 0xFFFFFF; + for(int i = 0; i < 3; ++i) + if(pointer[i]->getLastActivCounter() < minTime) + minTime = pointer[i]->getLastActivCounter(); + + // not very accurate but it's not required here + return (minTime/(Settings.PAL50 ? 50 : 60) > ScreensaverTime(Settings.screensaver)); +} +/**************************************************************************** + * SetupPads + * + * Sets up userInput triggers for use + ***************************************************************************/ +void SetupPads() +{ + PAD_Init(); + WPAD_Init(); + + // check WiiVC to init WiiU gamepad + WiiDRC_Init(); + isWiiVC = WiiDRC_Inited(); + + + // read wiimote accelerometer and IR data + WPAD_SetDataFormat(WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR); + WPAD_SetVRes(WPAD_CHAN_ALL, screenwidth, screenheight); + + for (int i = 0; i < 4; i++) + { + userInput[i].chan = i; + } + + SetWPADTimeout(); +} + +/**************************************************************************** + * ShutoffRumble + ***************************************************************************/ +void ShutoffRumble() +{ + for (int i = 0; i < 4; i++) + { + WPAD_Rumble(i, 0); + rumbleCount[i] = 0; + } +} + +/**************************************************************************** + * DoRumble + ***************************************************************************/ +void DoRumble(int i) +{ + if (rumbleRequest[i] && rumbleCount[i] < 3) + { + WPAD_Rumble(i, 1); // rumble on + rumbleCount[i]++; + } + else if (rumbleRequest[i]) + { + rumbleCount[i] = 20; + rumbleRequest[i] = 0; + } + else + { + if (rumbleCount[i]) rumbleCount[i]--; + WPAD_Rumble(i, 0); // rumble off + } +} + +/**************************************************************************** + * WiiDRC to WPAD + * + * Sets WPAD button state based on WiiDRC (WiiU gamepad in WiiVC) pressed buttons. + ***************************************************************************/ +u32 wiidrc_to_wpad(u32 btns) { + u32 ret = 0; + + if(btns & WIIDRC_BUTTON_LEFT) + ret |= WPAD_BUTTON_LEFT; + if(btns & WIIDRC_BUTTON_RIGHT) + ret |= WPAD_BUTTON_RIGHT; + if(btns & WIIDRC_BUTTON_UP) + ret |= WPAD_BUTTON_UP; + if(btns & WIIDRC_BUTTON_DOWN) + ret |= WPAD_BUTTON_DOWN; + if(btns & WIIDRC_BUTTON_A) + ret |= WPAD_BUTTON_A; + if(btns & WIIDRC_BUTTON_B) + ret |= WPAD_BUTTON_B; + if(btns & WIIDRC_BUTTON_X) + ret |= WPAD_BUTTON_1; + if(btns & WIIDRC_BUTTON_Y) + ret |= WPAD_BUTTON_2; + if((btns & WIIDRC_BUTTON_L) || (btns & WIIDRC_BUTTON_ZL) || (btns & WIIDRC_BUTTON_MINUS)) + ret |= WPAD_BUTTON_MINUS; + if((btns & WIIDRC_BUTTON_R) || (btns & WIIDRC_BUTTON_ZR) || (btns & WIIDRC_BUTTON_PLUS)) + ret |= WPAD_BUTTON_PLUS; + if(btns & WIIDRC_BUTTON_HOME) + ret |= WPAD_BUTTON_HOME; + + return (ret&0xffff) ; +} + +/**************************************************************************** + * WiiDRC to PAD + * + * Sets PAD button state based on WiiDRC (WiiU gamepad in WiiVC) pressed buttons. + ***************************************************************************/ +u32 wiidrc_to_pad(u32 btns) { + u32 ret = 0; + + if(btns & WIIDRC_BUTTON_LEFT) + ret |= PAD_BUTTON_LEFT; + if(btns & WIIDRC_BUTTON_RIGHT) + ret |= PAD_BUTTON_RIGHT; + if(btns & WIIDRC_BUTTON_UP) + ret |= PAD_BUTTON_UP; + if(btns & WIIDRC_BUTTON_DOWN) + ret |= PAD_BUTTON_DOWN; + if(btns & WIIDRC_BUTTON_A) + ret |= PAD_BUTTON_A; + if(btns & WIIDRC_BUTTON_B) + ret |= PAD_BUTTON_B; + if(btns & WIIDRC_BUTTON_X) + ret |= PAD_BUTTON_X; + if(btns & WIIDRC_BUTTON_Y) + ret |= PAD_BUTTON_Y; + if((btns & WIIDRC_BUTTON_L) || (btns & WIIDRC_BUTTON_ZL) || (btns & WIIDRC_BUTTON_MINUS)) + ret |= PAD_TRIGGER_L; + if((btns & WIIDRC_BUTTON_R) || (btns & WIIDRC_BUTTON_ZR) || (btns & WIIDRC_BUTTON_PLUS)) + ret |= PAD_TRIGGER_R; + if(btns & WIIDRC_BUTTON_HOME) + ret |= PAD_BUTTON_START; + + return (ret&0xffff) ; +} \ No newline at end of file diff --git a/source/input.h b/source/input.h new file mode 100644 index 0000000..da91f3e --- /dev/null +++ b/source/input.h @@ -0,0 +1,29 @@ +/**************************************************************************** + * libwiigui Template + * Tantric 2009 + * + * input.h + * Wii/GameCube controller management + ***************************************************************************/ + +#ifndef _INPUT_H_ +#define _INPUT_H_ + +#include +#include + +#define PI 3.14159265f +#define PADCAL 50 + +extern int rumbleRequest[4]; + +void SetupPads(); +void UpdatePads(); +void ShutoffRumble(); +void DoRumble(int i); +void SetWPADTimeout(); +bool ControlActivityTimeout(void); +u32 wiidrc_to_wpad(u32 btns); +u32 wiidrc_to_pad(u32 btns); + +#endif diff --git a/source/language/UpdateLanguage.cpp b/source/language/UpdateLanguage.cpp new file mode 100644 index 0000000..aca61e1 --- /dev/null +++ b/source/language/UpdateLanguage.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** + * languagefile updater + * for USB Loader GX *giantpune* + * 2015 Cyan + ***************************************************************************/ +#include +#include +#include +#include + +#include "UpdateLanguage.h" +#include "gettext.h" +#include "FileOperations/fileops.h" +#include "FileOperations/DirList.h" +#include "menu.h" +#include "network/networkops.h" +#include "network/http.h" +#include "network/URL_List.h" +#include "prompts/PromptWindows.h" +#include "prompts/ProgressWindow.h" +#include "utils/ShowError.h" +#include "gecko.h" +#include "svnrev.h" + +static const char * LanguageFilesURL = "http://svn.code.sf.net/p/usbloadergx/code/trunk/Languages/"; + +int DownloadAllLanguageFiles(int revision) +{ + if(!CreateSubfolder(Settings.languagefiles_path)) + { + ShowError(tr("Could not create path: %s"), Settings.languagefiles_path); + return -1; + } + + if(!IsNetworkInit()) + { + ShowError(tr("Network is not initiated.")); + return -2; + } + char fullURL[300]; + + URL_List LinkList(LanguageFilesURL); + int listsize = LinkList.GetURLCount(); + int files_downloaded = 0; + char target[6]; + if(revision > 0) + snprintf(target, sizeof(target), "%d", revision); + else + snprintf(target, sizeof(target), "%s", GetRev()); + + ShowProgress(tr("Updating Language Files:"), 0, 0, 0, listsize, false, true); + + for (int i = 0; i < listsize; i++) + { + const char * filename = strrchr(LinkList.GetURL(i), '/'); + if(filename) filename++; + else filename = LinkList.GetURL(i); + + if(!filename) + continue; + + const char * FileExt = strrchr(filename, '.'); + if (!FileExt || strcasecmp(FileExt, ".lang") != 0) + continue; + + gprintf("%s\n", filename); + + ShowProgress(tr("Updating Language Files:"), 0, filename, i, listsize, false, true); + + snprintf(fullURL, sizeof(fullURL), "%s%s?p=%s", LanguageFilesURL, filename, target); + + struct block file = downloadfile(fullURL); + if (file.data) + { + char filepath[300]; + snprintf(filepath, sizeof(filepath), "%s/%s", Settings.languagefiles_path, filename); + FILE * pfile = fopen(filepath, "wb"); + if(pfile) + { + fwrite(file.data, 1, file.size, pfile); + fclose(pfile); + files_downloaded++; + } + free(file.data); + } + } + + ProgressStop(); + + // reload current language file + if(Settings.language_path[0] != 0) + Settings.LoadLanguage(Settings.language_path, CONSOLE_DEFAULT); + else + Settings.LoadLanguage(NULL, CONSOLE_DEFAULT); + + return files_downloaded; +} + +int UpdateLanguageFiles() +{ + if(!CreateSubfolder(Settings.languagefiles_path)) + { + ShowError(tr("Could not create path: %s"), Settings.languagefiles_path); + return -1; + } + + if(!IsNetworkInit()) + { + ShowError(tr("Network is not initiated.")); + return -2; + } + + DirList Dir(Settings.languagefiles_path, ".lang"); + + //give up now if we didn't find any + if (Dir.GetFilecount() == 0) + { + if(WindowPrompt(tr("Error:"), tr("No language files to update on your devices! Do you want to download new language files?"), tr("Yes"), tr("No"))) + return DownloadAllLanguageFiles(); + + return -2; + } + + char savepath[150]; + char codeurl[200]; + + //we assume that the network will already be init by another function + // ( that has gui eletents in it because this one doesn't) + int done = 0; + + //build the URL, save path, and download each file and save it + for(int i = 0; i < Dir.GetFilecount(); ++i) + { + snprintf(codeurl, sizeof(codeurl), "%s%s?p=%s", LanguageFilesURL, Dir.GetFilename(i), GetRev()); + snprintf(savepath, sizeof(savepath), "%s/%s", Settings.languagefiles_path, Dir.GetFilename(i)); + + struct block file = downloadfile(codeurl); + + ShowProgress(tr("Updating Language Files:"), 0, Dir.GetFilename(i), i, Dir.GetFilecount(), false, true); + + if (file.data != NULL) + { + FILE * pfile; + pfile = fopen(savepath, "wb"); + if (pfile != NULL) + { + fwrite(file.data, 1, file.size, pfile); + fclose(pfile); + done++; + } + free(file.data); + } + } + + ProgressStop(); + + // reload current language file + if(Settings.language_path[0] != 0) + Settings.LoadLanguage(Settings.language_path, CONSOLE_DEFAULT); + else + Settings.LoadLanguage(NULL, CONSOLE_DEFAULT); + + // return the number of files we updated + return done; +} + diff --git a/source/language/UpdateLanguage.h b/source/language/UpdateLanguage.h new file mode 100644 index 0000000..1ae8e8f --- /dev/null +++ b/source/language/UpdateLanguage.h @@ -0,0 +1,19 @@ +/**************************************************************************** + * language update + * for USB Loader GX *giantpune* + ***************************************************************************/ +#ifndef ___UPDATELANGUAGE_H_ +#define ___UPDATELANGUAGE_H_ + +#define MAXLANGUAGEFILES 50 + +//! Checks the language path for files ending in .lang and updates them (up to MAXLANGUAGEFILES) +//! This function expects that the network is already init before it is called + +//! returns the number of files successfully updated +//! returns -2 if it can't find any .lang files in the path +//! return -1 if there is no network connection +int UpdateLanguageFiles(); +int DownloadAllLanguageFiles(int target = 0); + +#endif diff --git a/source/language/gettext.c b/source/language/gettext.c new file mode 100644 index 0000000..a8bb7b0 --- /dev/null +++ b/source/language/gettext.c @@ -0,0 +1,241 @@ +#include +#include +#include +#include +#include "gettext.h" + +typedef struct _MSG +{ + u32 id; + char* msgstr; + struct _MSG *next; +} MSG; +static MSG *baseMSG = 0; + +#define HASHWORDBITS 32 + +/* Defines the so called `hashpjw' function by P.J. Weinberger + [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, + 1986, 1987 Bell Telephone Laboratories, Inc.] */ +static inline u32 hash_string(const char *str_param) +{ + u32 hval, g; + const char *str = str_param; + + /* Compute the hash value for the given string. */ + hval = 0; + while (*str != '\0') + { + hval <<= 4; + hval += (u8) *str++; + g = hval & ((u32) 0xf << (HASHWORDBITS - 4)); + if (g != 0) + { + hval ^= g >> (HASHWORDBITS - 8); + hval ^= g; + } + } + return hval; +} + +/* Expand some escape sequences found in the argument string. */ +static char * +expand_escape(const char *str) +{ + char *retval, *rp; + const char *cp = str; + + retval = (char *) malloc(strlen(str) + 1); + if (retval == NULL) return NULL; + rp = retval; + + while (cp[0] != '\0' && cp[0] != '\\') + *rp++ = *cp++; + if (cp[0] == '\0') goto terminate; + do + { + + /* Here cp[0] == '\\'. */ + switch (*++cp) + { + case '\"': /* " */ + *rp++ = '\"'; + ++cp; + break; + case 'a': /* alert */ + *rp++ = '\a'; + ++cp; + break; + case 'b': /* backspace */ + *rp++ = '\b'; + ++cp; + break; + case 'f': /* form feed */ + *rp++ = '\f'; + ++cp; + break; + case 'n': /* new line */ + *rp++ = '\n'; + ++cp; + break; + case 'r': /* carriage return */ + *rp++ = '\r'; + ++cp; + break; + case 't': /* horizontal tab */ + *rp++ = '\t'; + ++cp; + break; + case 'v': /* vertical tab */ + *rp++ = '\v'; + ++cp; + break; + case '\\': + *rp = '\\'; + ++cp; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int ch = *cp++ - '0'; + + if (*cp >= '0' && *cp <= '7') + { + ch *= 8; + ch += *cp++ - '0'; + + if (*cp >= '0' && *cp <= '7') + { + ch *= 8; + ch += *cp++ - '0'; + } + } + *rp = ch; + } + break; + default: + *rp = '\\'; + break; + } + + while (cp[0] != '\0' && cp[0] != '\\') + *rp++ = *cp++; + } while (cp[0] != '\0'); + + /* Terminate string. */ + terminate: *rp = '\0'; + return retval; +} + +static MSG *findMSG(u32 id) +{ + MSG *msg; + for (msg = baseMSG; msg; msg = msg->next) + { + if (msg->id == id) return msg; + } + return NULL; +} + +static MSG *setMSG(const char *msgid, const char *msgstr) +{ + u32 id = hash_string(msgid); + MSG *msg = findMSG(id); + if (!msg) + { + msg = (MSG *) malloc(sizeof(MSG)); + msg->id = id; + msg->msgstr = NULL; + msg->next = baseMSG; + baseMSG = msg; + } + if (msg) + { + if (msgstr) + { + if (msg->msgstr) free(msg->msgstr); + //msg->msgstr = strdup(msgstr); + msg->msgstr = expand_escape(msgstr); + } + return msg; + } + return NULL; +} +void gettextCleanUp(void) +{ + while (baseMSG) + { + MSG *nextMsg = baseMSG->next; + free(baseMSG->msgstr); + free(baseMSG); + baseMSG = nextMsg; + } +} + +bool gettextLoadLanguage(const char* langFile) +{ + FILE *f; + char line[512]; + char *lastID = NULL; + + gettextCleanUp(); + f = fopen(langFile, "r"); + if (!f) return false; + + while (fgets(line, sizeof(line), f)) + { + // lines starting with # are comments + if (line[0] == '#') + continue; + else if (strncmp(line, "msgid \"", 7) == 0) + { + char *msgid, *end; + if (lastID) + { + free(lastID); + lastID = NULL; + } + msgid = &line[7]; + end = strrchr(msgid, '"'); + if (end && end - msgid > 1) + { + *end = 0; + lastID = strdup(msgid); + } + } + else if (strncmp(line, "msgstr \"", 8) == 0) + { + char *msgstr, *end; + + if (lastID == NULL) continue; + + msgstr = &line[8]; + end = strrchr(msgstr, '"'); + if (end && end - msgstr > 1) + { + *end = 0; + setMSG(lastID, msgstr); + } + free(lastID); + lastID = NULL; + } + + } + + fclose(f); + return true; +} +const char *gettext(const char *msgid) +{ + if(!msgid[0]) return NULL; + MSG *msg = findMSG(hash_string(msgid)); + if (msg && msg->msgstr) return msg->msgstr; + return msgid; +} + diff --git a/source/language/gettext.h b/source/language/gettext.h new file mode 100644 index 0000000..1995c95 --- /dev/null +++ b/source/language/gettext.h @@ -0,0 +1,23 @@ +#ifndef _GETTEXT_H_ +#define _GETTEXT_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + + bool gettextLoadLanguage(const char* langFile); + void gettextCleanUp(void); + /* + * input msg = a text in ASCII + * output = the translated msg in utf-8 + */ + const char *gettext(const char *msg); +#define tr(s) gettext(s) +#define trNOOP(s) (s) + +#ifdef __cplusplus +} +#endif + +#endif /* _GETTEXT_H_ */ diff --git a/source/libs/libdrc/libwiidrc.a b/source/libs/libdrc/libwiidrc.a new file mode 100644 index 0000000..d47f62d Binary files /dev/null and b/source/libs/libdrc/libwiidrc.a differ diff --git a/source/libs/libdrc/wiidrc.h b/source/libs/libdrc/wiidrc.h new file mode 100644 index 0000000..32657f0 --- /dev/null +++ b/source/libs/libdrc/wiidrc.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 FIX94 + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ +#ifndef _WIIDRC_H_ +#define _WIIDRC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct WiiDRCData { + s16 xAxisL; + s16 xAxisR; + s16 yAxisL; + s16 yAxisR; + u16 button; + u8 battery; + u8 extra; +}; + +#define WIIDRC_BUTTON_A 0x8000 +#define WIIDRC_BUTTON_B 0x4000 +#define WIIDRC_BUTTON_X 0x2000 +#define WIIDRC_BUTTON_Y 0x1000 +#define WIIDRC_BUTTON_LEFT 0x0800 +#define WIIDRC_BUTTON_RIGHT 0x0400 +#define WIIDRC_BUTTON_UP 0x0200 +#define WIIDRC_BUTTON_DOWN 0x0100 +#define WIIDRC_BUTTON_ZL 0x0080 +#define WIIDRC_BUTTON_ZR 0x0040 +#define WIIDRC_BUTTON_L 0x0020 +#define WIIDRC_BUTTON_R 0x0010 +#define WIIDRC_BUTTON_PLUS 0x0008 +#define WIIDRC_BUTTON_MINUS 0x0004 +#define WIIDRC_BUTTON_HOME 0x0002 +#define WIIDRC_BUTTON_SYNC 0x0001 + +#define WIIDRC_EXTRA_BUTTON_L3 0x80 +#define WIIDRC_EXTRA_BUTTON_R3 0x40 +#define WIIDRC_EXTRA_BUTTON_TV 0x20 +#define WIIDRC_EXTRA_OVERLAY_TV 0x10 +#define WIIDRC_EXTRA_OVERLAY_POWER 0x01 + +bool WiiDRC_Init(); +bool WiiDRC_Inited(); +bool WiiDRC_Recalibrate(); +bool WiiDRC_ScanPads(); +bool WiiDRC_Connected(); +bool WiiDRC_ShutdownRequested(); +const u8 *WiiDRC_GetRawI2CAddr(); +const struct WiiDRCData *WiiDRC_Data(); +u32 WiiDRC_ButtonsUp(); +u32 WiiDRC_ButtonsDown(); +u32 WiiDRC_ButtonsHeld(); +s16 WiiDRC_lStickX(); +s16 WiiDRC_lStickY(); +s16 WiiDRC_rStickX(); +s16 WiiDRC_rStickY(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/libs/libext2fs/ext2_frag.h b/source/libs/libext2fs/ext2_frag.h new file mode 100644 index 0000000..5073277 --- /dev/null +++ b/source/libs/libext2fs/ext2_frag.h @@ -0,0 +1,16 @@ +#ifndef EXT2_FRAG_H_ +#define EXT2_FRAG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*_ext2_frag_append_t)(void *ff, u32 offset, u32 sector, u32 count); + +int _EXT2_get_fragments(const char *in_path, _ext2_frag_append_t append_fragment, void *callback_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/libs/libext2fs/libcustomext2fs.a b/source/libs/libext2fs/libcustomext2fs.a new file mode 100644 index 0000000..c5a4450 Binary files /dev/null and b/source/libs/libext2fs/libcustomext2fs.a differ diff --git a/source/libs/libfat/fatfile_frag.h b/source/libs/libfat/fatfile_frag.h new file mode 100644 index 0000000..3af9b32 --- /dev/null +++ b/source/libs/libfat/fatfile_frag.h @@ -0,0 +1,16 @@ +#ifndef FAT_FRAG_H_ +#define FAT_FRAG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*_fat_frag_append_t)(void *ff, u32 offset, u32 sector, u32 count); + +int _FAT_get_fragments (const char *path, _fat_frag_append_t append_fragment, void *callback_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/libs/libfat/libcustomfat.a b/source/libs/libfat/libcustomfat.a new file mode 100644 index 0000000..0cbd9ca Binary files /dev/null and b/source/libs/libfat/libcustomfat.a differ diff --git a/source/libs/libntfs/libcustomntfs.a b/source/libs/libntfs/libcustomntfs.a new file mode 100644 index 0000000..32107de Binary files /dev/null and b/source/libs/libntfs/libcustomntfs.a differ diff --git a/source/libs/libntfs/ntfsfile_frag.h b/source/libs/libntfs/ntfsfile_frag.h new file mode 100644 index 0000000..889abb1 --- /dev/null +++ b/source/libs/libntfs/ntfsfile_frag.h @@ -0,0 +1,15 @@ +#ifndef NTFS_FRAG_H_ +#define NTFS_FRAG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*_ntfs_frag_append_t)(void *ff, u32 offset, u32 sector, u32 count); +int _NTFS_get_fragments (const char *path, _ntfs_frag_append_t append_fragment, void *callback_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/libs/libruntimeiospatch/libruntimeiospatch.a b/source/libs/libruntimeiospatch/libruntimeiospatch.a new file mode 100644 index 0000000..10ea9cd Binary files /dev/null and b/source/libs/libruntimeiospatch/libruntimeiospatch.a differ diff --git a/source/libs/libruntimeiospatch/runtimeiospatch.h b/source/libs/libruntimeiospatch/runtimeiospatch.h new file mode 100644 index 0000000..d7cb9ba --- /dev/null +++ b/source/libs/libruntimeiospatch/runtimeiospatch.h @@ -0,0 +1,161 @@ +// 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, version 2.0. + +// 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 2.0 for more details. + +// Copyright (C) 2010 Joseph Jordan +// Copyright (C) 2012-2013 damysteryman +// Copyright (C) 2012-2015 Christopher Bratusek +// Copyright (C) 2013 DarkMatterCore +// Copyright (C) 2014 megazig +// Copyright (C) 2015 FIX94 + +#ifndef __RUNTIMEIOSPATCH_H__ +#define __RUNTIMEIOSPATCH_H__ + +/** + * Version information for Libruntimeiospatch. + */ +#define LIB_RUNTIMEIOSPATCH_VERSION "1.5.2" + +//============================================================================== +// HW_RVL header +//============================================================================== +#if defined(HW_RVL) /* defined(HW_RVL) */ + +/** + *Returns true when HW_AHBPROT access can be applied + */ +#define AHBPROT_DISABLED (*(vu32*)0xcd800064 == 0xFFFFFFFF) + +//============================================================================== +// Error code definitions: +//============================================================================== +#define ERROR_AHBPROT -5 +#define ERROR_PATCH -7 + +//============================================================================== +// C++ header +//============================================================================== +#ifdef __cplusplus +extern "C" { +#endif +/* __cplusplus */ + +//============================================================================== +// Extra standard declarations +//============================================================================== +//typedef signed int s32; +//============================================================================== + +//============================================================================== +// Patchsets: +//============================================================================== +/* +Wii: + * DI Readlimit + * ISFS Permissions + * ES SetUID + * ES SetIdentify + * Hash Check (aka Trucha) + * New Hash Check (aka New Trucha) + * SSL patches + +Sciifii: + * MEM2 Prot + * ES OpenTitleContent 1 & 2 + * ES ReadContent Prot + * ES CloseContent + * ES TitleVersionCheck + * ES TitleDeleteCheck + +vWii: + * Kill Anti-SystemTitle-Install 1, 2, 3, 4 & 5 +*/ + + +//============================================================================== +// Functions: +//============================================================================== + +/** + * This function can be used to keep HW_AHBPROT access when going to reload IOS + * @param verbose Flag determing whether or not to print messages on-screen + * @example + * if(AHBPROT_DISABLED) { + * s32 ret; + * ret = IosPatch_AHBPROT(false); + * if (ret) { + * IOS_ReloadIOS(36); + * } else { + * printf("IosPatch_AHBPROT failed."); + * } + * } + * @return Signed 32bit integer representing code + * > 0 : Success - return equals to number of applied patches + * ERROR_AHBPROT : Error - No HW_AHBPROT access + */ +s32 IosPatch_AHBPROT(bool verbose); + + +/** + * This function applies patches on current IOS + * @see Patchsets + * @param wii Flag determining whether or not to apply Wii patches. + * @param sciifii Flag determining whether or not to apply extra Sciifii patches. + * @param vwii Flag determining whether or not to apply extra vWii patches. + * @param wiivc Flag determining whether or not to apply WiiVC patches. + * @param verbose Flag determining whether or not to print messages on-screen. + * @example if(AHBPROT_DISABLED) IosPatch_FULL(true, false, false, false); + * @return Signed 32bit integer representing code + * > 0 : Success - return equals to number of applied patches + * ERROR_AHBPROT : Error - No HW_AHBPROT access + * ERROR_PATCH : Error - Patching HW_AHBPROT access failed + */ +s32 IosPatch_RUNTIME(bool wii, bool sciifii, bool vwii, bool wiivc, bool verbose); + + +/** + * This function combines IosPatch_AHBPROT + IOS_ReloadIOS + IosPatch_RUNTIME + * @see Patchsets + * @param wii Flag determining whether or not to apply Wii patches. + * @param sciifii Flag determining whether or not to apply extra Sciifii patches. + * @param vwii Flag determining whether or not to apply extra vWii patches. + * @param wiivc Flag determining whether or not to apply WiiVC patches. + * @param verbose Flag determining whether or not to print messages on-screen. + * @param IOS Which IOS to reload into. + * @example if(AHBPROT_DISABLED) IosPatch_FULL(true, false, false, false, 58); + * @return Signed 32bit integer representing code + * > 0 : Success - return equals to number of applied patches + * ERROR_AHBPROT : Error - No HW_AHBPROT access + * ERROR_PATCH : Error - Patching HW_AHBPROT access failed + */ +s32 IosPatch_FULL(bool wii, bool sciifii, bool vwii, bool wiivc, bool verbose, int IOS); + +/** + * This function patches only SSL certificate check + * @param verbose Flag determing whether or not to print messages on-screen. + * @example if(AHBPROT_DISABLED) IosPatch_SSL(true); + * @return Signed 32bit integer representing code + * > 0 : Success - return equals to number of applied patches + * ERROR_AHBPROT : Error - No HW_AHBPROT access + */ +s32 IosPatch_SSL(bool verbose); + +//============================================================================== +// C++ footer +//============================================================================== +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +//============================================================================== +// HW_RVL footer +//============================================================================== +#endif /* defined(HW_RVL) */ + +#endif diff --git a/source/libs/libwbfs/gcdisc.c b/source/libs/libwbfs/gcdisc.c new file mode 100644 index 0000000..0910b80 --- /dev/null +++ b/source/libs/libwbfs/gcdisc.c @@ -0,0 +1,144 @@ +// Copyright 2012 Dimok based on wiidisc.c: +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "gcdisc.h" + +static void disc_read(gcdisc_t *d, u32 offset, u8 *data, u32 len) +{ + if (data) + { + int ret = 0; + if (len == 0) return; + ret = d->read(d->fp, offset, len, data); + if (ret < 0) + wbfs_fatal( "error reading disc" ); + } +} + +static u32 do_fst(gcdisc_t *d, u8 *fst, const char *names, u32 i) +{ + u32 offset; + u32 size; + const char *name; + u32 j; + + name = names + (wbfs_be32(fst + 12 * i) & 0x00ffffff); + size = wbfs_be32(fst + 12 * i + 8); + + if (i == 0) + { + for (j = 1; j < size && !d->extracted_buffer;) + { + j = do_fst(d, fst, names, j); + } + return size; + } + + if (fst[12 * i]) + { + + for (j = i + 1; j < size && !d->extracted_buffer;) + j = do_fst(d, fst, names, j); + + return size; + } + else + { + offset = wbfs_be32(fst + 12 * i + 4); + + if (d->extract_pathname && strcasecmp(name, d->extract_pathname) == 0) + { + d->extracted_buffer = wbfs_ioalloc( size ); + d->extracted_size = size; + disc_read(d, offset, d->extracted_buffer, size); + } + return i + 1; + } +} + +static void do_files(gcdisc_t*d) +{ + u8 *b = wbfs_ioalloc( 0x480 ); // XXX: determine actual header size + //u32 dol_offset; + u32 fst_offset; + u32 fst_size; + u8 *fst; + u32 n_files; + disc_read(d, 0, b, 0x480); + + //dol_offset = wbfs_be32(b + 0x0420); + fst_offset = wbfs_be32(b + 0x0424); + fst_size = wbfs_be32(b + 0x0428); + + if (fst_size) + { + fst = wbfs_ioalloc( fst_size ); + if (fst == 0) + wbfs_fatal( "malloc fst" ); + disc_read(d, fst_offset, fst, fst_size); + n_files = wbfs_be32(fst + 8); + + + if (d->extract_pathname && strcmp(d->extract_pathname, "FST") == 0) + { + // if empty pathname requested return fst + d->extracted_buffer = fst; + d->extracted_size = fst_size; + d->extract_pathname = NULL; + // skip do_fst if only fst requested + n_files = 0; + } + + if (12 * n_files <= fst_size) + { + if (n_files > 1) do_fst(d, fst, (char *) fst + 12 * n_files, 0); + } + + if (fst != d->extracted_buffer) wbfs_iofree( fst ); + } + wbfs_iofree( b ); +} + +static void do_disc(gcdisc_t*d) +{ + u8 *b = wbfs_ioalloc( 0x100 ); + u32 magic; + disc_read(d, 0, b, 0x100); + magic = wbfs_be32(b + 28); + if (magic != 0xC2339F3D) + { + wbfs_iofree( b ); + wbfs_error( "not a gc disc" ); + return; + } + wbfs_iofree( b ); + + do_files(d); +} + +gcdisc_t *gc_open_disc(read_wiidisc_callback_t read, void*fp) +{ + gcdisc_t *d = wbfs_malloc( sizeof( gcdisc_t ) ); + if (!d) return 0; + wbfs_memset( d, 0, sizeof( gcdisc_t ) ); + d->read = read; + d->fp = fp; + + return d; +} +void gc_close_disc(gcdisc_t *d) +{ + wbfs_free( d ); +} + +u8 * gc_extract_file(gcdisc_t *d, const char *pathname) +{ + u8 *retval = 0; + d->extract_pathname = pathname; + d->extracted_buffer = 0; + do_disc(d); + d->extract_pathname = 0; + retval = d->extracted_buffer; + return retval; +} diff --git a/source/libs/libwbfs/gcdisc.h b/source/libs/libwbfs/gcdisc.h new file mode 100644 index 0000000..f46ae4c --- /dev/null +++ b/source/libs/libwbfs/gcdisc.h @@ -0,0 +1,32 @@ +#ifndef GCDISC_H +#define GCDISC_H + +#include +#include "libwbfs_os.h" // this file is provided by the project wanting to compile libwbfs and wiidisc +#include "wiidisc.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct gcdisc_s + { + read_wiidisc_callback_t read; + void *fp; + + const char *extract_pathname; + u8 *extracted_buffer; + int extracted_size; + } gcdisc_t; + + gcdisc_t *gc_open_disc(read_wiidisc_callback_t read, void*fp); + void gc_close_disc(gcdisc_t *); + // returns a buffer allocated with wbfs_ioalloc() or NULL if not found of alloc error + u8 * gc_extract_file(gcdisc_t *d, const char *pathname); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/source/libs/libwbfs/libwbfs.c b/source/libs/libwbfs/libwbfs.c new file mode 100644 index 0000000..efe0c64 --- /dev/null +++ b/source/libs/libwbfs/libwbfs.c @@ -0,0 +1,821 @@ +// Copyright 2009 Kwiirk +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +// Modified by oggzee + +#include "libwbfs.h" + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define ERROR(x) do {wbfs_error(x);goto error;}while(0) +#define ALIGN_LBA(x) (((x)+p->hd_sec_sz-1)&(~(p->hd_sec_sz-1))) + +wbfs_t wbfs_iso_file; + +static int force_mode = 0; + +void wbfs_set_force_mode(int force) +{ + force_mode = force; +} + +static u8 size_to_shift(u32 size) +{ + u8 ret = 0; + while (size) + { + ret++; + size >>= 1; + } + return ret - 1; +} +#define read_le32_unaligned(x) ((x)[0]|((x)[1]<<8)|((x)[2]<<16)|((x)[3]<<24)) + +wbfs_t*wbfs_open_hd(rw_sector_callback_t read_hdsector, rw_sector_callback_t write_hdsector, void *callback_data, + int hd_sector_size, int num_hd_sector __attribute( ( unused ) ), int reset) +{ + int i = num_hd_sector, ret; + u8 *ptr, *tmp_buffer = wbfs_ioalloc( hd_sector_size ); + u8 part_table[16 * 4]; + ret = read_hdsector(callback_data, 0, 1, tmp_buffer); + if (ret) return 0; + //find wbfs partition + wbfs_memcpy( part_table, tmp_buffer + 0x1be, 16*4 ); + ptr = part_table; + for (i = 0; i < 4; i++, ptr += 16) + { + u32 part_lba = read_le32_unaligned( ptr + 0x8 ); + wbfs_head_t *head = (wbfs_head_t *) tmp_buffer; + ret = read_hdsector(callback_data, part_lba, 1, tmp_buffer); + // verify there is the magic. + if (head->magic == wbfs_htonl( WBFS_MAGIC )) + { + wbfs_t*p = wbfs_open_partition(read_hdsector, write_hdsector, callback_data, hd_sector_size, 0, part_lba, + reset); + wbfs_iofree( tmp_buffer ); + return p; + } + } + wbfs_iofree( tmp_buffer ); + if (reset)// XXX make a empty hd partition.. + { + } + return 0; +} +wbfs_t*wbfs_open_partition(rw_sector_callback_t read_hdsector, rw_sector_callback_t write_hdsector, + void *callback_data, int hd_sector_size, int num_hd_sector, u32 part_lba, int reset) +{ + wbfs_t *p = wbfs_malloc( sizeof( wbfs_t ) ); + + wbfs_head_t *head = wbfs_ioalloc( hd_sector_size ? hd_sector_size : 512 ); + + //constants, but put here for consistancy + p->wii_sec_sz = 0x8000; + p->wii_sec_sz_s = size_to_shift(0x8000); + p->n_wii_sec = (num_hd_sector / 0x8000) * hd_sector_size; + p->n_wii_sec_per_disc = 143432 * 2;//support for double layers discs.. + p->head = head; + p->part_lba = part_lba; + // init the partition + if (reset) + { + u8 sz_s; + wbfs_memset( head, 0, hd_sector_size ); + head->magic = wbfs_htonl( WBFS_MAGIC ); + head->hd_sec_sz_s = size_to_shift(hd_sector_size); + head->n_hd_sec = wbfs_htonl( num_hd_sector ); + // choose minimum wblk_sz that fits this partition size + for (sz_s = 6; sz_s < 11; sz_s++) + { + // ensure that wbfs_sec_sz is big enough to address every blocks using 16 bits + if (p->n_wii_sec < ((1U << 16) * (1 << sz_s))) break; + } + head->wbfs_sec_sz_s = sz_s + p->wii_sec_sz_s; + } + else read_hdsector(callback_data, p->part_lba, 1, head); + if (head->magic != wbfs_htonl( WBFS_MAGIC )) + ERROR( "bad magic" ); + if (!force_mode && hd_sector_size && head->hd_sec_sz_s != size_to_shift(hd_sector_size)) + ERROR( "hd sector size doesn't match" ); + if (!force_mode && num_hd_sector && head->n_hd_sec != (u32) wbfs_htonl( num_hd_sector )) + ERROR( "hd num sector doesn't match" ); + p->hd_sec_sz = 1 << head->hd_sec_sz_s; + p->hd_sec_sz_s = head->hd_sec_sz_s; + p->n_hd_sec = wbfs_ntohl( head->n_hd_sec ); + + p->n_wii_sec = (p->n_hd_sec / p->wii_sec_sz) * (p->hd_sec_sz); + + p->wbfs_sec_sz_s = head->wbfs_sec_sz_s; + p->wbfs_sec_sz = 1 << p->wbfs_sec_sz_s; + p->n_wbfs_sec = p->n_wii_sec >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s); + p->n_wbfs_sec_per_disc = p->n_wii_sec_per_disc >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s); + p->disc_info_sz = ALIGN_LBA( sizeof( wbfs_disc_info_t ) + p->n_wbfs_sec_per_disc * 2 ); + + //printf("hd_sector_size %X wii_sector size %X wbfs sector_size %X\n",p->hd_sec_sz,p->wii_sec_sz,p->wbfs_sec_sz); + p->read_hdsector = read_hdsector; + p->write_hdsector = write_hdsector; + p->callback_data = callback_data; + + p->freeblks_lba = (p->wbfs_sec_sz - p->n_wbfs_sec / 8) >> p->hd_sec_sz_s; + + if (!reset) + p->freeblks = 0; // will alloc and read only if needed + else + { + // init with all free blocks + p->freeblks = wbfs_ioalloc( ALIGN_LBA( p->n_wbfs_sec / 8 ) ); + wbfs_memset( p->freeblks, 0xff, p->n_wbfs_sec / 8 ); + } + p->max_disc = (p->freeblks_lba - 1) / (p->disc_info_sz >> p->hd_sec_sz_s); + if (p->max_disc > p->hd_sec_sz - sizeof(wbfs_head_t)) p->max_disc = p->hd_sec_sz - sizeof(wbfs_head_t); + + p->tmp_buffer = wbfs_ioalloc( p->hd_sec_sz ); + p->n_disc_open = 0; + return p; + error: wbfs_free( p ); + wbfs_iofree( head ); + return 0; + +} + +void wbfs_sync(wbfs_t*p) +{ + // copy back descriptors + if (p->write_hdsector) + { + p->write_hdsector(p->callback_data, p->part_lba + 0, 1, p->head); + + if (p->freeblks) p->write_hdsector(p->callback_data, p->part_lba + p->freeblks_lba, + ALIGN_LBA( p->n_wbfs_sec / 8 ) >> p->hd_sec_sz_s, p->freeblks); + } +} + +void wbfs_close(wbfs_t*p) +{ + wbfs_sync(p); + + if (p->n_disc_open) + ERROR( "trying to close wbfs while discs still open" ); + + wbfs_iofree( p->head ); + wbfs_iofree( p->tmp_buffer ); + if (p->freeblks) wbfs_iofree( p->freeblks ); + + wbfs_free( p ); + + error: return; +} + +wbfs_disc_t *wbfs_open_disc(wbfs_t* p, u8 *discid) +{ + u32 i; + int disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s; + wbfs_disc_t *d = 0; + for (i = 0; i < p->max_disc; i++) + { + if (p->head->disc_table[i]) + { + p->read_hdsector(p->callback_data, p->part_lba + 1 + i * disc_info_sz_lba, 1, p->tmp_buffer); + if (wbfs_memcmp( discid, p->tmp_buffer, 6 ) == 0) + { + d = wbfs_malloc( sizeof( *d ) ); + if (!d) + ERROR( "allocating memory" ); + d->p = p; + d->i = i; + d->header = wbfs_ioalloc( p->disc_info_sz ); + if (!d->header) + ERROR( "allocating memory" ); + p->read_hdsector(p->callback_data, p->part_lba + 1 + i * disc_info_sz_lba, disc_info_sz_lba, d->header); + p->n_disc_open++; + // for(i=0;in_wbfs_sec_per_disc;i++) + // printf("%d,",wbfs_ntohs(d->header->wlba_table[i])); + return d; + } + } + } + return 0; + error: if (d) wbfs_iofree( d ); + return 0; + +} +void wbfs_close_disc(wbfs_disc_t*d) +{ + d->p->n_disc_open--; + wbfs_iofree( d->header ); + wbfs_free( d ); +} +// offset is pointing 32bit words to address the whole dvd, although len is in bytes +int wbfs_disc_read(wbfs_disc_t*d, u32 offset, u32 len, u8 *data) +{ + if (d->p == &wbfs_iso_file) + { + return wbfs_iso_file_read(d, offset, data, len); + } + + wbfs_t *p = d->p; + u16 wlba = offset >> (p->wbfs_sec_sz_s - 2); + u32 iwlba_shift = p->wbfs_sec_sz_s - p->hd_sec_sz_s; + u32 lba_mask = (p->wbfs_sec_sz - 1) >> (p->hd_sec_sz_s); + u32 lba = (offset >> (p->hd_sec_sz_s - 2)) & lba_mask; + u32 off = offset & ((p->hd_sec_sz >> 2) - 1); + u16 iwlba = wbfs_ntohs( d->header->wlba_table[wlba] ); + u32 len_copied; + int err = 0; + u8 *ptr = data; + if (unlikely( iwlba == 0 )) return 1; + if (unlikely( off )) + { + off *= 4; + err = p->read_hdsector(p->callback_data, p->part_lba + (iwlba << iwlba_shift) + lba, 1, p->tmp_buffer); + if (err) return err; + len_copied = p->hd_sec_sz - off; + if (likely( len < len_copied )) len_copied = len; + wbfs_memcpy( ptr, p->tmp_buffer + off, len_copied ); + len -= len_copied; + ptr += len_copied; + lba++; + if (unlikely( lba > lba_mask && len )) + { + lba = 0; + iwlba = wbfs_ntohs( d->header->wlba_table[++wlba] ); + if (unlikely( iwlba == 0 )) return 1; + } + } + while (likely( len >= p->hd_sec_sz )) + { + u32 nlb = len >> (p->hd_sec_sz_s); + + if (unlikely( lba + nlb > p->wbfs_sec_sz )) // dont cross wbfs sectors.. + nlb = p->wbfs_sec_sz - lba; + err = p->read_hdsector(p->callback_data, p->part_lba + (iwlba << iwlba_shift) + lba, nlb, ptr); + if (err) return err; + len -= nlb << p->hd_sec_sz_s; + ptr += nlb << p->hd_sec_sz_s; + lba += nlb; + if (unlikely( lba > lba_mask && len )) + { + lba = 0; + iwlba = wbfs_ntohs( d->header->wlba_table[++wlba] ); + if (unlikely( iwlba == 0 )) return 1; + } + } + if (unlikely( len )) + { + err = p->read_hdsector(p->callback_data, p->part_lba + (iwlba << iwlba_shift) + lba, 1, p->tmp_buffer); + if (err) return err; + wbfs_memcpy( ptr, p->tmp_buffer, len ); + } + return 0; +} + +// disc listing +u32 wbfs_count_discs(wbfs_t*p) +{ + u32 i, count = 0; + for (i = 0; i < p->max_disc; i++) + if (p->head->disc_table[i]) count++; + return count; + +} + +u32 wbfs_sector_used(wbfs_t *p, wbfs_disc_info_t *di) +{ + u32 tot_blk = 0, j; + for (j = 0; j < p->n_wbfs_sec_per_disc; j++) + if (wbfs_ntohs( di->wlba_table[j] )) tot_blk++; + return tot_blk; +} + +u32 wbfs_get_disc_info(wbfs_t*p, u32 index, u8 *header, int header_size, u32 *size)//size in 32 bit +{ + u32 i, count = 0; + if (!p) return 1; + int disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s; + + for (i = 0; i < p->max_disc; i++) + if (p->head->disc_table[i]) + { + if (count++ == index) + { + p->read_hdsector(p->callback_data, p->part_lba + 1 + i * disc_info_sz_lba, 1, p->tmp_buffer); + if (header_size > (int) p->hd_sec_sz) header_size = p->hd_sec_sz; + u32 magic = wbfs_ntohl( *( u32* )( p->tmp_buffer + 24 ) ); + if (magic != 0x5D1C9EA3) + { + p->head->disc_table[i] = 0; + return 1; + } + memcpy(header, p->tmp_buffer, header_size); + if (size) + { + u8 *header = wbfs_ioalloc( p->disc_info_sz ); + p->read_hdsector(p->callback_data, p->part_lba + 1 + i * disc_info_sz_lba, disc_info_sz_lba, header); + u32 sec_used = wbfs_sector_used(p, (wbfs_disc_info_t *) header); + wbfs_iofree( header ); + *size = sec_used << (p->wbfs_sec_sz_s - 2); + } + return 0; + } + } + return 1; +} + +static void load_freeblocks(wbfs_t*p) +{ + if (p->freeblks) return; + // XXX should handle malloc error.. + p->freeblks = wbfs_ioalloc( ALIGN_LBA( p->n_wbfs_sec / 8 ) ); + p->read_hdsector(p->callback_data, p->part_lba + p->freeblks_lba, ALIGN_LBA( p->n_wbfs_sec / 8 ) >> p->hd_sec_sz_s, + p->freeblks); + +} +u32 wbfs_count_usedblocks(wbfs_t*p) +{ + u32 i, j, count = 0; + load_freeblocks(p); + for (i = 0; i < p->n_wbfs_sec / (8 * 4); i++) + { + u32 v = wbfs_ntohl( p->freeblks[i] ); + if (v == ~0U) + count += 32; + else if (v != 0) for (j = 0; j < 32; j++) + if (v & (1 << j)) count++; + } + return count; +} + +// write access + + +//static +int block_used(u8 *used, u32 i, u32 wblk_sz) +{ + u32 k; + i *= wblk_sz; + for (k = 0; k < wblk_sz; k++) + if (i + k < 143432 * 2 && used[i + k]) return 1; + return 0; +} + +static u32 alloc_block(wbfs_t*p) +{ + u32 i, j; + for (i = 0; i < p->n_wbfs_sec / (8 * 4); i++) + { + u32 v = wbfs_ntohl( p->freeblks[i] ); + if (v != 0) + { + for (j = 0; j < 32; j++) + if (v & (1 << j)) + { + p->freeblks[i] = wbfs_htonl( v & ~( 1 << j ) ); + return (i * 32) + j + 1; + } + } + } + return ~0; +} +static void free_block(wbfs_t *p, int bl) +{ + int i = (bl - 1) / (32); + int j = (bl - 1) & 31; + u32 v = wbfs_ntohl( p->freeblks[i] ); + p->freeblks[i] = wbfs_htonl( v | 1 << j ); +} + +int install_abort_signal = 0; + +s32 wbfs_add_disc(wbfs_t*p, read_wiidisc_callback_t read_src_wii_disc, void *callback_data, + progress_callback_t spinner, partition_selector_t sel, int copy_1_1) +{ + int i, discn, ret; + u32 tot, cur; + u32 wii_sec_per_wbfs_sect = 1 << (p->wbfs_sec_sz_s - p->wii_sec_sz_s); + wiidisc_t *d = 0; + u8 *used = 0; + wbfs_disc_info_t *info = 0; + u8* copy_buffer = 0; + int retval = -1; + int num_wbfs_sect_to_copy; + u32 last_used; + used = wbfs_malloc( p->n_wii_sec_per_disc ); + + if (!used) + ERROR( "unable to alloc memory" ); + // copy_1_1 needs disk usage for layers detection + //if(!copy_1_1) + { + d = wd_open_disc(read_src_wii_disc, callback_data); + if (!d) + ERROR( "unable to open wii disc" ); + wd_build_disc_usage(d, sel, used); + wd_close_disc(d); + d = 0; + } + + for (i = 0; i < p->max_disc; i++)// find a free slot. + if (p->head->disc_table[i] == 0) break; + if (i == p->max_disc) + ERROR( "no space left on device (table full)" ); + p->head->disc_table[i] = 1; + discn = i; + load_freeblocks(p); + + // build disc info + info = wbfs_ioalloc( p->disc_info_sz ); + read_src_wii_disc(callback_data, 0, 0x100, info->disc_header_copy); + + copy_buffer = wbfs_ioalloc( p->wii_sec_sz ); + if (!copy_buffer) + ERROR( "alloc memory" ); + tot = 0; + cur = 0; + num_wbfs_sect_to_copy = p->n_wbfs_sec_per_disc; + // count total number of sectors to write + last_used = 0; + for (i = 0; i < num_wbfs_sect_to_copy; i++) + { + if (block_used(used, i, wii_sec_per_wbfs_sect)) + { + tot += wii_sec_per_wbfs_sect; + last_used = i; + } + } + if (copy_1_1) + { + // detect single or dual layer + if ((last_used + 1) > (p->n_wbfs_sec_per_disc / 2)) + { + // dual layer + num_wbfs_sect_to_copy = p->n_wbfs_sec_per_disc; + } + else + { + // single layer + num_wbfs_sect_to_copy = p->n_wbfs_sec_per_disc / 2; + } + tot = num_wbfs_sect_to_copy * wii_sec_per_wbfs_sect; + } + + install_abort_signal = 0; + /* + // num of hd sectors to copy could be specified directly + if (copy_1_1 > 1) { + u32 hd_sec_per_wii_sec = p->wii_sec_sz / p->hd_sec_sz; + num_wbfs_sect_to_copy = copy_1_1 / hd_sec_per_wii_sec / wii_sec_per_wbfs_sect; + tot = num_wbfs_sect_to_copy * wii_sec_per_wbfs_sect; + }*/ + if (spinner) spinner(0, tot); + for (i = 0; i < num_wbfs_sect_to_copy; i++) + { + u16 bl = 0; + if (copy_1_1 || block_used(used, i, wii_sec_per_wbfs_sect)) + { + u16 j; + + bl = alloc_block(p); + if (bl == 0xffff) + ERROR( "no space left on device (disc full)" ); + for (j = 0; j < wii_sec_per_wbfs_sect; j++) + { + u32 offset = (i * (p->wbfs_sec_sz >> 2)) + (j * (p->wii_sec_sz >> 2)); + + ret = read_src_wii_disc(callback_data, offset, p->wii_sec_sz, copy_buffer); + if (ret) + { + if (copy_1_1 && i > p->n_wbfs_sec_per_disc / 2) + { + // end of dual layer data + if (j > 0) + { + info->wlba_table[i] = wbfs_htons( bl ); + } + spinner(tot, tot); + break; + } + //ERROR("read error"); + printf("\rWARNING: read (%u) error (%d)\n", (unsigned int)offset, ret); + } + + //fix the partition table + if (offset == (0x40000 >> 2)) wd_fix_partition_table(d, sel, copy_buffer); + p->write_hdsector(p->callback_data, p->part_lba + bl * (p->wbfs_sec_sz / p->hd_sec_sz) + j + * (p->wii_sec_sz / p->hd_sec_sz), p->wii_sec_sz / p->hd_sec_sz, copy_buffer); + cur++; + if (spinner) spinner(cur, tot); + } + } + if (install_abort_signal) + break; + info->wlba_table[i] = wbfs_htons( bl ); + } + + if(install_abort_signal) + { + int n; + for(n = 0; n < i; n++) + { + u32 iwlba = wbfs_ntohs(info->wlba_table[n]); + if (iwlba) + free_block(p,iwlba); + } + wbfs_memset(info,0,p->disc_info_sz); + p->head->disc_table[discn] = 0; + } + // write disc info + int disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s; + p->write_hdsector(p->callback_data, p->part_lba + 1 + discn * disc_info_sz_lba, disc_info_sz_lba, info); + wbfs_sync(p); + retval = 0; + error: if (d) wd_close_disc(d); + if (used) wbfs_free( used ); + if (info) wbfs_iofree( info ); + if (copy_buffer) wbfs_iofree( copy_buffer ); + // init with all free blocks + + return retval; +} + +u32 wbfs_rm_disc(wbfs_t*p, u8* discid) +{ + wbfs_disc_t *d = wbfs_open_disc(p, discid); + int i; + int discn = 0; + int disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s; + if (!d) return 1; + load_freeblocks(p); + discn = d->i; + for (i = 0; i < p->n_wbfs_sec_per_disc; i++) + { + u32 iwlba = wbfs_ntohs( d->header->wlba_table[i] ); + if (iwlba) free_block(p, iwlba); + } + memset(d->header, 0, p->disc_info_sz); + p->write_hdsector(p->callback_data, p->part_lba + 1 + discn * disc_info_sz_lba, disc_info_sz_lba, d->header); + p->head->disc_table[discn] = 0; + wbfs_close_disc(d); + wbfs_sync(p); + return 0; +} + +u32 wbfs_ren_disc(wbfs_t*p, u8* discid, u8* newname) +{ + wbfs_disc_t *d = wbfs_open_disc(p, discid); + int disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s; + + if (!d) return 1; + + memset(d->header->disc_header_copy + 0x20, 0, 0x40); + strncpy((char *) d->header->disc_header_copy + 0x20, (char *) newname, 0x39); + + p->write_hdsector(p->callback_data, p->part_lba + 1 + d->i * disc_info_sz_lba, disc_info_sz_lba, d->header); + wbfs_close_disc(d); + return 0; +} + +u32 wbfs_rID_disc(wbfs_t*p, u8* discid, u8* newID) +{ + wbfs_disc_t *d = wbfs_open_disc(p, discid); + int disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s; + + if (!d) return 1; + + memset(d->header->disc_header_copy, 0, 0x10); + strncpy((char *) d->header->disc_header_copy, (char *) newID, 0x9); + + p->write_hdsector(p->callback_data, p->part_lba + 1 + d->i * disc_info_sz_lba, disc_info_sz_lba, d->header); + wbfs_close_disc(d); + return 0; +} + +// trim the file-system to its minimum size +u32 wbfs_trim(wbfs_t*p) +{ + u32 maxbl; + load_freeblocks(p); + maxbl = alloc_block(p); + p->n_hd_sec = maxbl << (p->wbfs_sec_sz_s - p->hd_sec_sz_s); + p->head->n_hd_sec = wbfs_htonl( p->n_hd_sec ); + // make all block full + memset(p->freeblks, 0, p->n_wbfs_sec / 8); + wbfs_sync(p); + // os layer will truncate the file. + return maxbl; +} + +// data extraction +u32 wbfs_extract_disc(wbfs_disc_t*d, rw_sector_callback_t write_dst_wii_sector, void *callback_data, + progress_callback_t spinner) +{ + wbfs_t *p = d->p; + u8* copy_buffer = 0; + int i; + int src_wbs_nlb = p->wbfs_sec_sz / p->hd_sec_sz; + int dst_wbs_nlb = p->wbfs_sec_sz / p->wii_sec_sz; + copy_buffer = wbfs_ioalloc( p->wbfs_sec_sz ); + if (!copy_buffer) + { + wbfs_error( "alloc memory" ); + return 1; + } + + for (i = 0; i < p->n_wbfs_sec_per_disc; i++) + { + u32 iwlba = wbfs_ntohs( d->header->wlba_table[i] ); + if (iwlba) + { + + if (spinner) spinner(i, p->n_wbfs_sec_per_disc); + p->read_hdsector(p->callback_data, p->part_lba + iwlba * src_wbs_nlb, src_wbs_nlb, copy_buffer); + write_dst_wii_sector(callback_data, i * dst_wbs_nlb, dst_wbs_nlb, copy_buffer); + } + } + wbfs_iofree( copy_buffer ); + return 0; +} + +u64 wbfs_estimate_disc(wbfs_t *p, read_wiidisc_callback_t read_src_wii_disc, void *callback_data, partition_selector_t sel) +{ + int i; + u32 tot; + u32 wii_sec_per_wbfs_sect = 1 << (p->wbfs_sec_sz_s - p->wii_sec_sz_s); + wiidisc_t *d = 0; + u8 *used = 0; + wbfs_disc_info_t *info = 0; + + tot = 0; + + used = wbfs_malloc( p->n_wii_sec_per_disc ); + if (!used) + { + ERROR( "unable to alloc memory" ); + } + + d = wd_open_disc(read_src_wii_disc, callback_data); + if (!d) + { + ERROR( "unable to open wii disc" ); + } + + wd_build_disc_usage(d, sel, used); + wd_close_disc(d); + d = 0; + + info = wbfs_ioalloc( p->disc_info_sz ); + read_src_wii_disc(callback_data, 0, 0x100, info->disc_header_copy); + + for (i = 0; i < p->n_wbfs_sec_per_disc; i++) + { + if (block_used(used, i, wii_sec_per_wbfs_sect)) + { + tot++; + } + } + + error: + if (d) wd_close_disc(d); + if (used) wbfs_free( used ); + if (info) wbfs_iofree( info ); + + return (u64) tot * (u64) p->wbfs_sec_sz; +} + +u32 wbfs_size_disc(wbfs_t*p, read_wiidisc_callback_t read_src_wii_disc, void *callback_data, partition_selector_t sel, + u32 *comp_size, u32 *real_size) +{ + int i; + u32 tot = 0, last = 0; + u32 wii_sec_per_wbfs_sect = 1 << (p->wbfs_sec_sz_s - p->wii_sec_sz_s); + wiidisc_t *d = 0; + u8 *used = 0; + used = wbfs_malloc( p->n_wii_sec_per_disc ); + if (!used) + ERROR( "unable to alloc memory" ); + d = wd_open_disc(read_src_wii_disc, callback_data); + if (!d) + ERROR( "unable to open wii disc" ); + wd_build_disc_usage(d, sel, used); + wd_close_disc(d); + d = 0; + + // count total number to write for spinner + for (i = 0; i < p->n_wbfs_sec_per_disc; i++) + { + if (block_used(used, i, wii_sec_per_wbfs_sect)) + { + tot += wii_sec_per_wbfs_sect; + last = i * wii_sec_per_wbfs_sect; + } + } + + error: if (d) wd_close_disc(d); + if (used) wbfs_free( used ); + + *comp_size = tot; + *real_size = last; + + return 0; +} + +// offset is pointing 32bit words to address the whole dvd, although len is in bytes +//int wbfs_disc_read(wbfs_disc_t*d,u32 offset, u8 *data, u32 len) + +// offset points 32bit words, count counts bytes +//int (*read_wiidisc_callback_t)(void*fp,u32 offset,u32 count,void*iobuf); + +// connect wiidisc to wbfs_disc +s32 read_wiidisc_wbfsdisc(void*fp, u32 offset, u32 count, void*iobuf) +{ + return wbfs_disc_read((wbfs_disc_t*) fp, offset, count, iobuf); +} + +int wbfs_extract_file(wbfs_disc_t*d, char *path, void **data) +{ + wiidisc_t *wd = 0; + int ret = 0; + + wd = wd_open_disc(read_wiidisc_wbfsdisc, d); + if (!wd) + { + wbfs_error( "opening wbfs disc" ); + return -1; + } + wd->extracted_size = 0; + *data = wd_extract_file(wd, ONLY_GAME_PARTITION, path); + ret = wd->extracted_size; + if (!*data) + { + //ERROR("file not found"); + ret = -1; + } + wd_close_disc(wd); + + return ret; +} + +int wbfs_get_fragments(wbfs_disc_t *d, _frag_append_t append_fragment, void *callback_data, u32 hdd_sector_size) +{ + if (!d) return -1; + + wbfs_t *p = d->p; + int src_wbs_nlb = p->wbfs_sec_sz / hdd_sector_size; + int i, ret, last = 0; + for (i = 0; i < p->n_wbfs_sec_per_disc; i++) + { + u32 iwlba = wbfs_ntohs( d->header->wlba_table[i] ); + if (iwlba) + { + ret = append_fragment(callback_data, i * src_wbs_nlb, // offset + p->part_lba + iwlba * src_wbs_nlb, // sector + src_wbs_nlb); // count + if (ret) return ret; // error + last = i; + } + } + if (last < p->n_wbfs_sec_per_disc / 2) + { + last = p->n_wbfs_sec_per_disc / 2; + } + u32 size = last * src_wbs_nlb; + append_fragment(callback_data, size, 0, 0); // set size + return 0; +} + +// wrapper for reading .iso files using wbfs apis + +#include +#include + +// offset is pointing 32bit words to address the whole dvd, although len is in bytes +int wbfs_iso_file_read(wbfs_disc_t*d, u32 offset, u8 *data, u32 len) +{ + if (!d || d->p != &wbfs_iso_file) return -1; + int fd = d->i; + off_t off = ((u64) offset) << 2; + off_t ret_off; + int ret; + ret_off = lseek(fd, off, SEEK_SET); + if (ret_off != off) return -1; + ret = read(fd, data, len); + if (ret != (int) len) return -2; + return 0; +} + +u32 wbfs_disc_sector_used(wbfs_disc_t *d) +{ + if(!d) return 0; + + if (d->p == &wbfs_iso_file) + { + int fd = d->i; + struct stat st; + if (fstat(fd, &st) == -1) return 0; + return (st.st_size >> 9); + } + + return wbfs_sector_used(d->p, d->header); +} + diff --git a/source/libs/libwbfs/libwbfs.h b/source/libs/libwbfs/libwbfs.h new file mode 100644 index 0000000..b3accdc --- /dev/null +++ b/source/libs/libwbfs/libwbfs.h @@ -0,0 +1,234 @@ +// Modified by oggzee + +#ifndef LIBWBFS_H +#define LIBWBFS_H + +#include "libwbfs_os.h" // this file is provided by the project wanting to compile libwbfs +#include "wiidisc.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + enum + { + WBFS_DEVICE_USB = 1, /* USB device */ + WBFS_DEVICE_SDHC + /* SDHC device */ + }; + + typedef u32 be32_t; + typedef u16 be16_t; + + typedef struct wbfs_head + { + be32_t magic; + // parameters copied in the partition for easy dumping, and bug reports + be32_t n_hd_sec; // total number of hd_sec in this partition + u8 hd_sec_sz_s; // sector size in this partition + u8 wbfs_sec_sz_s; // size of a wbfs sec + u8 padding3[2]; + u8 disc_table[0]; // size depends on hd sector size + }__attribute( ( packed ) ) wbfs_head_t; + + typedef struct wbfs_disc_info + { + u8 disc_header_copy[0x100]; + be16_t wlba_table[0]; + } wbfs_disc_info_t; + + // WBFS first wbfs_sector structure: + // + // ----------- + // | wbfs_head | (hd_sec_sz) + // ----------- + // | | + // | disc_info | + // | | + // ----------- + // | | + // | disc_info | + // | | + // ----------- + // | | + // | ... | + // | | + // ----------- + // | | + // | disc_info | + // | | + // ----------- + // | | + // |freeblk_tbl| + // | | + // ----------- + // + + // callback definition. Return 1 on fatal error (callback is supposed to make retries until no hopes..) + typedef s32 (*rw_sector_callback_t)(void*fp, u32 lba, u32 count, void*iobuf); + typedef void (*progress_callback_t)(s64 status, s64 total); + + typedef struct wbfs_s + { + wbfs_head_t *head; + + /* hdsectors, the size of the sector provided by the hosting hard drive */ + u32 hd_sec_sz; + u8 hd_sec_sz_s; // the power of two of the last number + u32 n_hd_sec; // the number of hd sector in the wbfs partition + + /* standard wii sector (0x8000 bytes) */ + u32 wii_sec_sz; + u8 wii_sec_sz_s; + u32 n_wii_sec; + u32 n_wii_sec_per_disc; + + /* The size of a wbfs sector */ + u32 wbfs_sec_sz; + u32 wbfs_sec_sz_s; + u16 n_wbfs_sec; // this must fit in 16 bit! + u16 n_wbfs_sec_per_disc; // size of the lookup table + + u32 part_lba; + /* virtual methods to read write the partition */ + rw_sector_callback_t read_hdsector; + rw_sector_callback_t write_hdsector; + void *callback_data; + + u16 max_disc; + u32 freeblks_lba; + u32 *freeblks; + u16 disc_info_sz; + + u8 *tmp_buffer; // pre-allocated buffer for unaligned read + + u32 n_disc_open; + + } wbfs_t; + + typedef struct wbfs_disc_s + { + wbfs_t *p; + wbfs_disc_info_t *header; // pointer to wii header + int i; // disc index in the wbfs header (disc_table) + } wbfs_disc_t; + +#define WBFS_MAGIC (('W'<<24)|('B'<<16)|('F'<<8)|('S')) + + /*! @brief open a MSDOS partitionned harddrive. This tries to find a wbfs partition into the harddrive + @param read_hdsector,write_hdsector: accessors to a harddrive + @hd_sector_size: size of the hd sector. Can be set to zero if the partition in already initialized + @num_hd_sector: number of sectors in this disc. Can be set to zero if the partition in already initialized + @reset: not implemented, This will format the whole harddrive with one wbfs partition that fits the whole disk. + calls wbfs_error() to have textual meaning of errors + @return NULL in case of error + */ + wbfs_t*wbfs_open_hd(rw_sector_callback_t read_hdsector, rw_sector_callback_t write_hdsector, void *callback_data, + int hd_sector_size, int num_hd_sector, int reset); + + /*! @brief open a wbfs partition + @param read_hdsector,write_hdsector: accessors to the partition + @hd_sector_size: size of the hd sector. Can be set to zero if the partition in already initialized + @num_hd_sector: number of sectors in this partition. Can be set to zero if the partition in already initialized + @partition_lba: The partitio offset if you provided accessors to the whole disc. + @reset: initialize the partition with an empty wbfs. + calls wbfs_error() to have textual meaning of errors + @return NULL in case of error + */ + wbfs_t*wbfs_open_partition(rw_sector_callback_t read_hdsector, rw_sector_callback_t write_hdsector, + void *callback_data, int hd_sector_size, int num_hd_sector, u32 partition_lba, int reset); + + /*! @brief close a wbfs partition, and sync the metadatas to the disc */ + void wbfs_close(wbfs_t*); + + /*! @brief open a disc inside a wbfs partition use a 6 char discid+vendorid + @return NULL if discid is not present + */ + wbfs_disc_t *wbfs_open_disc(wbfs_t* p, u8 *diskid); + + /*! @brief close a already open disc inside a wbfs partition */ + void wbfs_close_disc(wbfs_disc_t*d); + + u32 wbfs_sector_used(wbfs_t *p, wbfs_disc_info_t *di); + + /*! @brief accessor to the wii disc + @param d: a pointer to already open disc + @param offset: an offset inside the disc, *points 32bit words*, allowing to access 16GB data + @param len: The length of the data to fetch, in *bytes* + */ + // offset is pointing 32bit words to address the whole dvd, although len is in bytes + int wbfs_disc_read(wbfs_disc_t*d, u32 offset, u32 len, u8 *data); + + /*! @return the number of discs inside the partition */ + u32 wbfs_count_discs(wbfs_t*p); + /*! get the disc info of ith disc inside the partition. It correspond to the first 0x100 bytes of the wiidvd + http://www.wiibrew.org/wiki/Wiidisc#Header + @param i: index of the disc inside the partition + @param header: pointer to 0x100 bytes to write the header + @size: optional pointer to a 32bit word that will get the size in 32bit words of the DVD taken on the partition. + */ + u32 wbfs_get_disc_info(wbfs_t*p, u32 i, u8 *header, int header_size, u32 *size); + + /*! get the number of used block of the partition. + to be multiplied by p->wbfs_sec_sz (use 64bit multiplication) to have the number in bytes + */ + u32 wbfs_count_usedblocks(wbfs_t*p); + + /******************* write access ******************/ + + /*! add a wii dvd inside the partition + @param read_src_wii_disc: a callback to access the wii dvd. offsets are in 32bit, len in bytes! + @callback_data: private data passed to the callback + @spinner: a pointer to a function that is regulary called to update a progress bar. + @sel: selects which partitions to copy. + @copy_1_1: makes a 1:1 copy, whenever a game would not use the wii disc format, and some data is hidden outside the filesystem. + */ + s32 wbfs_add_disc(wbfs_t*p, read_wiidisc_callback_t read_src_wii_disc, void *callback_data, + progress_callback_t spinner, partition_selector_t sel, int copy_1_1); + + /*! remove a wiidvd inside a partition */ + u32 wbfs_rm_disc(wbfs_t*p, u8* discid); + + /*! rename a game */ + u32 wbfs_ren_disc(wbfs_t*p, u8* discid, u8* newname); + + /* change ID of a game*/ + u32 wbfs_rID_disc(wbfs_t*p, u8* discid, u8* newID); + /*! trim the file-system to its minimum size + This allows to use wbfs as a wiidisc container + */ + u32 wbfs_trim(wbfs_t*p); + + /*! extract a disc from the wbfs, unused sectors are just untouched, allowing descent filesystem to only really usefull space to store the disc. + Even if the filesize is 4.7GB, the disc usage will be less. + */ + u32 wbfs_extract_disc(wbfs_disc_t*d, rw_sector_callback_t write_dst_wii_sector, void *callback_data, + progress_callback_t spinner); + + /*! extract a file from the wii disc filesystem. + E.G. Allows to extract the opening.bnr to install a game as a system menu channel + */ + int wbfs_extract_file(wbfs_disc_t*d, char *path, void **data); + + // remove some sanity checks + void wbfs_set_force_mode(int force); + + u64 wbfs_estimate_disc(wbfs_t *p, read_wiidisc_callback_t read_src_wii_disc, void *callback_data, + partition_selector_t sel); + // compressed and real size + u32 wbfs_size_disc(wbfs_t*p, read_wiidisc_callback_t read_src_wii_disc, void *callback_data, + partition_selector_t sel, u32 *comp_size, u32 *real_size); + + typedef int (*_frag_append_t)(void *ff, u32 offset, u32 sector, u32 count); + int wbfs_get_fragments(wbfs_disc_t *d, _frag_append_t append_fragment, void *callback_data, u32 hdd_sector_size); + + extern wbfs_t wbfs_iso_file; + u32 wbfs_disc_sector_used(wbfs_disc_t *d); + int wbfs_iso_file_read(wbfs_disc_t*d, u32 offset, u8 *data, u32 len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/source/libs/libwbfs/libwbfs_os.h b/source/libs/libwbfs/libwbfs_os.h new file mode 100644 index 0000000..0453145 --- /dev/null +++ b/source/libs/libwbfs/libwbfs_os.h @@ -0,0 +1,33 @@ +#ifndef LIBWBFS_GLUE_H +#define LIBWBFS_GLUE_H + +#include +#include "memory/mem2.h" + +#define debug_printf(fmt, ...); + +#include +#define wbfs_fatal(x) do { printf("\nwbfs panic: %s\n\n",x); return; } while(0) +#define wbfs_error(x) do { printf("\nwbfs error: %s\n\n",x); } while(0) + +#include +#include + +#define wbfs_malloc(x) MEM2_alloc(x) +#define wbfs_free(x) free(x) +#define wbfs_ioalloc(x) MEM2_alloc(((x) + 31) & ~31) +#define wbfs_iofree(x) free(x) +#define wbfs_be16(x) (*((u16*)(x))) +#define wbfs_be32(x) (*((u32*)(x))) +#define wbfs_ntohl(x) (x) +#define wbfs_htonl(x) (x) +#define wbfs_ntohs(x) (x) +#define wbfs_htons(x) (x) + +#include + +#define wbfs_memcmp(x,y,z) memcmp(x,y,z) +#define wbfs_memcpy(x,y,z) memcpy(x,y,z) +#define wbfs_memset(x,y,z) memset(x,y,z) + +#endif diff --git a/source/libs/libwbfs/rijndael.c b/source/libs/libwbfs/rijndael.c new file mode 100644 index 0000000..41f3bcc --- /dev/null +++ b/source/libs/libwbfs/rijndael.c @@ -0,0 +1,432 @@ +/* Rijndael Block Cipher - rijndael.c + + Written by Mike Scott 21st April 1999 + mike@compapp.dcu.ie + + Permission for free direct or derivative use is granted subject + to compliance with any conditions that the originators of the + algorithm place on its exploitation. + + */ + +#include +#include + +#define u8 unsigned char /* 8 bits */ +#define u32 unsigned long /* 32 bits */ +#define u64 unsigned long long + +/* rotates x one bit to the left */ + +#define ROTL(x) (((x)>>7)|((x)<<1)) + +/* Rotates 32-bit word left by 1, 2 or 3 byte */ + +#define ROTL8(x) (((x)<<8)|((x)>>24)) +#define ROTL16(x) (((x)<<16)|((x)>>16)) +#define ROTL24(x) (((x)<<24)|((x)>>8)) + +/* Fixed Data */ + +static u8 InCo[4] = { 0xB, 0xD, 0x9, 0xE }; /* Inverse Coefficients */ + +static u8 fbsub[256]; +static u8 rbsub[256]; +static u8 ptab[256], ltab[256]; +static u32 ftable[256]; +static u32 rtable[256]; +static u32 rco[30]; + +/* Parameter-dependent data */ + +int Nk, Nb, Nr; +u8 fi[24], ri[24]; +u32 fkey[120]; +u32 rkey[120]; + +static inline u32 pack(u8 *b) +{ /* pack bytes into a 32-bit Word */ + return ((u32 ) b[3] << 24) | ((u32 ) b[2] << 16) | ((u32 ) b[1] << 8) | (u32 ) b[0]; +} + +static inline void unpack(u32 a, u8 *b) +{ /* unpack bytes from a word */ + b[0] = (u8 ) a; + b[1] = (u8 ) (a >> 8); + b[2] = (u8 ) (a >> 16); + b[3] = (u8 ) (a >> 24); +} + +static inline u8 xtime(u8 a) +{ + u8 b; + if (a & 0x80) + b = 0x1B; + else b = 0; + a <<= 1; + a ^= b; + return a; +} + +static inline u8 bmul(u8 x, u8 y) +{ /* x.y= AntiLog(Log(x) + Log(y)) */ + if (x && y) + return ptab[(ltab[x] + ltab[y]) % 255]; + else return 0; +} + +static inline u32 SubByte(u32 a) +{ + u8 b[4]; + unpack(a, b); + b[0] = fbsub[b[0]]; + b[1] = fbsub[b[1]]; + b[2] = fbsub[b[2]]; + b[3] = fbsub[b[3]]; + return pack(b); +} + +static inline u8 product(u32 x, u32 y) +{ /* dot product of two 4-byte arrays */ + u8 xb[4], yb[4]; + unpack(x, xb); + unpack(y, yb); + return bmul(xb[0], yb[0]) ^ bmul(xb[1], yb[1]) ^ bmul(xb[2], yb[2]) ^ bmul(xb[3], yb[3]); +} + +static inline u32 InvMixCol(u32 x) +{ /* matrix Multiplication */ + u32 y, m; + u8 b[4]; + + m = pack(InCo); + b[3] = product(m, x); + m = ROTL24( m ); + b[2] = product(m, x); + m = ROTL24( m ); + b[1] = product(m, x); + m = ROTL24( m ); + b[0] = product(m, x); + y = pack(b); + return y; +} + +static inline u8 ByteSub(u8 x) +{ + u8 y = ptab[255 - ltab[x]]; /* multiplicative inverse */ + x = y; + x = ROTL( x ); + y ^= x; + x = ROTL( x ); + y ^= x; + x = ROTL( x ); + y ^= x; + x = ROTL( x ); + y ^= x; + y ^= 0x63; + return y; +} + +static inline void gentables(void) +{ /* generate tables */ + int i; + u8 y, b[4]; + + /* use 3 as primitive root to generate power and log tables */ + + ltab[0] = 0; + ptab[0] = 1; + ltab[1] = 0; + ptab[1] = 3; + ltab[3] = 1; + for (i = 2; i < 256; i++) + { + ptab[i] = ptab[i - 1] ^ xtime(ptab[i - 1]); + ltab[ptab[i]] = i; + } + + /* affine transformation:- each bit is xored with itself shifted one bit */ + + fbsub[0] = 0x63; + rbsub[0x63] = 0; + for (i = 1; i < 256; i++) + { + y = ByteSub((u8 ) i); + fbsub[i] = y; + rbsub[y] = i; + } + + for (i = 0, y = 1; i < 30; i++) + { + rco[i] = y; + y = xtime(y); + } + + /* calculate forward and reverse tables */ + for (i = 0; i < 256; i++) + { + y = fbsub[i]; + b[3] = y ^ xtime(y); + b[2] = y; + b[1] = y; + b[0] = xtime(y); + ftable[i] = pack(b); + + y = rbsub[i]; + b[3] = bmul(InCo[0], y); + b[2] = bmul(InCo[1], y); + b[1] = bmul(InCo[2], y); + b[0] = bmul(InCo[3], y); + rtable[i] = pack(b); + } +} + +static inline void gkey(int nb, int nk, char *key) +{ /* blocksize=32*nb bits. Key=32*nk bits */ + /* currently nb,bk = 4, 6 or 8 */ + /* key comes as 4*Nk bytes */ + /* Key Scheduler. Create expanded encryption key */ + int i, j, k, m, N; + int C1, C2, C3; + u32 CipherKey[8]; + + Nb = nb; + Nk = nk; + + /* Nr is number of rounds */ + if (Nb >= Nk) + Nr = 6 + Nb; + else Nr = 6 + Nk; + + C1 = 1; + if (Nb < 8) + { + C2 = 2; + C3 = 3; + } + else + { + C2 = 3; + C3 = 4; + } + + /* pre-calculate forward and reverse increments */ + for (m = j = 0; j < nb; j++, m += 3) + { + fi[m] = (j + C1) % nb; + fi[m + 1] = (j + C2) % nb; + fi[m + 2] = (j + C3) % nb; + ri[m] = (nb + j - C1) % nb; + ri[m + 1] = (nb + j - C2) % nb; + ri[m + 2] = (nb + j - C3) % nb; + } + + N = Nb * (Nr + 1); + + for (i = j = 0; i < Nk; i++, j += 4) + { + CipherKey[i] = pack((u8 *) &key[j]); + } + for (i = 0; i < Nk; i++) + fkey[i] = CipherKey[i]; + for (j = Nk, k = 0; j < N; j += Nk, k++) + { + fkey[j] = fkey[j - Nk] ^ SubByte(ROTL24( fkey[j-1] )) ^ rco[k]; + if (Nk <= 6) + { + for (i = 1; i < Nk && (i + j) < N; i++) + fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; + } + else + { + for (i = 1; i < 4 && (i + j) < N; i++) + fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; + if ((j + 4) < N) fkey[j + 4] = fkey[j + 4 - Nk] ^ SubByte(fkey[j + 3]); + for (i = 5; i < Nk && (i + j) < N; i++) + fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; + } + + } + + /* now for the expanded decrypt key in reverse order */ + + for (j = 0; j < Nb; j++) + rkey[j + N - Nb] = fkey[j]; + for (i = Nb; i < N - Nb; i += Nb) + { + k = N - Nb - i; + for (j = 0; j < Nb; j++) + rkey[k + j] = InvMixCol(fkey[i + j]); + } + for (j = N - Nb; j < N; j++) + rkey[j - N + Nb] = fkey[j]; +} + +/* There is an obvious time/space trade-off possible here. * + * Instead of just one ftable[], I could have 4, the other * + * 3 pre-rotated to save the ROTL8, ROTL16 and ROTL24 overhead */ + +static inline void encrypt(char *buff) +{ + int i, j, k, m; + u32 a[8], b[8], *x, *y, *t; + + for (i = j = 0; i < Nb; i++, j += 4) + { + a[i] = pack((u8 *) &buff[j]); + a[i] ^= fkey[i]; + } + k = Nb; + x = a; + y = b; + + /* State alternates between a and b */ + for (i = 1; i < Nr; i++) + { /* Nr is number of rounds. May be odd. */ + + /* if Nb is fixed - unroll this next + loop and hard-code in the values of fi[] */ + + for (m = j = 0; j < Nb; j++, m += 3) + { /* deal with each 32-bit element of the State */ + /* This is the time-critical bit */ + y[j] = fkey[k++] ^ ftable[(u8 ) x[j]] ^ ROTL8( ftable[( u8 )( x[fi[m]] >> 8 )] ) + ^ ROTL16( ftable[( u8 )( x[fi[m+1]] >> 16 )] ) ^ ROTL24( ftable[x[fi[m+2]] >> 24] ); + } + t = x; + x = y; + y = t; /* swap pointers */ + } + + /* Last Round - unroll if possible */ + for (m = j = 0; j < Nb; j++, m += 3) + { + y[j] = fkey[k++] ^ (u32 ) fbsub[(u8 ) x[j]] ^ ROTL8( ( u32 )fbsub[( u8 )( x[fi[m]] >> 8 )] ) + ^ ROTL16( ( u32 )fbsub[( u8 )( x[fi[m+1]] >> 16 )] ) ^ ROTL24( ( u32 )fbsub[x[fi[m+2]] >> 24] ); + } + for (i = j = 0; i < Nb; i++, j += 4) + { + unpack(y[i], (u8 *) &buff[j]); + x[i] = y[i] = 0; /* clean up stack */ + } + return; +} + +static inline void decrypt(char *buff) +{ + int i, j, k, m; + u32 a[8], b[8], *x, *y, *t; + + for (i = j = 0; i < Nb; i++, j += 4) + { + a[i] = pack((u8 *) &buff[j]); + a[i] ^= rkey[i]; + } + k = Nb; + x = a; + y = b; + + /* State alternates between a and b */ + for (i = 1; i < Nr; i++) + { /* Nr is number of rounds. May be odd. */ + + /* if Nb is fixed - unroll this next + loop and hard-code in the values of ri[] */ + + for (m = j = 0; j < Nb; j++, m += 3) + { /* This is the time-critical bit */ + y[j] = rkey[k++] ^ rtable[(u8 ) x[j]] ^ ROTL8( rtable[( u8 )( x[ri[m]] >> 8 )] ) + ^ ROTL16( rtable[( u8 )( x[ri[m+1]] >> 16 )] ) ^ ROTL24( rtable[x[ri[m+2]] >> 24] ); + } + t = x; + x = y; + y = t; /* swap pointers */ + } + + /* Last Round - unroll if possible */ + for (m = j = 0; j < Nb; j++, m += 3) + { + y[j] = rkey[k++] ^ (u32 ) rbsub[(u8 ) x[j]] ^ ROTL8( ( u32 )rbsub[( u8 )( x[ri[m]] >> 8 )] ) + ^ ROTL16( ( u32 )rbsub[( u8 )( x[ri[m+1]] >> 16 )] ) ^ ROTL24( ( u32 )rbsub[x[ri[m+2]] >> 24] ); + } + for (i = j = 0; i < Nb; i++, j += 4) + { + unpack(y[i], (u8 *) &buff[j]); + x[i] = y[i] = 0; /* clean up stack */ + } + return; +} + +void aes_set_key(u8 *key) +{ + gentables(); + gkey(4, 4, (char*) key); +} + +// CBC mode decryption +void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) +{ + u8 block[16]; + unsigned int blockno = 0, i; + + //printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); + + for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) + { + unsigned int fraction; + if (blockno == (len / sizeof(block))) // last block + { + fraction = len % sizeof(block); + if (fraction == 0) break; + memset(block, 0, sizeof(block)); + } + else fraction = 16; + + // debug_printf("block %d: fraction = %d\n", blockno, fraction); + memcpy(block, inbuf + blockno * sizeof(block), fraction); + decrypt((char*) block); + u8 *ctext_ptr; + if (blockno == 0) + ctext_ptr = iv; + else ctext_ptr = inbuf + (blockno - 1) * sizeof(block); + + for (i = 0; i < fraction; i++) + outbuf[blockno * sizeof(block) + i] = ctext_ptr[i] ^ block[i]; + // debug_printf("Block %d output: ", blockno); + // hexdump(outbuf + blockno*sizeof(block), 16); + } +} + +// CBC mode encryption +void aes_encrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) +{ + u8 block[16]; + unsigned int blockno = 0, i; + + // debug_printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); + + for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) + { + unsigned int fraction; + if (blockno == (len / sizeof(block))) // last block + { + fraction = len % sizeof(block); + if (fraction == 0) break; + memset(block, 0, sizeof(block)); + } + else fraction = 16; + + // debug_printf("block %d: fraction = %d\n", blockno, fraction); + memcpy(block, inbuf + blockno * sizeof(block), fraction); + + for (i = 0; i < fraction; i++) + block[i] = inbuf[blockno * sizeof(block) + i] ^ iv[i]; + + encrypt((char*) block); + memcpy(iv, block, sizeof(block)); + memcpy(outbuf + blockno * sizeof(block), block, sizeof(block)); + // debug_printf("Block %d output: ", blockno); + // hexdump(outbuf + blockno*sizeof(block), 16); + } +} + diff --git a/source/libs/libwbfs/wiidisc.c b/source/libs/libwbfs/wiidisc.c new file mode 100644 index 0000000..4e2dc8c --- /dev/null +++ b/source/libs/libwbfs/wiidisc.c @@ -0,0 +1,367 @@ +// Copyright 2009 Kwiirk based on negentig.c: +// Copyright 2007,2008 Segher Boessenkool +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "wiidisc.h" + +void aes_set_key(u8 *key); +void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len); + +void _decrypt_title_key(u8 *tik, u8 *title_key) +{ + u8 common_key[16] = { 0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4, 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7 }; + u8 korean_key[16]={ 0x63, 0xb8, 0x2b, 0xb4, 0xf4, 0x61, 0x4e, 0x2e, 0x13, 0xf2, 0xfe, 0xfb, 0xba, 0x4c, 0x9b, 0x7e }; //korean common key + u8 iv[16]; + + wbfs_memset( iv, 0, sizeof iv ); + wbfs_memcpy( iv, tik + 0x01dc, 8 ); + + //check byte 0x1f1 in ticket to determine whether or not to use Korean Common Key. + //if value = 0x01, use Korean Common Key, else just use regular one -dmm + //Also check the GameID region code as some channels are using wrong ticket with 0x01 -Cyan + if(tik[0x01f1] == 0x01 && (tik[0x01e3] == 'K' || tik[0x01e3] == 'Q' || tik[0x01e3] == 'T')){ + aes_set_key(korean_key); + } else { + aes_set_key(common_key); + } + + aes_decrypt(iv, tik + 0x01bf, title_key, 16); +} + +static void disc_read(wiidisc_t *d, u32 offset, u8 *data, u32 len) +{ + if (data) + { + int ret = 0; + if (len == 0) return; + ret = d->read(d->fp, offset, len, data); + if (ret) + wbfs_fatal( "error reading disc" ); + } + if (d->sector_usage_table) + { + u32 blockno = offset >> 13; + do + { + d->sector_usage_table[blockno] = 1; + blockno += 1; + if (len > 0x8000) len -= 0x8000; + } while (len > 0x8000); + } +} + +static void partition_raw_read(wiidisc_t *d, u32 offset, u8 *data, u32 len) +{ + disc_read(d, d->partition_raw_offset + offset, data, len); +} + +static void partition_read_block(wiidisc_t *d, u32 blockno, u8 *block) +{ + u8*raw = d->tmp_buffer; + u8 iv[16]; + u32 offset; + if (d->sector_usage_table) d->sector_usage_table[d->partition_block + blockno] = 1; + offset = d->partition_data_offset + ((0x8000 >> 2) * blockno); + partition_raw_read(d, offset, raw, 0x8000); + + // decrypt data + memcpy(iv, raw + 0x3d0, 16); + aes_set_key(d->disc_key); + aes_decrypt(iv, raw + 0x400, block, 0x7c00); +} + +static void partition_read(wiidisc_t *d, u32 offset, u8 *data, u32 len, int fake) +{ + u8 *block = d->tmp_buffer2; + u32 offset_in_block; + u32 len_in_block; + if (fake && d->sector_usage_table == 0) return; + + while (len) + { + offset_in_block = offset % (0x7c00 >> 2); + len_in_block = 0x7c00 - (offset_in_block << 2); + if (len_in_block > len) len_in_block = len; + if (!fake) + { + partition_read_block(d, offset / (0x7c00 >> 2), block); + wbfs_memcpy( data, block + ( offset_in_block << 2 ), len_in_block ); + } + else d->sector_usage_table[d->partition_block + (offset / (0x7c00 >> 2))] = 1; + data += len_in_block; + offset += len_in_block >> 2; + len -= len_in_block; + } +} + +static u32 do_fst(wiidisc_t *d, u8 *fst, const char *names, u32 i) +{ + u32 offset; + u32 size; + const char *name; + u32 j; + + name = names + (wbfs_be32(fst + 12 * i) & 0x00ffffff); + size = wbfs_be32(fst + 12 * i + 8); + + if (i == 0) + { + for (j = 1; j < size && !d->extracted_buffer;) + { + j = do_fst(d, fst, names, j); + } + return size; + } + //printf("name %s\n",name); + + if (fst[12 * i]) + { + + for (j = i + 1; j < size && !d->extracted_buffer;) + j = do_fst(d, fst, names, j); + + return size; + } + else + { + offset = wbfs_be32(fst + 12 * i + 4); + + if (d->extract_pathname && strcasecmp(name, d->extract_pathname) == 0) + { + d->extracted_buffer = wbfs_ioalloc( size ); + d->extracted_size = size; + partition_read(d, offset, d->extracted_buffer, size, 0); + } + else partition_read(d, offset, 0, size, 1); + return i + 1; + } +} + +static void do_files(wiidisc_t*d) +{ + u8 *b = wbfs_ioalloc( 0x480 ); // XXX: determine actual header size + u32 dol_offset; + u32 fst_offset; + u32 fst_size; + u32 apl_offset; + u32 apl_size; + u8 *apl_header = wbfs_ioalloc( 0x20 ); + u8 *fst; + u32 n_files; + partition_read(d, 0, b, 0x480, 0); + + dol_offset = wbfs_be32(b + 0x0420); + fst_offset = wbfs_be32(b + 0x0424); + fst_size = wbfs_be32(b + 0x0428) << 2; + + apl_offset = 0x2440 >> 2; + partition_read(d, apl_offset, apl_header, 0x20, 0); + apl_size = 0x20 + wbfs_be32(apl_header + 0x14) + wbfs_be32(apl_header + 0x18); + // fake read dol and partition + if (apl_size) partition_read(d, apl_offset, 0, apl_size, 1); + partition_read(d, dol_offset, 0, (fst_offset - dol_offset) << 2, 1); + + if (fst_size) + { + fst = wbfs_ioalloc( fst_size ); + if (fst == 0) + wbfs_fatal( "malloc fst" ); + partition_read(d, fst_offset, fst, fst_size, 0); + n_files = wbfs_be32(fst + 8); + + + if (d->extract_pathname && strcmp(d->extract_pathname, "FST") == 0) + { + // if empty pathname requested return fst + d->extracted_buffer = fst; + d->extracted_size = fst_size; + d->extract_pathname = NULL; + // skip do_fst if only fst requested + n_files = 0; + } + + if (12 * n_files <= fst_size) + { + if (n_files > 1) do_fst(d, fst, (char *) fst + 12 * n_files, 0); + } + + if (fst != d->extracted_buffer) wbfs_iofree( fst ); + } + wbfs_iofree( b ); + wbfs_iofree( apl_header ); +} + +static void do_partition(wiidisc_t*d) +{ + u8 *tik = wbfs_ioalloc( 0x2a4 ); + u8 *b = wbfs_ioalloc( 0x1c ); + u64 tmd_offset; + u32 tmd_size; + u8 *tmd; + u64 cert_offset; + u32 cert_size; + u8 *cert; + u64 h3_offset; + + // read ticket, and read some offsets and sizes + partition_raw_read(d, 0, tik, 0x2a4); + partition_raw_read(d, 0x2a4 >> 2, b, 0x1c); + + tmd_size = wbfs_be32(b); + tmd_offset = wbfs_be32(b + 4); + cert_size = wbfs_be32(b + 8); + cert_offset = wbfs_be32(b + 0x0c); + h3_offset = wbfs_be32(b + 0x10); + d->partition_data_offset = wbfs_be32(b + 0x14); + d->partition_block = (d->partition_raw_offset + d->partition_data_offset) >> 13; + tmd = wbfs_ioalloc( tmd_size ); + if (tmd == 0) + wbfs_fatal( "malloc tmd" ); + partition_raw_read(d, tmd_offset, tmd, tmd_size); + + if(d->extract_pathname && strcmp(d->extract_pathname, "TMD") == 0 && !d->extracted_buffer) + { + d->extracted_buffer = tmd; + d->extracted_size = tmd_size; + } + + cert = wbfs_ioalloc( cert_size ); + if (cert == 0) + wbfs_fatal( "malloc cert" ); + partition_raw_read(d, cert_offset, cert, cert_size); + + _decrypt_title_key(tik, d->disc_key); + + partition_raw_read(d, h3_offset, 0, 0x18000); + + wbfs_iofree( b ); + wbfs_iofree( tik ); + wbfs_iofree( cert ); + if(tmd != d->extracted_buffer) + wbfs_iofree( tmd ); + + do_files(d); + +} +static int test_parition_skip(u32 partition_type, partition_selector_t part_sel) +{ + switch (part_sel) + { + case ALL_PARTITIONS: + return 0; + case REMOVE_UPDATE_PARTITION: + return (partition_type == 1); + case ONLY_GAME_PARTITION: + return (partition_type != 0); + default: + return (partition_type != part_sel); + } +} +static void do_disc(wiidisc_t*d) +{ + u8 *b = wbfs_ioalloc( 0x100 ); + u64 partition_offset[32]; // XXX: don't know the real maximum + u64 partition_type[32]; // XXX: don't know the real maximum + u32 n_partitions; + u32 magic; + u32 i; + disc_read(d, 0, b, 0x100); + magic = wbfs_be32(b + 24); + if (magic != 0x5D1C9EA3) + { + wbfs_iofree( b ); + wbfs_error( "not a wii disc" ); + return; + } + disc_read(d, 0x40000 >> 2, b, 0x100); + n_partitions = wbfs_be32(b); + disc_read(d, wbfs_be32(b + 4), b, 0x100); + for (i = 0; i < n_partitions; i++) + { + partition_offset[i] = wbfs_be32(b + 8 * i); + partition_type[i] = wbfs_be32(b + 8 * i + 4); + } + for (i = 0; i < n_partitions; i++) + { + d->partition_raw_offset = partition_offset[i]; + if (!test_parition_skip(partition_type[i], d->part_sel)) do_partition(d); + } + wbfs_iofree( b ); +} + +wiidisc_t *wd_open_disc(read_wiidisc_callback_t read, void*fp) +{ + wiidisc_t *d = wbfs_malloc( sizeof( wiidisc_t ) ); + if (!d) return 0; + wbfs_memset( d, 0, sizeof( wiidisc_t ) ); + d->read = read; + d->fp = fp; + d->part_sel = ALL_PARTITIONS; + d->tmp_buffer = wbfs_ioalloc( 0x8000 ); + d->tmp_buffer2 = wbfs_malloc( 0x8000 ); + + return d; +} +void wd_close_disc(wiidisc_t *d) +{ + wbfs_iofree( d->tmp_buffer ); + wbfs_free( d->tmp_buffer2 ); + wbfs_free( d ); +} +// returns a buffer allocated with wbfs_ioalloc() or NULL if not found of alloc error +// XXX pathname not implemented. files are extracted by their name. +// first file found with that name is returned. +u8 * wd_extract_file(wiidisc_t *d, partition_selector_t partition_type, char *pathname) +{ + u8 *retval = 0; + d->extract_pathname = pathname; + d->extracted_buffer = 0; + d->part_sel = partition_type; + do_disc(d); + d->extract_pathname = 0; + d->part_sel = ALL_PARTITIONS; + retval = d->extracted_buffer; + return retval; +} + +void wd_build_disc_usage(wiidisc_t *d, partition_selector_t selector, u8* usage_table) +{ + d->sector_usage_table = usage_table; + wbfs_memset( usage_table, 0, 143432*2 ); + d->part_sel = selector; + do_disc(d); + d->part_sel = ALL_PARTITIONS; + d->sector_usage_table = 0; +} + +void wd_fix_partition_table(wiidisc_t *d, partition_selector_t selector, u8* partition_table) +{ + u8 *b = partition_table; + u32 partition_offset; + u32 partition_type; + u32 n_partitions, i, j; + u32 *b32; + if (selector == ALL_PARTITIONS) return; + n_partitions = wbfs_be32(b); + if (wbfs_be32(b + 4) - (0x40000 >> 2) > 0x50) + wbfs_fatal( "cannot modify this partition table. Please report the bug." ); + + b += (wbfs_be32(b + 4) - (0x40000 >> 2)) * 4; + j = 0; + for (i = 0; i < n_partitions; i++) + { + partition_offset = wbfs_be32(b + 8 * i); + partition_type = wbfs_be32(b + 8 * i + 4); + if (!test_parition_skip(partition_type, selector)) + { + b32 = (u32*) (b + 8 * j); + b32[0] = wbfs_htonl( partition_offset ); + b32[1] = wbfs_htonl( partition_type ); + j++; + } + } + b32 = (u32*) (partition_table); + *b32 = wbfs_htonl( j ); +} + diff --git a/source/libs/libwbfs/wiidisc.h b/source/libs/libwbfs/wiidisc.h new file mode 100644 index 0000000..8183970 --- /dev/null +++ b/source/libs/libwbfs/wiidisc.h @@ -0,0 +1,67 @@ +#ifndef WIIDISC_H +#define WIIDISC_H +#include +#include "libwbfs_os.h" // this file is provided by the project wanting to compile libwbfs and wiidisc +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ +#if 0 //removes extra automatic indentation by editors +} +#endif + // callback definition. Return 1 on fatal error (callback is supposed to make retries until no hopes..) + // offset points 32bit words, count counts bytes + typedef s32 (*read_wiidisc_callback_t)(void*fp, u32 offset, u32 count, void*iobuf); + + typedef enum + { + UPDATE_PARTITION_TYPE = 0, GAME_PARTITION_TYPE, OTHER_PARTITION_TYPE, + // value in between selects partition types of that value + ALL_PARTITIONS = 0xffffffff - 3, + REMOVE_UPDATE_PARTITION, // keeps game + channel installers + ONLY_GAME_PARTITION, + } partition_selector_t; + + typedef struct wiidisc_s + { + read_wiidisc_callback_t read; + void *fp; + u8 *sector_usage_table; + + // everything points 32bit words. + u32 disc_raw_offset; + u32 partition_raw_offset; + u32 partition_data_offset; + u32 partition_data_size; + u32 partition_block; + + u8 *tmp_buffer; + u8 *tmp_buffer2; + u8 disc_key[16]; + int dont_decrypt; + + partition_selector_t part_sel; + + char *extract_pathname; + u8 *extracted_buffer; + int extracted_size; + } wiidisc_t; + + wiidisc_t *wd_open_disc(read_wiidisc_callback_t read, void*fp); + void wd_close_disc(wiidisc_t *); + // returns a buffer allocated with wbfs_ioalloc() or NULL if not found of alloc error + u8 * wd_extract_file(wiidisc_t *d, partition_selector_t partition_type, char *pathname); + + void wd_build_disc_usage(wiidisc_t *d, partition_selector_t selector, u8* usage_table); + + // effectively remove not copied partition from the partition table. + void wd_fix_partition_table(wiidisc_t *d, partition_selector_t selector, u8* partition_table); + +#if 0 +{ +#endif +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/source/lstub.cpp b/source/lstub.cpp new file mode 100644 index 0000000..459975b --- /dev/null +++ b/source/lstub.cpp @@ -0,0 +1,102 @@ +//functions for manipulating the HBC stub by giantpune + +#include +#include +#include +#include + +#include "lstub.h" +#include "gecko.h" + +#include "wad/nandtitle.h" + +extern const u8 stub_bin[]; +extern const u32 stub_bin_size; + +static char* determineStubTIDLocation() +{ + u32 *stubID = (u32*) 0x80001818; + + //HBC stub 1.0.6 and lower, and stub.bin + if (stubID[0] == 0x480004c1 && stubID[1] == 0x480004f5) + return (char *) 0x800024C6; + + //HBC stub changed @ version 1.0.7. this file was last updated for HBC 1.0.8 + else if (stubID[0] == 0x48000859 && stubID[1] == 0x4800088d) return (char *) 0x8000286A; + + //hexdump( stubID, 0x20 ); + return NULL; + +} + +s32 Set_Stub(u64 reqID) +{ + if (NandTitles.IndexOf(reqID) < 0) return WII_EINSTALL; + + char *stub = determineStubTIDLocation(); + if (!stub) return -68; + + stub[0] = TITLE_7( reqID ); + stub[1] = TITLE_6( reqID ); + stub[8] = TITLE_5( reqID ); + stub[9] = TITLE_4( reqID ); + stub[4] = TITLE_3( reqID ); + stub[5] = TITLE_2( reqID ); + stub[12] = TITLE_1( reqID ); + stub[13] = ((u8) (reqID)); + + DCFlushRange(stub, 0x10); + + return 1; + +} + +s32 Set_Stub_Split(u32 type, const char* reqID) +{ + const u32 lower = ((u32)reqID[0] << 24) | + ((u32)reqID[1] << 16) | + ((u32)reqID[2] << 8) | + ((u32)reqID[3]); + + u64 reqID64 = TITLE_ID( type, lower ); + return Set_Stub(reqID64); + +} + +void loadStub() +{ + char *stubLoc = (char *) 0x80001800; + memcpy(stubLoc, stub_bin, stub_bin_size); + DCFlushRange(stubLoc, stub_bin_size); +} + +u64 getStubDest() +{ + if (!hbcStubAvailable()) return 0; + + char ret[8]; + u64 retu = 0; + + char *stub = determineStubTIDLocation(); + if (!stub) return 0; + + ret[0] = stub[0]; + ret[1] = stub[1]; + ret[2] = stub[8]; + ret[3] = stub[9]; + ret[4] = stub[4]; + ret[5] = stub[5]; + ret[6] = stub[12]; + ret[7] = stub[13]; + + memcpy(&retu, ret, 8); + + return retu; +} + +u8 hbcStubAvailable() +{ + char * sig = (char *) 0x80001804; + return (strncmp(sig, "STUBHAXX", 8) == 0); +} + diff --git a/source/lstub.h b/source/lstub.h new file mode 100644 index 0000000..978d563 --- /dev/null +++ b/source/lstub.h @@ -0,0 +1,29 @@ +//small group of functions to manipulate the HBC stub +//brought to you by giantpune + +#ifndef _LSTUB_H_ +#define _LSTUB_H_ + +//to set the "return to" stub for a certain ID +//!reqID is the Requested ID to return to +//!returns WII_EINTERNAL if it cant get the list of installed titles with ES functions +//!retuns -69 if the ID is not installed +//!1 if successful +s32 Set_Stub(u64 reqID); + +//!same as the above function, but expects a type and 4 char channel ID +s32 Set_Stub_Split(u32 type, const char* reqID); + +//load the default HBC stub into memory. as long as nothing writes to the 0x80001800 +// +0xDC7 memory block it will stay there. by default it has 0x00010001/JODI. +void loadStub(); + +//get whatever ID the stub is set to load +//!returns 0 if no stub is loaded into memory (must be the HBC stub at 0x800018000) +//!otherwise returns the ID set to return to +u64 getStubDest(); + +//returns 0 or 1 depending on wether the stub is available +u8 hbcStubAvailable(); + +#endif diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..312abb2 --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** + * USB Loader GX Team + * + * Main loadup of the application + * + * libwiigui + * Tantric 2009 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "video.h" +#include "menu/menus.h" +#include "memory/mem2.h" +#include "wad/nandtitle.h" +#include "StartUpProcess.h" +#include "sys.h" + +extern "C" +{ + extern s32 MagicPatches(s32); + void __exception_setreload(int t); +} + +int main(int argc, char *argv[]) +{ + __exception_setreload(20); + // activate magic access rights + MagicPatches(1); + // init video + InitVideo(); + // video frame buffers must be in mem1 + MEM2_init(48); + // init gecko + InitGecko(); + // redirect stdout and stderr to gecko + USBGeckoOutput(); + NandTitles.Get(); + setlocale(LC_ALL, "en.UTF-8"); + + if(StartUpProcess::Run(argc, argv) < 0) + return -1; + + MainMenu(MENU_DISCLIST); + return 0; +} diff --git a/source/main.h b/source/main.h new file mode 100644 index 0000000..f545ca6 --- /dev/null +++ b/source/main.h @@ -0,0 +1,16 @@ +/**************************************************************************** + * libwiigui Template + * Tantric 2009 + * + * demo.h + ***************************************************************************/ + +#ifndef _MAIN_H_ +#define _MAIN_H_ + +#include "FreeTypeGX.h" + +void DefaultSettings(); +extern FreeTypeGX *fontSystem; + +#endif diff --git a/source/memory/mem2.cpp b/source/memory/mem2.cpp new file mode 100644 index 0000000..8f4cfa5 --- /dev/null +++ b/source/memory/mem2.cpp @@ -0,0 +1,214 @@ + +#include "mem2.h" +#include "mem2alloc.hpp" + +#include +#include +#include + +#define MAX_MEM1_ARENA_LO ((void *) (0x81700000-size)) +#define MEM2_PRIORITY_SIZE 30720 // 30KB + +// Forbid the use of MEM2 through malloc +u32 MALLOC_MEM2 = 0; + +static CMEM2Alloc g_mem2gp; + +static bool g_bigGoesToMem2 = true; + +extern "C" +{ + +extern __typeof(malloc) __real_malloc; +extern __typeof(calloc) __real_calloc; +extern __typeof(realloc) __real_realloc; +extern __typeof(memalign) __real_memalign; +extern __typeof(free) __real_free; +extern __typeof(malloc_usable_size) __real_malloc_usable_size; + + +void MEM2_takeBigOnes(bool b) +{ + g_bigGoesToMem2 = b; +} + +void MEM2_init(unsigned int mem2Size) +{ + g_mem2gp.init(mem2Size); +} + +void MEM2_cleanup(void) +{ + g_mem2gp.cleanup(); +} + +void *MEM2_alloc(unsigned int s) +{ + return g_mem2gp.allocate(s); +} + +void MEM2_free(void *p) +{ + g_mem2gp.release(p); +} + +void *MEM2_realloc(void *p, unsigned int s) +{ + return g_mem2gp.reallocate(p, s); +} + +unsigned int MEM2_usableSize(void *p) +{ + return CMEM2Alloc::usableSize(p); +} + +unsigned int MEM2_freesize() +{ + return g_mem2gp.FreeSize(); +} + +void *MEM1_alloc(unsigned int s) +{ + return __real_malloc(s); +} + +void *MEM1_memalign(unsigned int a, unsigned int s) +{ + return __real_memalign(a, s); +} + +void MEM1_free(void *p) +{ + __real_free(p); +} + +void *MEM1_realloc(void *p, unsigned int s) +{ + return __real_realloc(p, s); +} + +void *__wrap_malloc(size_t size) +{ + void *p; + if ((SYS_GetArena1Lo() > MAX_MEM1_ARENA_LO) || (g_bigGoesToMem2 && size > MEM2_PRIORITY_SIZE)) + { + p = g_mem2gp.allocate(size); + if (p != 0) { + return p; + } + return __real_malloc(size); + } + p = __real_malloc(size); + if (p != 0) { + return p; + } + return g_mem2gp.allocate(size); +} + +void *__wrap_calloc(size_t n, size_t size) +{ + void *p; + if ((SYS_GetArena1Lo() > MAX_MEM1_ARENA_LO) || (g_bigGoesToMem2 && size > MEM2_PRIORITY_SIZE)) + { + p = g_mem2gp.allocate(n * size); + if (p != 0) + { + memset(p, 0, n * size); + return p; + } + return __real_calloc(n, size); + } + p = __real_calloc(n, size); + if (p != 0) { + return p; + } + p = g_mem2gp.allocate(n * size); + if (p != 0) { + memset(p, 0, n * size); + } + return p; +} + +void *__wrap_memalign(size_t a, size_t size) +{ + void *p; + if ((SYS_GetArena1Lo() > MAX_MEM1_ARENA_LO) || (g_bigGoesToMem2 && size > MEM2_PRIORITY_SIZE)) + { + if (a <= 32 && 32 % a == 0) + { + p = g_mem2gp.allocate(size); + if (p != 0) { + return p; + } + } + return __real_memalign(a, size); + } + p = __real_memalign(a, size); + if (p != 0 || a > 32 || 32 % a != 0) { + return p; + } + + return g_mem2gp.allocate(size); +} + +void __wrap_free(void *p) +{ + if(!p) + return; + + if (((u32)p & 0x10000000) != 0) + { + g_mem2gp.release(p); + } + else + { + __real_free(p); + } +} + +void *__wrap_realloc(void *p, size_t size) +{ + void *n; + // ptr from mem2 + if (((u32)p & 0x10000000) != 0 || (p == 0 && g_bigGoesToMem2 && size > MEM2_PRIORITY_SIZE)) + { + n = g_mem2gp.reallocate(p, size); + if (n != 0) { + return n; + } + n = __real_malloc(size); + if (n == 0) { + return 0; + } + if (p != 0) + { + memcpy(n, p, MEM2_usableSize(p) < size ? MEM2_usableSize(p) : size); + g_mem2gp.release(p); + } + return n; + } + // ptr from malloc + n = __real_realloc(p, size); + if (n != 0) { + return n; + } + n = g_mem2gp.allocate(size); + if (n == 0) { + return 0; + } + if (p != 0) + { + memcpy(n, p, __real_malloc_usable_size(p) < size ? __real_malloc_usable_size(p) : size); + __real_free(p); + } + return n; +} + +size_t __wrap_malloc_usable_size(void *p) +{ + if (((u32)p & 0x10000000) != 0) + return CMEM2Alloc::usableSize(p); + return __real_malloc_usable_size(p); +} + +} ///extern "C" diff --git a/source/memory/mem2.h b/source/memory/mem2.h new file mode 100644 index 0000000..9e0b848 --- /dev/null +++ b/source/memory/mem2.h @@ -0,0 +1,31 @@ +// 2 MEM2 allocators, one for general purpose, one for covers +// Aligned and padded to 32 bytes, as required by many functions + +#ifndef __MEM2_H_ +#define __MEM2_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define isMEM2Buffer(p) (((u32) p & 0x10000000) != 0) + +void *MEM1_alloc(unsigned int s); +void *MEM1_memalign(unsigned int a, unsigned int s); +void *MEM1_realloc(void *p, unsigned int s); +void MEM1_free(void *p); + +void MEM2_init(unsigned int mem2Size); +void MEM2_cleanup(void); +void MEM2_takeBigOnes(bool b); +void *MEM2_alloc(unsigned int s); +void *MEM2_realloc(void *p, unsigned int s); +void MEM2_free(void *p); +unsigned int MEM2_usableSize(void *p); +unsigned int MEM2_freesize(); + +#ifdef __cplusplus +} +#endif + +#endif // !defined(__MEM2_H_) diff --git a/source/memory/mem2alloc.cpp b/source/memory/mem2alloc.cpp new file mode 100644 index 0000000..1f025dd --- /dev/null +++ b/source/memory/mem2alloc.cpp @@ -0,0 +1,238 @@ +#include "mem2alloc.hpp" + +#include +#include +#include + +#define IOS_RELOAD_AREA 0x90200000 + +class LockMutex +{ + mutex_t &m_mutex; +public: + LockMutex(mutex_t &m) : m_mutex(m) { LWP_MutexLock(m_mutex); } + ~LockMutex(void) { LWP_MutexUnlock(m_mutex); } +}; + +void CMEM2Alloc::init(unsigned int size) +{ + m_baseAddress = (SBlock *) std::max(((u32)SYS_GetArena2Lo() + 31) & ~31, (u32)IOS_RELOAD_AREA); + m_endAddress = (SBlock *) ((char *)m_baseAddress + std::min((u32)(size * 0x100000), SYS_GetArena2Size() & ~31)); + if (m_endAddress > (SBlock *) 0x93300000) //rest is reserved for usb/usb2/network and other stuff... (0xE0000 bytes) + m_endAddress = (SBlock *) 0x93300000; + SYS_SetArena2Lo(m_endAddress); + LWP_MutexInit(&m_mutex, 0); +} + +void CMEM2Alloc::init(void *addr, void *end) +{ + m_baseAddress = (SBlock *)(((u32)addr + 31) & ~31); + m_endAddress = (SBlock *)((u32)end & ~31); + LWP_MutexInit(&m_mutex, 0); +} + +void CMEM2Alloc::cleanup(void) +{ + LWP_MutexDestroy(m_mutex); + m_mutex = 0; + m_first = 0; + // Try to release the range we took through SYS functions + if (SYS_GetArena2Lo() == m_endAddress) + SYS_SetArena2Lo(m_baseAddress); + m_baseAddress = 0; + m_endAddress = 0; +} + +void CMEM2Alloc::clear(void) +{ + m_first = 0; + memset(m_baseAddress, 0, (u8 *)m_endAddress - (u8 *)m_endAddress); +} + +unsigned int CMEM2Alloc::usableSize(void *p) +{ + return p == 0 ? 0 : ((SBlock *)p - 1)->s * sizeof (SBlock); +} + +void *CMEM2Alloc::allocate(unsigned int s) +{ + if (s == 0) + s = 1; + // + LockMutex lock(m_mutex); + // + s = (s - 1) / sizeof (SBlock) + 1; + // First block + if (m_first == 0) + { + if (m_baseAddress + s + 1 >= m_endAddress) + return 0; + m_first = m_baseAddress; + m_first->next = 0; + m_first->prev = 0; + m_first->s = s; + m_first->f = false; + return (void *)(m_first + 1); + } + // Search for a free block + SBlock *i; + SBlock *j; + for (i = m_first; i != 0; i = i->next) + { + if (i->f && i->s >= s) + break; + j = i; + } + // Create a new block + if (i == 0) + { + i = j + j->s + 1; + if (i + s + 1 >= m_endAddress) + return 0; + j->next = i; + i->prev = j; + i->next = 0; + i->s = s; + i->f = false; + return (void *)(i + 1); + } + // Reuse a free block + i->f = false; + // Split it + if (i->s > s + 1) + { + j = i + s + 1; + j->f = true; + j->s = i->s - s - 1; + i->s = s; + j->next = i->next; + j->prev = i; + i->next = j; + if (j->next != 0) + j->next->prev = j; + } + return (void *)(i + 1); +} + +void CMEM2Alloc::release(void *p) +{ + if (p == 0) + return; + + LockMutex lock(m_mutex); + SBlock *i = (SBlock *)p - 1; + i->f = true; + + // If there are no other blocks following yet, + // set the remaining size to free size. - Dimok + if(i->next == 0) + i->s = m_endAddress - i - 1; + + // Merge with previous block + if (i->prev != 0 && i->prev->f) + { + i = i->prev; + i->s += i->next->s + 1; + i->next = i->next->next; + if (i->next != 0) + i->next->prev = i; + } + // Merge with next block + if (i->next != 0 && i->next->f) + { + i->s += i->next->s + 1; + i->next = i->next->next; + if (i->next != 0) + i->next->prev = i; + } +} + +void *CMEM2Alloc::reallocate(void *p, unsigned int s) +{ + SBlock *i; + SBlock *j; + void *n; + + if (s == 0) + s = 1; + if (p == 0) + return allocate(s); + + i = (SBlock *)p - 1; + s = (s - 1) / sizeof (SBlock) + 1; + { + LockMutex lock(m_mutex); + + //out of memory /* Dimok */ + if (i + s + 1 >= m_endAddress) + { + return 0; + } + + // Last block + if (i->next == 0 && i + s + 1 < m_endAddress) + { + i->s = s; + return p; + } + // Size <= current size + next block + if (i->next != 0 && i->s < s && i->next->f && i->s + i->next->s + 1 >= s) + { + // Merge + i->s += i->next->s + 1; + i->next = i->next->next; + if (i->next != 0) + i->next->prev = i; + } + // Size <= current size + if (i->s >= s) + { + // Split + if (i->s > s + 1) + { + j = i + s + 1; + j->f = true; + j->s = i->s - s - 1; + i->s = s; + j->next = i->next; + j->prev = i; + i->next = j; + if (j->next != 0) + j->next->prev = j; + } + return p; + } + } + // Size > current size + n = allocate(s * sizeof (SBlock)); + if (n == 0) + return 0; + memcpy(n, p, i->s * sizeof (SBlock)); + release(p); + return n; +} + +unsigned int CMEM2Alloc::FreeSize() +{ + LockMutex lock(m_mutex); + + if (m_first == 0) + return (const char *) m_endAddress - (const char *) m_baseAddress; + + SBlock *i; + unsigned int size = 0; + + for(i = m_first; i != 0; i = i->next) + { + if(i->f && i->next != 0) + size += i->s; + + else if(i->f && i->next == 0) + size += m_endAddress - i - 1; + + else if(!i->f && i->next == 0) + size += m_endAddress - i - i->s - 1; + } + + return size*sizeof(SBlock); +} diff --git a/source/memory/mem2alloc.hpp b/source/memory/mem2alloc.hpp new file mode 100644 index 0000000..e66f524 --- /dev/null +++ b/source/memory/mem2alloc.hpp @@ -0,0 +1,42 @@ +// MEM2 allocator +// Made as a class so i can have 2 sections, one being dedicated to the covers + +#ifndef __MEM2ALLOC_HPP +#define __MEM2ALLOC_HPP + +#include + +class CMEM2Alloc +{ +public: + void *allocate(unsigned int s); + void release(void *p); + void *reallocate(void *p, unsigned int s); + void init(unsigned int size); + void init(void *addr, void *end); + void cleanup(void); + void clear(void); + static unsigned int usableSize(void *p); + void forceEndAddress(void *newAddr) { m_endAddress = (SBlock *)newAddr; } + void *getEndAddress(void) const { return m_endAddress; } + void info(void *&address, unsigned int &size) const { address = m_baseAddress; size = (const char *)m_endAddress - (const char *)m_baseAddress; } + unsigned int FreeSize(); + // + CMEM2Alloc(void) : m_baseAddress(0), m_endAddress(0), m_first(0), m_mutex(0) { } +private: + struct SBlock + { + unsigned int s; + SBlock *next; + SBlock *prev; + bool f; + } __attribute__((aligned(32))); + SBlock *m_baseAddress; + SBlock *m_endAddress; + SBlock *m_first; + mutex_t m_mutex; +private: + CMEM2Alloc(const CMEM2Alloc &); +}; + +#endif // !defined(__MEM2ALLOC_HPP) diff --git a/source/memory/memory.h b/source/memory/memory.h new file mode 100644 index 0000000..f51f2b8 --- /dev/null +++ b/source/memory/memory.h @@ -0,0 +1,37 @@ +#ifndef __MEMORY_H_ +#define __MEMORY_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define Disc_ID ((vu32*) 0x80000000) +#define Disc_Region ((vu32*) 0x80000003) +#define Disc_Magic ((vu32*) 0x80000018) +#define Sys_Magic ((vu32*) 0x80000020) +#define Sys_Version ((vu32*) 0x80000024) +#define Mem_Size ((vu32*) 0x80000028) +#define Board_Model ((vu32*) 0x8000002C) +#define Arena_L ((vu32*) 0x80000030) +#define Arena_H ((vu32*) 0x80000034) +#define FST ((vu32*) 0x80000038) +#define Max_FST ((vu32*) 0x8000003C) +#define Assembler ((vu32*) 0x80000060) +#define Video_Mode ((vu32*) 0x800000CC) +#define Dev_Debugger ((vu32*) 0x800000EC) +#define Simulated_Mem ((vu32*) 0x800000F0) +#define BI2 ((vu32*) 0x800000F4) +#define Bus_Speed ((vu32*) 0x800000F8) +#define CPU_Speed ((vu32*) 0x800000FC) +#define Online_Check ((vu32*) 0x80003180) +#define GameID_Address ((vu32*) 0x80003184) +#define HW_PPCSPEED ((vu32*) 0xCD800018) + +#define allocate_memory(size) memalign(32, (size+31)&(~31)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/menu.cpp b/source/menu.cpp new file mode 100644 index 0000000..717fccd --- /dev/null +++ b/source/menu.cpp @@ -0,0 +1,235 @@ +/**************************************************************************** + * USB Loader GX Team + * + * libwiigui Template + * by Tantric 2009 + * + * menu.cpp + * Menu flow routines - handles all menu logic + ***************************************************************************/ +#include + +#include "GUI/gui.h" +#include "homebrewboot/BootHomebrew.h" +#include "homebrewboot/HomebrewBrowser.hpp" +#include "prompts/ProgressWindow.h" +#include "menu/GameBrowseMenu.hpp" +#include "menu/menus.h" +#include "mload/mload.h" +#include "mload/mload_modules.h" +#include "network/networkops.h" +#include "patches/patchcode.h" +#include "settings/menus/GlobalSettings.hpp" +#include "settings/CGameSettings.h" +#include "themes/CTheme.h" +#include "themes/ThemeMenu.h" +#include "themes/ThemeDownloader.h" +#include "usbloader/disc.h" +#include "usbloader/GameList.h" +#include "usbloader/MountGamePartition.h" +#include "mload/mload_modules.h" +#include "audio.h" +#include "gecko.h" +#include "menu.h" +#include "sys.h" +#include "wpad.h" +#include "settings/newtitles.h" +#include "usbloader/frag.h" +#include "usbloader/wbfs.h" +#include "wad/nandtitle.h" + +/*** Variables that are also used extern ***/ +GuiWindow * mainWindow = NULL; +WiiPointer * pointer[4] = { NULL, NULL, NULL, NULL }; +GuiImage * bgImg = NULL; +GuiImageData * background = NULL; +GuiBGM * bgMusic = NULL; +GuiSound *btnSoundClick = NULL; +GuiSound *btnSoundClick2 = NULL; +GuiSound *btnSoundOver = NULL; + +static int currentMenu = 0; + +static lwp_t guithread = LWP_THREAD_NULL; +static bool guiHalt = true; +static bool ExitRequested = false; + +/**************************************************************************** + * ResumeGui + * + * Signals the GUI thread to start, and resumes the thread. This is called + * after finishing the removal/insertion of new elements, and after initial + * GUI setup. + ***************************************************************************/ +void ResumeGui() +{ + guiHalt = false; + LWP_ResumeThread(guithread); +} + +/**************************************************************************** + * HaltGui + * + * Signals the GUI thread to stop, and waits for GUI thread to stop + * This is necessary whenever removing/inserting new elements into the GUI. + * This eliminates the possibility that the GUI is in the middle of accessing + * an element that is being changed. + ***************************************************************************/ +void HaltGui() +{ + if (guiHalt) return; + guiHalt = true; + + // wait for thread to finish + while (!LWP_ThreadIsSuspended(guithread)) + usleep(100); +} + +/**************************************************************************** + * UpdateGUI + * + * Primary thread to allow GUI to respond to state changes, and draws GUI + ***************************************************************************/ +static void * UpdateGUI(void *arg) +{ + u8 i; + + while (!ExitRequested) + { + if (guiHalt) + { + LWP_SuspendThread(guithread); + continue; + } + + UpdatePads(); + + mainWindow->Draw(); + if (Settings.tooltips && Theme::ShowTooltips && mainWindow->GetState() != STATE_DISABLED) + mainWindow->DrawTooltip(); + + // Pointer modifies wpad data struct for easy implementation of "virtual pointer" with PAD-Sticks + // That is why it has to be called right before updating other gui elements with the triggers + i = 4; + while(i--) + pointer[i]->Draw(&userInput[i]); + + for (i = 0; i < 4; i++) + mainWindow->Update(&userInput[i]); + + Menu_Render(); + + if (bgMusic) bgMusic->UpdateState(); + } + + for (i = 5; i < 255; i += 10) + { + mainWindow->Draw(); + Menu_DrawRectangle(0, 0, screenwidth, screenheight, (GXColor) {0, 0, 0, i}, 1); + Menu_Render(); + } + + mainWindow->RemoveAll(); + ShutoffRumble(); + + return NULL; +} + +/**************************************************************************** + * InitGUIThread + * + * Startup GUI threads + ***************************************************************************/ +void InitGUIThreads() +{ + ExitRequested = false; + + if(guithread == LWP_THREAD_NULL) + LWP_CreateThread(&guithread, UpdateGUI, NULL, NULL, 65536, LWP_PRIO_HIGHEST); +} + +void ExitGUIThreads() +{ + ExitRequested = true; + + if(guithread != LWP_THREAD_NULL) + { + ResumeGui(); + LWP_JoinThread(guithread, NULL); + guithread = LWP_THREAD_NULL; + } +} + +/**************************************************************************** + * MainMenu + ***************************************************************************/ +int MainMenu(int menu) +{ + currentMenu = menu; + + InitGUIThreads(); + + InitProgressThread(); + InitNetworkThread(); + + if (Settings.autonetwork) + ResumeNetworkThread(); + + btnSoundClick = new GuiSound(NULL, 0, Settings.sfxvolume); + btnSoundClick->LoadSoundEffect(Resources::GetFile("button_click.wav"), Resources::GetFileSize("button_click.wav")); + btnSoundClick2 = new GuiSound(NULL, 0, Settings.sfxvolume); + btnSoundClick2->LoadSoundEffect(Resources::GetFile("button_click2.wav"), Resources::GetFileSize("button_click2.wav")); + btnSoundOver = new GuiSound(NULL, 0, Settings.sfxvolume); + btnSoundOver->LoadSoundEffect(Resources::GetFile("button_over.wav"), Resources::GetFileSize("button_over.wav")); + + pointer[0] = new WiiPointer("player1_point.png"); + pointer[1] = new WiiPointer("player2_point.png"); + pointer[2] = new WiiPointer("player3_point.png"); + pointer[3] = new WiiPointer("player4_point.png"); + + mainWindow = new GuiWindow(screenwidth, screenheight); + + background = Resources::GetImageData(Settings.widescreen ? "wbackground.png" : "background.png"); + + bgImg = new GuiImage(background); + mainWindow->Append(bgImg); + + ResumeGui(); + + bgMusic = new GuiBGM(Resources::GetFile("bg_music.ogg"), Resources::GetFileSize("bg_music.ogg"), Settings.volume); + bgMusic->SetLoop(Settings.musicloopmode); //loop music + bgMusic->Load(Settings.ogg_path); + bgMusic->Play(); + + MountGamePartition(); + + while (currentMenu != MENU_EXIT) + { + bgMusic->SetVolume(Settings.volume); + + switch (currentMenu) + { + case MENU_SETTINGS: + currentMenu = GlobalSettings::Execute(); + break; + case MENU_THEMEMENU: + currentMenu = ThemeMenu::Execute(); + break; + // case MENU_THEMEDOWNLOADER: + // currentMenu = ThemeDownloader::Execute(); + // break; + case MENU_HOMEBREWBROWSE: + currentMenu = HomebrewBrowser::Execute(); + break; + case MENU_DISCLIST: + default: // unrecognized menu + currentMenu = GameBrowseMenu::Execute(); + break; + } + } + + //! THIS SHOULD NEVER HAPPEN ANYMORE + ExitApp(); + + return -1; +} diff --git a/source/menu.h b/source/menu.h new file mode 100644 index 0000000..0a14c13 --- /dev/null +++ b/source/menu.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * libwiigui Template + * Tantric 2009 + * + * menu.h + * Menu flow routines - handles all menu logic + ***************************************************************************/ + +#ifndef _MENU_H_ +#define _MENU_H_ + +#include +#include "GUI/gui.h" +#include "Controls/WiiPointer.h" +#include "settings/CSettings.h" +#include "main.h" + +void InitGUIThreads(void); +void ExitGUIThreads(void); + +int MainMenu(int menuitem); + +enum +{ + MENU_EXIT = -1, + MENU_NONE, + MENU_SETTINGS, + MENU_DISCLIST, + MENU_GAME_SETTINGS, + MENU_HOMEBREWBROWSE, + BOOTHOMEBREW, + MENU_THEMEDOWNLOADER, + MENU_THEMEMENU, +}; + +void ResumeGui(); +void HaltGui(); + +extern WiiPointer *pointer[4]; +extern GuiImageData *background; +extern GuiImage *bgImg; +extern GuiWindow *mainWindow; +extern GuiText *GameRegionTxt; +extern GuiText *GameIDTxt; +extern GuiImageData *cover; +extern GuiImage *coverImg; +extern FreeTypeGX *fontSystem; + +#endif diff --git a/source/menu/GameBrowseMenu.cpp b/source/menu/GameBrowseMenu.cpp new file mode 100644 index 0000000..371c565 --- /dev/null +++ b/source/menu/GameBrowseMenu.cpp @@ -0,0 +1,1671 @@ +#include +#include "GameBrowseMenu.hpp" +#include "banner/BannerAsync.h" +#include "Controls/DeviceHandler.hpp" +#include "GUI/gui_gamelist.h" +#include "GUI/gui_gamegrid.h" +#include "GUI/gui_gamecarousel.h" +#include "GUI/GuiBannerGrid.h" +#include "GUI/LoadCoverImage.h" +#include "prompts/PromptWindows.h" +#include "prompts/gameinfo.h" +#include "prompts/DiscBrowser.h" +#include "prompts/GameWindow.hpp" +#include "prompts/BannerWindow.hpp" +#include "prompts/CategorySwitchPrompt.hpp" +#include "prompts/CheckboxPrompt.hpp" +#include "themes/CTheme.h" +#include "language/gettext.h" +#include "usbloader/wbfs.h" +#include "usbloader/wdvd.h" +#include "usbloader/GameList.h" +#include "network/networkops.h" +#include "network/update.h" +#include "network/ImageDownloader.h" +#include "settings/CSettings.h" +#include "settings/CGameStatistics.h" +#include "settings/CGameSettings.h" +#include "settings/GameTitles.h" +#include "SystemMenu/SystemMenuResources.h" +#include "system/IosLoader.h" +#include "utils/StringTools.h" +#include "utils/rockout.h" +#include "utils/ShowError.h" +#include "utils/tools.h" +#include "utils/PasswordCheck.h" +#include "gecko.h" +#include "menus.h" +#include "wpad.h" +#include "sys.h" + +extern bool updateavailable; + +struct discHdr *dvdheader = NULL; +static bool Exiting = false; + +GameBrowseMenu::GameBrowseMenu() + : GuiWindow(screenwidth, screenheight) +{ + returnMenu = MENU_NONE; + gameSelectedOld = -1; + lastrawtime = 0; + Exiting = false; + show_searchwindow = false; + gameBrowser = NULL; + searchBar = NULL; + gameCover = NULL; + gameCoverImg = NULL; + GameIDTxt = NULL; + GameRegionTxt = NULL; + listBackground = NULL; + carouselBackground = NULL; + gridBackground = NULL; + WDVD_GetCoverStatus(&DiscDriveCoverOld); + gameList.FilterList(); + HDDSizeCallback.SetCallback(this, &GameBrowseMenu::UpdateFreeSpace); + + btnInstall = Resources::GetImageData("button_install.png"); + btnInstallOver = Resources::GetImageData("button_install_over.png"); + btnSettings = Resources::GetImageData("settings_button.png"); + btnSettingsOver = Resources::GetImageData("settings_button_over.png"); + btnpwroff = Resources::GetImageData("wiimote_poweroff.png"); + btnpwroffOver = Resources::GetImageData("wiimote_poweroff_over.png"); + btnhome = Resources::GetImageData("menu_button.png"); + btnhomeOver = Resources::GetImageData("menu_button_over.png"); + btnsdcardOver = Resources::GetImageData("sdcard_over.png"); + btnsdcard = Resources::GetImageData("sdcard.png"); + + imgfavIcon = Resources::GetImageData("favIcon.png"); + imgfavIcon_gray = Resources::GetImageData("favIcon_gray.png"); + imgsearchIcon = Resources::GetImageData("searchIcon.png"); + imgsearchIcon_gray = Resources::GetImageData("searchIcon_gray.png"); + imgabcIcon = Resources::GetImageData("abcIcon.png"); + imgrankIcon = Resources::GetImageData("rankIcon.png"); + imgplayCountIcon = Resources::GetImageData("playCountIcon.png"); + imgplayersSortIcon = Resources::GetImageData("playersSort.png"); + imgarrangeGrid = Resources::GetImageData("arrangeGrid.png"); + imgarrangeGrid_gray = Resources::GetImageData("arrangeGrid_gray.png"); + imgarrangeList = Resources::GetImageData("arrangeList.png"); + imgarrangeList_gray = Resources::GetImageData("arrangeList_gray.png"); + imgarrangeCarousel = Resources::GetImageData("arrangeCarousel.png"); + imgarrangeCarousel_gray = Resources::GetImageData("arrangeCarousel_gray.png"); + imgBannerGrid = Resources::GetImageData("arrangeBannerGrid.png"); + imgBannerGrid_gray = Resources::GetImageData("arrangeBannerGrid_gray.png"); + imgdvd = Resources::GetImageData("dvd.png"); + imgdvd_gray = Resources::GetImageData("dvd_gray.png"); + imgLock = Resources::GetImageData("lock.png"); + imgLock_gray = Resources::GetImageData("lock_gray.png"); + imgUnlock = Resources::GetImageData("unlock.png"); + imgUnlock_gray = Resources::GetImageData("unlock_gray.png"); + imgCategory = Resources::GetImageData("category.png"); + imgCategory_gray = Resources::GetImageData("category_gray.png"); + imgLoaderMode = Resources::GetImageData("loader_mode.png"); + + homebrewImgData = Resources::GetImageData("browser.png"); + homebrewImgDataOver = Resources::GetImageData("browser_over.png"); + + trigA = new GuiTrigger; + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigHome = new GuiTrigger; + trigHome->SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, PAD_BUTTON_START); + trig2 = new GuiTrigger; + trig2->SetButtonOnlyTrigger(-1, WPAD_BUTTON_2 | WPAD_CLASSIC_BUTTON_X, PAD_BUTTON_Y); + trig1 = new GuiTrigger; + trig1->SetButtonOnlyTrigger(-1, WPAD_BUTTON_1 | WPAD_CLASSIC_BUTTON_Y, PAD_BUTTON_X); + + usedSpaceTxt = new GuiText(" ", 18, thColor("r=55 g=190 b=237 a=255 - hdd info color")); + usedSpaceTxt->SetAlignment(thAlign("center - hdd info align hor"), thAlign("top - hdd info align ver")); + usedSpaceTxt->SetPosition(thInt("0 - hdd info pos x"), thInt("400 - hdd info pos y")); + + gamecntTxt = new GuiText((char *) NULL, 18, thColor("r=55 g=190 b=237 a=255 - game count color")); + gamecntBtn = new GuiButton(100, 18); + gamecntBtn->SetAlignment(thAlign("center - game count align hor"), thAlign("top - game count align ver")); + gamecntBtn->SetPosition(thInt("0 - game count pos x"), thInt("420 - game count pos y")); + gamecntBtn->SetLabel(gamecntTxt); + gamecntBtn->SetEffectGrow(); + gamecntBtn->SetTrigger(trigA); + + installBtnTT = new GuiTooltip(tr( "Install a game" )); + if (Settings.wsprompt) installBtnTT->SetWidescreen(Settings.widescreen); + installBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + installBtnImg = new GuiImage(btnInstall); + installBtnImgOver = new GuiImage(btnInstallOver); + installBtnImg->SetWidescreen(Settings.widescreen); + installBtnImgOver->SetWidescreen(Settings.widescreen); + + installBtn = new GuiButton(installBtnImg, installBtnImgOver, ALIGN_LEFT, ALIGN_TOP, + thInt("16 - install btn pos x"), thInt("355 - install btn pos y"), + trigA, btnSoundOver, btnSoundClick2, 1, installBtnTT, 24, -30, 0, 5); + + settingsBtnTT = new GuiTooltip(tr( "Settings" )); + if (Settings.wsprompt) settingsBtnTT->SetWidescreen(Settings.widescreen); + settingsBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + settingsBtnImg = new GuiImage(btnSettings); + settingsBtnImg->SetWidescreen(Settings.widescreen); + settingsBtnImgOver = new GuiImage(btnSettingsOver); + settingsBtnImgOver->SetWidescreen(Settings.widescreen); + settingsBtn = new GuiButton(settingsBtnImg, settingsBtnImgOver, 0, 3, + thInt("64 - settings btn pos x"), thInt("371 - settings btn pos y"), + trigA, btnSoundOver, btnSoundClick2, 1, settingsBtnTT, 65, -30, 0, 5); + + homeBtnTT = new GuiTooltip(tr( "Back to HBC or Wii Menu" )); + if (Settings.wsprompt) homeBtnTT->SetWidescreen(Settings.widescreen); + homeBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + homeBtnImg = new GuiImage(btnhome); + homeBtnImg->SetWidescreen(Settings.widescreen); + homeBtnImgOver = new GuiImage(btnhomeOver); + homeBtnImgOver->SetWidescreen(Settings.widescreen); + homeBtn = new GuiButton(homeBtnImg, homeBtnImgOver, 0, 3, + thInt("489 - home menu btn pos x"), thInt("371 - home menu btn pos y"), + trigA, btnSoundOver, btnSoundClick2, 1, homeBtnTT, 15, -30, 1, 5); + homeBtn->RemoveSoundClick(); + homeBtn->SetTrigger(trigHome); + + poweroffBtnTT = new GuiTooltip(tr( "Power off the Wii" )); + if (Settings.wsprompt) poweroffBtnTT->SetWidescreen(Settings.widescreen); + poweroffBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + poweroffBtnImg = new GuiImage(btnpwroff); + poweroffBtnImgOver = new GuiImage(btnpwroffOver); + poweroffBtnImg->SetWidescreen(Settings.widescreen); + poweroffBtnImgOver->SetWidescreen(Settings.widescreen); + poweroffBtn = new GuiButton(poweroffBtnImg, poweroffBtnImgOver, 0, 3, + thInt("576 - power off btn pos x"), thInt("355 - power off btn pos y"), + trigA, btnSoundOver, btnSoundClick2, 1, poweroffBtnTT, -10, -30, 1, 5); + + sdcardBtnTT = new GuiTooltip(tr( "Reload SD" )); + if (Settings.wsprompt) sdcardBtnTT->SetWidescreen(Settings.widescreen); + sdcardBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + sdcardImg = new GuiImage(btnsdcard); + sdcardImgOver = new GuiImage(btnsdcardOver); + sdcardImg->SetWidescreen(Settings.widescreen); + sdcardImgOver->SetWidescreen(Settings.widescreen); + sdcardBtn = new GuiButton(sdcardImg, sdcardImgOver, 0, 3, + thInt("160 - sd card btn pos x"), thInt("395 - sd card btn pos y"), + trigA, btnSoundOver, btnSoundClick2, 1, sdcardBtnTT, 15, -30, 0, 5); + + gameInfo = new GuiButton(0, 0); + gameInfo->SetTrigger(trig2); + gameInfo->SetSoundClick(btnSoundClick2); + + favoriteBtnTT = new GuiTooltip(tr( "Display favorites only" )); + if (Settings.wsprompt) favoriteBtnTT->SetWidescreen(Settings.widescreen); + favoriteBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + favoriteBtnImg = new GuiImage(imgfavIcon); + favoriteBtnImg->SetWidescreen(Settings.widescreen); + favoriteBtnImg_g = new GuiImage(imgfavIcon_gray); + favoriteBtnImg_g->SetWidescreen(Settings.widescreen); + favoriteBtn = new GuiButton(favoriteBtnImg_g, favoriteBtnImg_g, ALIGN_LEFT, ALIGN_TOP, 0, 0, + trigA, btnSoundOver, btnSoundClick2, 1, favoriteBtnTT, -15, 52, 0, 3); + favoriteBtn->SetSelectable(false); + + searchBtnTT = new GuiTooltip(tr( "Set Search-Filter" )); + if (Settings.wsprompt) searchBtnTT->SetWidescreen(Settings.widescreen); + searchBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + searchBtnImg = new GuiImage(imgsearchIcon); + searchBtnImg->SetWidescreen(Settings.widescreen); + searchBtnImg_g = new GuiImage(imgsearchIcon_gray); + searchBtnImg_g->SetWidescreen(Settings.widescreen); + searchBtn = new GuiButton(searchBtnImg_g, searchBtnImg_g, ALIGN_LEFT, ALIGN_TOP, 0, 0, + trigA, btnSoundOver, btnSoundClick2, 1, searchBtnTT, -15, 52, 0, 3); + searchBtn->SetSelectable(false); + + sortBtnTT = new GuiTooltip(" "); + if (Settings.wsprompt) sortBtnTT->SetWidescreen(Settings.widescreen); + sortBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + + sortBtnImg = new GuiImage(imgabcIcon); + sortBtnImg->SetWidescreen(Settings.widescreen); + sortBtn = new GuiButton(sortBtnImg, sortBtnImg, ALIGN_LEFT, ALIGN_TOP, 0, 0, trigA, btnSoundOver, btnSoundClick2, 1, sortBtnTT, -15, 52, 0, 3); + sortBtn->SetSelectable(false); + + loaderModeBtnTT = new GuiTooltip(tr("Select loader mode")); + if (Settings.wsprompt) loaderModeBtnTT->SetWidescreen(Settings.widescreen); + loaderModeBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + + loaderModeBtnImg = new GuiImage(imgLoaderMode); + loaderModeBtnImg->SetWidescreen(Settings.widescreen); + loaderModeBtn = new GuiButton(loaderModeBtnImg, loaderModeBtnImg, ALIGN_LEFT, ALIGN_TOP, 0, 0, trigA, btnSoundOver, btnSoundClick2, 1, loaderModeBtnTT, -15, 52, 0, 3); + loaderModeBtn->SetSelectable(false); + + categBtnTT = new GuiTooltip(tr("Select game categories")); + if (Settings.wsprompt) categBtnTT->SetWidescreen(Settings.widescreen); + categBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + + categBtnImg = new GuiImage(imgCategory); + categBtnImg->SetWidescreen(Settings.widescreen); + categBtnImg_g = new GuiImage(imgCategory_gray); + categBtnImg_g->SetWidescreen(Settings.widescreen); + categBtn = new GuiButton(categBtnImg, categBtnImg, ALIGN_LEFT, ALIGN_TOP, 0, 0, trigA, btnSoundOver, btnSoundClick2, 1, categBtnTT, -15, 52, 0, 3); + categBtn->SetSelectable(false); + + listBtnTT = new GuiTooltip(tr( "Display as a list" )); + if (Settings.wsprompt) listBtnTT->SetWidescreen(Settings.widescreen); + listBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + listBtnImg = new GuiImage(imgarrangeList); + listBtnImg->SetWidescreen(Settings.widescreen); + listBtnImg_g = new GuiImage(imgarrangeList_gray); + listBtnImg_g->SetWidescreen(Settings.widescreen); + listBtn = new GuiButton(listBtnImg_g, listBtnImg_g, ALIGN_LEFT, ALIGN_TOP, 0, 0, trigA, btnSoundOver, btnSoundClick2, 1, listBtnTT, 15, 52, 1, 3); + listBtn->SetSelectable(false); + + gridBtnTT = new GuiTooltip(tr( "Display as a grid" )); + if (Settings.wsprompt) gridBtnTT->SetWidescreen(Settings.widescreen); + gridBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + gridBtnImg = new GuiImage(imgarrangeGrid); + gridBtnImg->SetWidescreen(Settings.widescreen); + gridBtnImg_g = new GuiImage(imgarrangeGrid_gray); + gridBtnImg_g->SetWidescreen(Settings.widescreen); + gridBtn = new GuiButton(gridBtnImg_g, gridBtnImg_g, ALIGN_LEFT, ALIGN_TOP, 0, 0, trigA, btnSoundOver, btnSoundClick2, 1, gridBtnTT, 15, 52, 1, 3); + gridBtn->SetSelectable(false); + + carouselBtnTT = new GuiTooltip(tr( "Display as a carousel" )); + if (Settings.wsprompt) carouselBtnTT->SetWidescreen(Settings.widescreen); + carouselBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + carouselBtnImg = new GuiImage(imgarrangeCarousel); + carouselBtnImg->SetWidescreen(Settings.widescreen); + carouselBtnImg_g = new GuiImage(imgarrangeCarousel_gray); + carouselBtnImg_g->SetWidescreen(Settings.widescreen); + carouselBtn = new GuiButton(carouselBtnImg_g, carouselBtnImg_g, ALIGN_LEFT, ALIGN_TOP, 0, 0, trigA, btnSoundOver, btnSoundClick2, 1, carouselBtnTT, 15, 52, 1, 3); + carouselBtn->SetSelectable(false); + + bannerGridBtnTT = new GuiTooltip(tr( "Display as a channel grid" )); + if (Settings.wsprompt) bannerGridBtnTT->SetWidescreen(Settings.widescreen); + bannerGridBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + bannerGridBtnImg = new GuiImage(imgBannerGrid); + bannerGridBtnImg->SetWidescreen(Settings.widescreen); + bannerGridBtnImg_g = new GuiImage(imgBannerGrid_gray); + bannerGridBtnImg_g->SetWidescreen(Settings.widescreen); + bannerGridBtn = new GuiButton(bannerGridBtnImg_g, bannerGridBtnImg_g, ALIGN_LEFT, ALIGN_TOP, 0, 0, trigA, btnSoundOver, btnSoundClick2, 1, bannerGridBtnTT, 15, 52, 1, 3); + bannerGridBtn->SetSelectable(false); + + lockBtnTT = new GuiTooltip(NULL); + if (Settings.wsprompt) lockBtnTT->SetWidescreen(Settings.widescreen); + lockBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + lockBtnImg = new GuiImage(imgLock); + lockBtnImg->SetWidescreen(Settings.widescreen); + lockBtnImg_g = new GuiImage(imgLock_gray); + lockBtnImg_g->SetWidescreen(Settings.widescreen); + lockBtn = new GuiButton(lockBtnImg_g, lockBtnImg_g, ALIGN_LEFT, ALIGN_TOP, 0, 0, trigA, btnSoundOver, btnSoundClick2, 1, lockBtnTT, 15, 52, 1, 3); + lockBtn->SetSelectable(false); + + unlockBtnImg = new GuiImage(imgUnlock); + unlockBtnImg->SetWidescreen(Settings.widescreen); + unlockBtnImg_g = new GuiImage(imgUnlock_gray); + unlockBtnImg_g->SetWidescreen(Settings.widescreen); + + dvdBtnTT = new GuiTooltip(tr( "Mount DVD drive" )); + if (Settings.wsprompt) dvdBtnTT->SetWidescreen(Settings.widescreen); + dvdBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + dvdBtnImg = new GuiImage(imgdvd); + dvdBtnImg->SetWidescreen(Settings.widescreen); + dvdBtnImg_g = new GuiImage(imgdvd_gray); + dvdBtnImg_g->SetWidescreen(Settings.widescreen); + dvdBtn = new GuiButton(dvdBtnImg_g, 0, ALIGN_LEFT, ALIGN_TOP, 0, 0, + trigA, btnSoundOver, btnSoundClick2, 1, dvdBtnTT, 15, 52, 1, 3); + dvdBtn->SetSelectable(false); + + homebrewBtnTT = new GuiTooltip(tr( "Homebrew Launcher" )); + if (Settings.wsprompt) homebrewBtnTT->SetWidescreen(Settings.widescreen); + homebrewBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + homebrewImg = new GuiImage(homebrewImgData); + homebrewImgOver = new GuiImage(homebrewImgDataOver); + homebrewImg->SetWidescreen(Settings.widescreen); + homebrewImgOver->SetWidescreen(Settings.widescreen); + homebrewBtn = new GuiButton(homebrewImg, homebrewImgOver, ALIGN_LEFT, ALIGN_TOP, thInt("410 - HBC btn pos x"), thInt("405 - HBC btn pos y"), + trigA, btnSoundOver, btnSoundClick2, 1, homebrewBtnTT, 15, -30, 1, 5); + //Downloading Covers + DownloadBtnTT = new GuiTooltip(tr( "Click to Download Covers" )); + if (Settings.wsprompt) DownloadBtnTT->SetWidescreen(Settings.widescreen); + DownloadBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + DownloadBtn = new GuiButton (0, 0); + DownloadBtn->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + DownloadBtn->SetPosition(thInt("26 - cover/download btn pos x"), thInt("58 - cover/download btn pos y")); + DownloadBtn->SetSoundOver(btnSoundOver); + DownloadBtn->SetTrigger(0, trigA); + DownloadBtn->SetTrigger(1, trig1); + DownloadBtn->SetToolTip(DownloadBtnTT, 205, -30); + DownloadBtn->SetSelectable(false); + + gameCoverImg = new GuiImage(); + gameCoverImg->SetPosition(thInt("26 - cover/download btn pos x"), thInt("58 - cover/download btn pos y")); + gameCoverImg->SetWidescreen(Settings.widescreen); + + IDBtnTT = new GuiTooltip(tr( "Click to change game ID" )); + if (Settings.wsprompt) IDBtnTT->SetWidescreen(Settings.widescreen); + IDBtnTT->SetAlpha(thInt("255 - tooltip alpha")); + idBtn = new GuiButton(60, 23); + idBtn->SetPosition(thInt("68 - gameID btn pos x"), thInt("305 - gameID btn pos y")); + idBtn->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + idBtn->SetSoundOver(btnSoundOver); + idBtn->SetTrigger(0, trigA); + idBtn->SetToolTip(IDBtnTT, 205, -30); + idBtn->SetSelectable(false); + + GXColor clockColor = thColor("r=138 g=138 b=138 a=240 - clock color"); + float clockFontScaleFactor = thFloat("1.0 - Overrided clock scale factor. 1.0=allow user setting") != 1.0f ? thFloat("1.0 - Overrided clock scale factor. 1.0=allow user setting") : Settings.ClockFontScaleFactor; + clockTimeBack = new GuiText("88:88", 40 / Settings.FontScaleFactor * clockFontScaleFactor, (GXColor) {clockColor.r, clockColor.g, clockColor.b, (u8)(clockColor.a / 6)}); + clockTimeBack->SetAlignment(thAlign("left - clock align hor"), thAlign("top - clock align ver")); + clockTimeBack->SetPosition(thInt("275 - clock pos x"), thInt("335 - clock pos y")); + clockTimeBack->SetFont(Resources::GetFile("clock.ttf"), Resources::GetFileSize("clock.ttf")); + + clockTime = new GuiText("", 40 / Settings.FontScaleFactor * clockFontScaleFactor, clockColor); + clockTime->SetAlignment(thAlign("left - clock align hor"), thAlign("top - clock align ver")); + clockTime->SetPosition(thInt("275 - clock pos x"), thInt("335 - clock pos y")); + clockTime->SetFont(Resources::GetFile("clock.ttf"), Resources::GetFileSize("clock.ttf")); + + ToolBar.push_back(favoriteBtn); + ToolBar.push_back(searchBtn); + ToolBar.push_back(sortBtn); + ToolBar.push_back(categBtn); + ToolBar.push_back(listBtn); + ToolBar.push_back(gridBtn); + ToolBar.push_back(loaderModeBtn); + ToolBar.push_back(carouselBtn); + ToolBar.push_back(bannerGridBtn); + ToolBar.push_back(lockBtn); + ToolBar.push_back(dvdBtn); + SetUpdateCallback(UpdateCallback); + + ReloadBrowser(); +} + +GameBrowseMenu::~GameBrowseMenu() +{ + Exiting = true; + ResumeGui(); + + SetEffect(EFFECT_FADE, -20); + while(parentElement && this->GetEffect() > 0) usleep(100); + + HaltGui(); + if(parentElement) + ((GuiWindow *) parentElement)->Remove(this); + + RemoveAll(); + + //! Reset optional background image + bgImg->SetImage(background); + + delete listBackground; + delete carouselBackground; + delete gridBackground; + delete btnInstall; + delete btnInstallOver; + delete btnSettings; + delete btnSettingsOver; + delete btnpwroff; + delete btnpwroffOver; + delete btnhome; + delete btnhomeOver; + delete btnsdcardOver; + delete btnsdcard; + delete imgfavIcon; + delete imgfavIcon_gray; + delete imgsearchIcon; + delete imgsearchIcon_gray; + delete imgabcIcon; + delete imgrankIcon; + delete imgplayCountIcon; + delete imgplayersSortIcon; + delete imgarrangeGrid; + delete imgarrangeGrid_gray; + delete imgarrangeCarousel; + delete imgarrangeCarousel_gray; + delete imgBannerGrid; + delete imgBannerGrid_gray; + delete imgarrangeList; + delete imgarrangeList_gray; + delete imgdvd; + delete imgdvd_gray; + delete imgLock; + delete imgLock_gray; + delete imgUnlock; + delete imgUnlock_gray; + delete imgCategory; + delete imgCategory_gray; + delete imgLoaderMode; + delete homebrewImgData; + delete homebrewImgDataOver; + delete gameCover; + + delete trigA; + delete trigHome; + delete trig1; + delete trig2; + + delete installBtnImg; + delete installBtnImgOver; + delete settingsBtnImg; + delete settingsBtnImgOver; + delete homeBtnImg; + delete homeBtnImgOver; + delete poweroffBtnImg; + delete poweroffBtnImgOver; + delete sdcardImg; + delete sdcardImgOver; + delete favoriteBtnImg; + delete favoriteBtnImg_g; + delete searchBtnImg; + delete searchBtnImg_g; + delete sortBtnImg; + delete listBtnImg; + delete listBtnImg_g; + delete gridBtnImg; + delete gridBtnImg_g; + delete carouselBtnImg; + delete carouselBtnImg_g; + delete bannerGridBtnImg; + delete bannerGridBtnImg_g; + delete lockBtnImg; + delete lockBtnImg_g; + delete unlockBtnImg; + delete unlockBtnImg_g; + delete dvdBtnImg; + delete dvdBtnImg_g; + delete categBtnImg; + delete categBtnImg_g; + delete loaderModeBtnImg; + delete homebrewImg; + delete homebrewImgOver; + delete gameCoverImg; + + delete GameIDTxt; + delete GameRegionTxt; + delete usedSpaceTxt; + delete gamecntTxt; + delete clockTimeBack; + delete clockTime; + + delete gamecntBtn; + delete installBtn; + delete settingsBtn; + delete homeBtn; + delete poweroffBtn; + delete sdcardBtn; + delete gameInfo; + delete favoriteBtn; + delete searchBtn; + delete sortBtn; + delete listBtn; + delete gridBtn; + delete carouselBtn; + delete bannerGridBtn; + delete lockBtn; + delete dvdBtn; + delete categBtn; + delete loaderModeBtn; + delete homebrewBtn; + delete DownloadBtn; + delete idBtn; + + delete installBtnTT; + delete settingsBtnTT; + delete homeBtnTT; + delete poweroffBtnTT; + delete sdcardBtnTT; + delete favoriteBtnTT; + delete searchBtnTT; + delete sortBtnTT; + delete listBtnTT; + delete gridBtnTT; + delete carouselBtnTT; + delete bannerGridBtnTT; + delete lockBtnTT; + delete dvdBtnTT; + delete categBtnTT; + delete loaderModeBtnTT; + delete homebrewBtnTT; + delete DownloadBtnTT; + delete IDBtnTT; + + delete gameBrowser; + mainWindow->Remove(searchBar); + delete searchBar; + + ResumeGui(); +} + +int GameBrowseMenu::Execute() +{ + int retMenu = MENU_NONE; + + GameBrowseMenu * Menu = new GameBrowseMenu(); + mainWindow->Append(Menu); + + if(Settings.ShowFreeSpace) + { + ThreadedTask::Instance()->AddCallback(&Menu->HDDSizeCallback); + ThreadedTask::Instance()->Execute(); + } + + while(retMenu == MENU_NONE) + { + usleep(50000); + + if (shutdown) + Sys_Shutdown(); + if (reset) + Sys_Reboot(); + + retMenu = Menu->MainLoop(); + } + + delete Menu; + + return retMenu; +} + +void GameBrowseMenu::ReloadBrowser() +{ + ResumeGui(); + + SetEffect(EFFECT_FADE, -40); + while(parentElement && this->GetEffect() > 0) usleep(100); + + HaltGui(); + RemoveAll(); + mainWindow->Remove(searchBar); + + gamecntTxt->SetText(fmt("%s: %i", tr( "Games" ), gameList.size())); + + const char * sortTTText = NULL; + GuiImageData * sortImgData = NULL; + + if(Settings.GameSort & SORT_RANKING) + { + sortTTText = tr( "Sort by rank" ); + sortImgData = imgrankIcon; + } + else if(Settings.GameSort & SORT_PLAYCOUNT) + { + sortTTText = tr( "Sort order by most played"); + sortImgData = imgplayCountIcon; + } + else if(Settings.GameSort & SORT_PLAYERS) + { + sortTTText = tr( "Sort by number of players"); + sortImgData = imgplayersSortIcon; + } + else + { + sortTTText = tr("Sort alphabetically"); + sortImgData = imgabcIcon; + } + + sortBtnTT->SetText(sortTTText); + sortBtnImg->SetImage(sortImgData); + + if(DiscDriveCoverOld & 0x02) + dvdBtn->SetImage(dvdBtnImg); + else + dvdBtn->SetImage(dvdBtnImg_g); + + if (Settings.GameSort & SORT_FAVORITE) + { + favoriteBtn->SetImage(favoriteBtnImg); + favoriteBtn->SetImageOver(favoriteBtnImg); + } + else + { + favoriteBtn->SetImage(favoriteBtnImg_g); + favoriteBtn->SetImageOver(favoriteBtnImg_g); + } + + if (*gameList.GetCurrentFilter()) + { + if (!show_searchwindow) searchBtn->SetEffect(EFFECT_PULSE, 10, 105); + searchBtn->SetImage(searchBtnImg); + searchBtn->SetImageOver(searchBtnImg); + } + else if(!show_searchwindow) + { + searchBtn->SetImage(searchBtnImg_g); + searchBtn->SetImageOver(searchBtnImg_g); + } + + if (Settings.godmode) + { + GuiImage * unlockImage = strcmp(Settings.unlockCode, "") == 0 ? unlockBtnImg_g : unlockBtnImg; + lockBtn->SetImage(unlockImage); + lockBtn->SetImageOver(unlockImage); + lockBtnTT->SetText(tr( "Lock USB Loader GX" )); + } + else + { + lockBtn->SetImage(lockBtnImg); + lockBtn->SetImageOver(lockBtnImg); + lockBtnTT->SetText(tr( "Unlock USB Loader GX" )); + } + + categBtn->SetImage(categBtnImg); + for(u32 n = 0; n < Settings.EnabledCategories.size(); ++n) + { + if(Settings.EnabledCategories[n] == 0) + { + categBtn->SetImage(categBtnImg_g); + break; + } + } + + //! Check if the loaded setting is still in range + Settings.SelectedGame = LIMIT(Settings.SelectedGame, 0, gameList.size()-1); + Settings.GameListOffset = LIMIT(Settings.GameListOffset, 0, gameList.size()-1); + + delete gameBrowser; + delete searchBar; + gameBrowser = NULL; + searchBar = NULL; + + if (Settings.gameDisplay == LIST_MODE) + { + //! only one image, reload it since it won't be changeable later + if(gameList.size() == 1) + LoadCover(gameList[0]); + if(gameList.size() > 0) + Append(gameCoverImg); + DownloadBtn->SetSize(160, 224); + listBtn->SetImage(listBtnImg); + listBtn->SetImageOver(listBtnImg); + gridBtn->SetImage(gridBtnImg_g); + gridBtn->SetImageOver(gridBtnImg_g); + carouselBtn->SetImage(carouselBtnImg_g); + carouselBtn->SetImageOver(carouselBtnImg_g); + bannerGridBtn->SetImage(bannerGridBtnImg_g); + bannerGridBtn->SetImageOver(bannerGridBtnImg_g); + + favoriteBtn->SetPosition(Settings.widescreen ? thInt("214 - list layout favorite btn pos x widescreen") : thInt("168 - list layout favorite btn pos x"), + thInt("13 - list layout favorite btn pos y")); + searchBtn->SetPosition(Settings.widescreen ? thInt("246 - list layout search btn pos x widescreen") : thInt("208 - list layout search btn pos x"), + thInt("13 - list layout search btn pos y")); + sortBtn->SetPosition(Settings.widescreen ? thInt("278 - list layout abc/sort btn pos x widescreen") : thInt("248 - list layout abc/sort btn pos x"), + thInt("13 - list layout abc/sort btn pos y")); + loaderModeBtn->SetPosition(Settings.widescreen ? thInt("310 - list layout loadermode btn pos x widescreen") : thInt("288 - list layout loadermode btn pos x"), + thInt("13 - list layout loadermode btn pos y")); + categBtn->SetPosition(Settings.widescreen ? thInt("342 - list layout category btn pos x widescreen") : thInt("328 - list layout category btn pos x"), + thInt("13 - list layout category btn pos y")); + listBtn->SetPosition(Settings.widescreen ? thInt("374 - list layout list btn pos x widescreen") : thInt("368 - list layout list btn pos x"), + thInt("13 - list layout list btn pos y")); + gridBtn->SetPosition(Settings.widescreen ? thInt("406 - list layout grid btn pos x widescreen") : thInt("408 - list layout grid btn pos x"), + thInt("13 - list layout grid btn pos y")); + carouselBtn->SetPosition(Settings.widescreen ? thInt("438 - list layout carousel btn pos x widescreen") : thInt("448 - list layout carousel btn pos x"), + thInt("13 - list layout carousel btn pos y")); + bannerGridBtn->SetPosition(Settings.widescreen ? thInt("470 - list layout bannergrid btn pos x widescreen") : thInt("488 - list layout bannergrid btn pos x"), + thInt("13 - list layout bannergrid btn pos y")); + lockBtn->SetPosition(Settings.widescreen ? thInt("502 - list layout lock btn pos x widescreen") : thInt("528 - list layout lock btn pos x"), + thInt("13 - list layout lock btn pos y")); + dvdBtn->SetPosition(Settings.widescreen ? thInt("534 - list layout dvd btn pos x widescreen") : thInt("568 - list layout dvd btn pos x"), + thInt("13 - list layout dvd btn pos y")); + + gameBrowser = new GuiGameList(thInt("396 - game list layout width"), thInt("280 - game list layout height"), Settings.GameListOffset); + gameBrowser->SetPosition(thInt("200 - game list layout pos x"), thInt("49 - game list layout pos y")); + gameBrowser->SetAlignment(ALIGN_LEFT, ALIGN_CENTER); + gameBrowser->SetSelectedOption(Settings.SelectedGame); + + //! Setup optional background image + if(!listBackground) + listBackground = Resources::GetImageData("listBackground.png"); + if(listBackground) + bgImg->SetImage(listBackground); + else + bgImg->SetImage(background); + } + else if (Settings.gameDisplay == GRID_MODE) + { + DownloadBtn->SetSize(0, 0); + UpdateGameInfoText(NULL); + gridBtn->SetImage(gridBtnImg); + gridBtn->SetImageOver(gridBtnImg); + listBtn->SetImage(listBtnImg_g); + listBtn->SetImageOver(listBtnImg_g); + carouselBtn->SetImage(carouselBtnImg_g); + carouselBtn->SetImageOver(carouselBtnImg_g); + bannerGridBtn->SetImage(bannerGridBtnImg_g); + bannerGridBtn->SetImageOver(bannerGridBtnImg_g); + + favoriteBtn->SetPosition(Settings.widescreen ? thInt("144 - grid layout favorite btn pos x widescreen") : thInt("100 - grid layout favorite btn pos x"), + thInt("13 - grid layout favorite btn pos y")); + searchBtn->SetPosition(Settings.widescreen ? thInt("176 - grid layout search btn pos x widescreen") : thInt("140 - grid layout search btn pos x"), + thInt("13 - grid layout search btn pos y")); + sortBtn->SetPosition(Settings.widescreen ? thInt("208 - grid layout abc/sort btn pos x widescreen") : thInt("180 - grid layout abc/sort btn pos x"), + thInt("13 - grid layout abc/sort btn pos y")); + loaderModeBtn->SetPosition(Settings.widescreen ? thInt("240 - grid layout loadermode btn pos x widescreen") : thInt("220 - grid layout loadermode btn pos x"), + thInt("13 - grid layout loadermode btn pos y")); + categBtn->SetPosition(Settings.widescreen ? thInt("272 - grid layout category btn pos x widescreen") : thInt("260 - grid layout category btn pos x"), + thInt("13 - grid layout category btn pos y")); + listBtn->SetPosition(Settings.widescreen ? thInt("304 - grid layout list btn pos x widescreen") : thInt("300 - grid layout list btn pos x"), + thInt("13 - grid layout list btn pos y")); + gridBtn->SetPosition(Settings.widescreen ? thInt("336 - grid layout grid btn pos x widescreen") : thInt("340 - grid layout grid btn pos x"), + thInt("13 - grid layout grid btn pos y")); + carouselBtn->SetPosition(Settings.widescreen ? thInt("368 - grid layout carousel btn pos x widescreen") : thInt("380 - grid layout carousel btn pos x"), + thInt("13 - grid layout carousel btn pos y")); + bannerGridBtn->SetPosition(Settings.widescreen ? thInt("400 - grid layout bannergrid btn pos x widescreen") : thInt("420 - grid layout bannergrid btn pos x"), + thInt("13 - grid layout bannergrid btn pos y")); + lockBtn->SetPosition(Settings.widescreen ? thInt("432 - grid layout lock btn pos x widescreen") : thInt("460 - grid layout lock btn pos x"), + thInt("13 - grid layout lock btn pos y")); + dvdBtn->SetPosition(Settings.widescreen ? thInt("464 - grid layout dvd btn pos x widescreen") : thInt("500 - grid layout dvd btn pos x"), + thInt("13 - grid layout dvd btn pos y")); + + gameBrowser = new GuiGameGrid(thInt("640 - game grid layout width"), thInt("400 - game grid layout height"), Settings.theme_path, Settings.GameListOffset); + gameBrowser->SetPosition(thInt("0 - game grid layout pos x"), thInt("20 - game grid layout pos y")); + gameBrowser->SetAlignment(ALIGN_LEFT, ALIGN_CENTER); + + //! Setup optional background image + if(!gridBackground) + gridBackground = Resources::GetImageData("gridBackground.png"); + if(gridBackground) + bgImg->SetImage(gridBackground); + else + bgImg->SetImage(background); + } + else if (Settings.gameDisplay == CAROUSEL_MODE) + { + DownloadBtn->SetSize(0, 0); + UpdateGameInfoText(NULL); + carouselBtn->SetImage(carouselBtnImg); + carouselBtn->SetImageOver(carouselBtnImg); + listBtn->SetImage(listBtnImg_g); + listBtn->SetImageOver(listBtnImg_g); + gridBtn->SetImage(gridBtnImg_g); + gridBtn->SetImageOver(gridBtnImg_g); + bannerGridBtn->SetImage(bannerGridBtnImg_g); + bannerGridBtn->SetImageOver(bannerGridBtnImg_g); + + favoriteBtn->SetPosition(Settings.widescreen ? thInt("144 - carousel layout favorite btn pos x widescreen") : thInt("100 - carousel layout favorite btn pos x"), + thInt("13 - carousel layout favorite btn pos y")); + searchBtn->SetPosition(Settings.widescreen ? thInt("176 - carousel layout search btn pos x widescreen") : thInt("140 - carousel layout search btn pos x"), + thInt("13 - carousel layout search btn pos y")); + sortBtn->SetPosition(Settings.widescreen ? thInt("208 - carousel layout abc/sort btn pos x widescreen") : thInt("180 - carousel layout abc/sort btn pos x"), + thInt("13 - carousel layout abc/sort btn pos y")); + loaderModeBtn->SetPosition(Settings.widescreen ? thInt("240 - carousel layout loadermode btn pos x widescreen") : thInt("220 - carousel layout loadermode btn pos x"), + thInt("13 - carousel layout loadermode btn pos y")); + categBtn->SetPosition(Settings.widescreen ? thInt("272 - carousel layout category btn pos x widescreen") : thInt("260 - carousel layout category btn pos x"), + thInt("13 - carousel layout category btn pos y")); + listBtn->SetPosition(Settings.widescreen ? thInt("304 - carousel layout list btn pos x widescreen") : thInt("300 - carousel layout list btn pos x"), + thInt("13 - carousel layout list btn pos y")); + gridBtn->SetPosition(Settings.widescreen ? thInt("336 - carousel layout grid btn pos x widescreen") : thInt("340 - carousel layout grid btn pos x"), + thInt("13 - carousel layout grid btn pos y")); + carouselBtn->SetPosition(Settings.widescreen ? thInt("368 - carousel layout carousel btn pos x widescreen") : thInt("380 - carousel layout carousel btn pos x"), + thInt("13 - carousel layout carousel btn pos y")); + bannerGridBtn->SetPosition(Settings.widescreen ? thInt("400 - carousel layout bannergrid btn pos x widescreen") : thInt("420 - carousel layout bannergrid btn pos x"), + thInt("13 - carousel layout bannergrid btn pos y")); + lockBtn->SetPosition(Settings.widescreen ? thInt("432 - carousel layout lock btn pos x widescreen") : thInt("460 - carousel layout lock btn pos x"), + thInt("13 - carousel layout lock btn pos y")); + dvdBtn->SetPosition(Settings.widescreen ? thInt("464 - carousel layout dvd btn pos x widescreen") : thInt("500 - carousel layout dvd btn pos x"), + thInt("13 - carousel layout dvd btn pos y")); + + gameBrowser = new GuiGameCarousel(thInt("640 - game carousel layout width"), thInt("400 - game carousel layout height"), Settings.theme_path, Settings.GameListOffset); + gameBrowser->SetPosition(thInt("0 - game carousel layout pos x"), thInt("-20 - game carousel layout pos y")); + gameBrowser->SetAlignment(ALIGN_LEFT, ALIGN_CENTER); + + //! Setup optional background image + if(!carouselBackground) + carouselBackground = Resources::GetImageData("carouselBackground.png"); + if(carouselBackground) + bgImg->SetImage(carouselBackground); + else + bgImg->SetImage(background); + } + else if(Settings.gameDisplay == BANNERGRID_MODE) + { + DownloadBtn->SetSize(0, 0); + UpdateGameInfoText(NULL); + bannerGridBtn->SetImage(bannerGridBtnImg); + bannerGridBtn->SetImageOver(bannerGridBtnImg); + listBtn->SetImage(listBtnImg_g); + listBtn->SetImageOver(listBtnImg_g); + gridBtn->SetImage(gridBtnImg_g); + gridBtn->SetImageOver(gridBtnImg_g); + carouselBtn->SetImage(carouselBtnImg_g); + carouselBtn->SetImageOver(carouselBtnImg_g); + + favoriteBtn->SetPosition(Settings.widescreen ? thInt("144 - bannergrid layout favorite btn pos x widescreen") : thInt("100 - bannergrid layout favorite btn pos x"), + thInt("13 - bannergrid layout favorite btn pos y")); + searchBtn->SetPosition(Settings.widescreen ? thInt("176 - bannergrid layout search btn pos x widescreen") : thInt("140 - bannergrid layout search btn pos x"), + thInt("13 - bannergrid layout search btn pos y")); + sortBtn->SetPosition(Settings.widescreen ? thInt("208 - bannergrid layout abc/sort btn pos x widescreen") : thInt("180 - bannergrid layout abc/sort btn pos x"), + thInt("13 - bannergrid layout abc/sort btn pos y")); + loaderModeBtn->SetPosition(Settings.widescreen ? thInt("240 - bannergrid layout loadermode btn pos x widescreen") : thInt("220 - bannergrid layout loadermode btn pos x"), + thInt("13 - bannergrid layout loadermode btn pos y")); + categBtn->SetPosition(Settings.widescreen ? thInt("272 - bannergrid layout category btn pos x widescreen") : thInt("260 - bannergrid layout category btn pos x"), + thInt("13 - bannergrid layout category btn pos y")); + listBtn->SetPosition(Settings.widescreen ? thInt("304 - bannergrid layout list btn pos x widescreen") : thInt("300 - bannergrid layout list btn pos x"), + thInt("13 - bannergrid layout list btn pos y")); + gridBtn->SetPosition(Settings.widescreen ? thInt("336 - bannergrid layout grid btn pos x widescreen") : thInt("340 - bannergrid layout grid btn pos x"), + thInt("13 - bannergrid layout grid btn pos y")); + carouselBtn->SetPosition(Settings.widescreen ? thInt("368 - bannergrid layout carousel btn pos x widescreen") : thInt("380 - bannergrid layout carousel btn pos x"), + thInt("13 - bannergrid layout carousel btn pos y")); + bannerGridBtn->SetPosition(Settings.widescreen ? thInt("400 - bannergrid layout bannergrid btn pos x widescreen") : thInt("420 - bannergrid layout bannergrid btn pos x"), + thInt("13 - bannergrid layout bannergrid btn pos y")); + lockBtn->SetPosition(Settings.widescreen ? thInt("432 - bannergrid layout lock btn pos x widescreen") : thInt("460 - bannergrid layout lock btn pos x"), + thInt("13 - bannergrid layout lock btn pos y")); + dvdBtn->SetPosition(Settings.widescreen ? thInt("464 - bannergrid layout dvd btn pos x widescreen") : thInt("500 - bannergrid layout dvd btn pos x"), + thInt("13 - bannergrid layout dvd btn pos y")); + + gameBrowser = new GuiBannerGrid(Settings.GameListOffset + Settings.SelectedGame); + } + + if (thInt("1 - show hdd info: 1 for on and 0 for off") == 1) //force show hdd info + Append(usedSpaceTxt); + if (thInt("1 - show game count: 1 for on and 0 for off") == 1) //force show game cnt info + Append(gamecntBtn); + if (Settings.godmode || !(Settings.ParentalBlocks & BLOCK_SD_RELOAD_BUTTON)) + Append(sdcardBtn); + Append(poweroffBtn); + Append(gameInfo); + Append(homeBtn); + Append(settingsBtn); + + if (Settings.godmode || !(Settings.ParentalBlocks & BLOCK_HBC_MENU)) + Append(homebrewBtn); + + if (Settings.godmode || !(Settings.ParentalBlocks & BLOCK_GAME_INSTALL)) + Append(installBtn); + + if (Settings.godmode || !(Settings.ParentalBlocks & BLOCK_COVER_DOWNLOADS)) + Append(DownloadBtn); + + if ((Settings.gameDisplay == LIST_MODE) && (Settings.godmode || !(Settings.ParentalBlocks & BLOCK_GAMEID_CHANGE))) + Append(idBtn); + + Append(favoriteBtn); + Append(searchBtn); + Append(sortBtn); + Append(categBtn); + Append(listBtn); + Append(gridBtn); + Append(loaderModeBtn); + Append(carouselBtn); + Append(bannerGridBtn); + Append(lockBtn); + Append(dvdBtn); + + if ((Settings.hddinfo == CLOCK_HR12) || (Settings.hddinfo == CLOCK_HR24)) + { + Append(clockTimeBack); + Append(clockTime); + } + + if (gameBrowser) + Append(gameBrowser); + + if (show_searchwindow) + { + searchBar = new GuiSearchBar; + mainWindow->Append(searchBar); + } + + SetEffect(EFFECT_FADE, 40); + ResumeGui(); + + while(parentElement && this->GetEffect() > 0) usleep(100); +} + +int GameBrowseMenu::MainLoop() +{ + UpdateClock(); + CheckDiscSlotUpdate(); + + if (updateavailable == true) + { + gprintf("\tUpdate Available\n"); + SetState(STATE_DISABLED); + UpdateApp(); + updateavailable = false; + SetState(STATE_DEFAULT); + } + + else if (poweroffBtn->GetState() == STATE_CLICKED) + { + gprintf("\tpoweroffBtn clicked\n"); + int choice = 0; + if(isWiiU()) + choice = WindowPrompt(tr( "How to Shutdown?" ), 0, tr( "Full shutdown" ), tr("Cancel")); + else + choice = WindowPrompt(tr( "How to Shutdown?" ), 0, tr( "Full shutdown" ), tr( "Standby" ), tr( "Cancel" )); + + if (choice == 2) + Sys_ShutdownToIdle(); + else if (choice == 1) + Sys_ShutdownToStandby(); + + poweroffBtn->ResetState(); + } + else if (gamecntBtn->GetState() == STATE_CLICKED) + { + gprintf("\tgameCntBtn clicked\n"); + gamecntBtn->ResetState(); + + int choice = WindowPrompt(0, fmt("%s %sGameList ?", tr( "Save Game List to" ), Settings.update_path), "TXT", "CSV", tr( "Back" )); + if (choice) + { + if (save_gamelist(choice == 2)) + WindowPrompt(0, tr( "Saved" ), tr( "OK" )); + else + WindowPrompt(tr( "Error" ), tr( "Could not save." ), tr( "OK" )); + } + } + else if (homeBtn->GetState() == STATE_CLICKED) + { + gprintf("\thomeBtn clicked\n"); + WindowExitPrompt(); + + homeBtn->ResetState(); + } + else if (installBtn->GetState() == STATE_CLICKED) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_GAME_INSTALL)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + installBtn->ResetState(); + return MENU_NONE; + } + + int choice = WindowPrompt(tr( "Install a game" ), 0, tr( "Yes" ), tr( "No" )); + if (choice == 1) + { + this->SetState(STATE_DISABLED); + if(!(Settings.LoaderMode & MODE_WIIGAMES) && (gameList.GameCount() == 0)) + { + if(WBFS_ReInit(WBFS_DEVICE_USB) < 0) + ShowError(tr("Failed to initialize the USB storage device.")); + else + { + gameList.ReadGameList(); + GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path, false); + if(Settings.ShowFreeSpace) + { + ThreadedTask::Instance()->AddCallback(&HDDSizeCallback); + ThreadedTask::Instance()->Execute(); + } + return MenuInstall(); + } + } + else + return MenuInstall(); + + this->SetState(STATE_DEFAULT); + } + installBtn->ResetState(); + } + else if (sdcardBtn->GetState() == STATE_CLICKED) + { + gprintf("\tsdCardBtn Clicked\n"); + if(WindowPrompt(tr("Are you sure you want to remount SD?"), tr("The application might crash if there is currently a read/write access to the SD card!"), tr("Yes"), tr("Cancel"))) + { + HaltGui(); + BannerAsync::HaltThread(); + bgMusic->Pause(); + Settings.Save(); + DeviceHandler::Instance()->UnMountSD(); + DeviceHandler::Instance()->MountSD(); + gprintf("\tLoading config...%s\n", Settings.Load() ? "done" : "failed"); + gprintf("\tLoading language...%s\n", Settings.LoadLanguage(Settings.language_path, CONSOLE_DEFAULT) ? "done" : "failed"); + gprintf("\tLoading game settings...%s\n", GameSettings.Load(Settings.ConfigPath) ? "done" : "failed"); + gprintf("\tLoading game statistics...%s\n", GameStatistics.Load(Settings.ConfigPath) ? "done" : "failed"); + gprintf("\tLoading font...%s\n", Theme::LoadFont(Settings.theme_path) ? "done" : "failed (using default)"); + gprintf("\tLoading theme...%s\n", Theme::Load(Settings.theme) ? "done" : "failed (using default)"); + bgMusic->Resume(); + gameList.FilterList(); + ReloadBrowser(); + BannerAsync::ResumeThread(); + ResumeGui(); + } + sdcardBtn->ResetState(); + } + + else if (DownloadBtn->GetState() == STATE_CLICKED) + { + gprintf("\tDownloadBtn Clicked\n"); + ImageDownloader::DownloadImages(); + ReloadBrowser(); + DownloadBtn->ResetState(); + } + + else if (settingsBtn->GetState() == STATE_CLICKED) + { + if (!Settings.godmode && (Settings.ParentalBlocks & BLOCK_GLOBAL_SETTINGS)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + settingsBtn->ResetState(); + return MENU_NONE; + } + + return MENU_SETTINGS; + } + + else if (favoriteBtn->GetState() == STATE_CLICKED) + { + favoriteBtn->ResetState(); + gprintf("\tfavoriteBtn Clicked\n"); + + if(Settings.GameSort & SORT_FAVORITE) + Settings.GameSort &= ~SORT_FAVORITE; + else + Settings.GameSort |= SORT_FAVORITE; + + gameList.FilterList(); + + if((Settings.GameSort & SORT_FAVORITE) && gameList.size() == 0) + { + Settings.GameSort &= ~SORT_FAVORITE; + gameList.FilterList(); + ShowError(tr("No favorites selected.")); + } + else + ReloadBrowser(); + } + + else if (searchBtn->GetState() == STATE_CLICKED) + { + gprintf("\tsearchBtn Clicked\n"); + show_searchwindow = !show_searchwindow; + gameList.FilterList(); + ReloadBrowser(); + searchBtn->ResetState(); + if(show_searchwindow && wcslen(gameList.GetCurrentFilter()) == 0) + GridRowsPreSearch = Settings.gridRows; //! store old rows amount + } + + else if (searchBar && (searchChar = searchBar->GetClicked())) + { + if (searchChar > 27) //! Character clicked + { + int len = gameList.GetCurrentFilter() ? wcslen(gameList.GetCurrentFilter()) : 0; + wchar_t newFilter[len + 2]; + if (gameList.GetCurrentFilter()) wcscpy(newFilter, gameList.GetCurrentFilter()); + newFilter[len] = searchChar; + newFilter[len + 1] = 0; + + gameList.FilterList(newFilter); + } + else if (searchChar == 27) //! Close + { + show_searchwindow = false; + searchBtn->StopEffect(); + } + else if (searchChar == 7) //! Clear + { + gameList.FilterList(L""); + Settings.gridRows = GridRowsPreSearch; //! restore old rows amount so we don't stay on one row + } + else if (searchChar == 8) //! Backspace + { + int len = wcslen(gameList.GetCurrentFilter()); + wchar_t newFilter[len + 1]; + if (gameList.GetCurrentFilter()) wcscpy(newFilter, gameList.GetCurrentFilter()); + newFilter[len > 0 ? len - 1 : 0] = 0; + gameList.FilterList(newFilter); + if(len == 1) + Settings.gridRows = GridRowsPreSearch; //! restore old rows amount so we don't stay on one row + } + else if (searchChar == 6) + { + Settings.SearchMode = Settings.SearchMode == SEARCH_BEGINNING ? SEARCH_CONTENT : SEARCH_BEGINNING; + gameList.FilterList(); + } + ReloadBrowser(); + return MENU_NONE; + } + + else if (sortBtn->GetState() == STATE_CLICKED) + { + sortBtn->ResetState(); + gprintf("\tsortBtn clicked\n"); + if(Settings.GameSort & SORT_ABC) + { + Settings.GameSort &= ~SORT_ABC; + Settings.GameSort |= SORT_RANKING; + } + else if(Settings.GameSort & SORT_RANKING) + { + Settings.GameSort &= ~SORT_RANKING; + Settings.GameSort |= SORT_PLAYCOUNT; + } + else if(Settings.GameSort & SORT_PLAYCOUNT) + { + Settings.GameSort &= ~SORT_PLAYCOUNT; + Settings.GameSort |= SORT_PLAYERS; + } + else if(Settings.GameSort & SORT_PLAYERS) + { + Settings.GameSort &= ~SORT_PLAYERS; + Settings.GameSort |= SORT_ABC; + } + + gameList.FilterList(); + ReloadBrowser(); + } + + else if (listBtn->GetState() == STATE_CLICKED) + { + if (!Settings.godmode && (Settings.ParentalBlocks & BLOCK_LOADER_LAYOUT_BUTTON)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + listBtn->ResetState(); + return returnMenu; + } + gprintf("\tlistBtn Clicked\n"); + if (Settings.gameDisplay != LIST_MODE) + { + Settings.gameDisplay = LIST_MODE; + ReloadBrowser(); + } + listBtn->ResetState(); + } + + else if (gridBtn->GetState() == STATE_CLICKED) + { + if (!Settings.godmode && (Settings.ParentalBlocks & BLOCK_LOADER_LAYOUT_BUTTON)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + gridBtn->ResetState(); + return returnMenu; + } + gprintf("\tgridBtn Clicked\n"); + if (Settings.gameDisplay != GRID_MODE) + { + Settings.gameDisplay = GRID_MODE; + ReloadBrowser(); + } + gridBtn->ResetState(); + } + + else if (carouselBtn->GetState() == STATE_CLICKED) + { + if (!Settings.godmode && (Settings.ParentalBlocks & BLOCK_LOADER_LAYOUT_BUTTON)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + carouselBtn->ResetState(); + return returnMenu; + } + gprintf("\tcarouselBtn Clicked\n"); + if (Settings.gameDisplay != CAROUSEL_MODE) + { + Settings.gameDisplay = CAROUSEL_MODE; + ReloadBrowser(); + } + carouselBtn->ResetState(); + } + + else if (bannerGridBtn->GetState() == STATE_CLICKED) + { + if (!Settings.godmode && (Settings.ParentalBlocks & BLOCK_LOADER_LAYOUT_BUTTON)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + bannerGridBtn->ResetState(); + return returnMenu; + } + gprintf("\tbannerGridBtn Clicked\n"); + if(!SystemMenuResources::Instance()->IsLoaded()) { + WindowPrompt(tr( "Error:" ), tr( "Banner grid layout is only available with AHBPROT! Please consider installing new HBC version." ), tr( "OK" )); + bannerGridBtn->ResetState(); + return MENU_NONE; + } + if (Settings.gameDisplay != BANNERGRID_MODE) + { + Settings.gameDisplay = BANNERGRID_MODE; + ReloadBrowser(); + } + bannerGridBtn->ResetState(); + } + + else if (homebrewBtn->GetState() == STATE_CLICKED) + { + gprintf("\thomebrewBtn Clicked\n"); + return MENU_HOMEBREWBROWSE; + } + + else if (gameInfo->GetState() == STATE_CLICKED) + { + gprintf("\tgameinfo Clicked\n"); + int SelectedGame = GetSelectedGame(); + gameInfo->ResetState(); + if (SelectedGame >= 0 && SelectedGame < (s32) gameList.size()) + { + rockout(gameList[SelectedGame]); + SetState(STATE_DISABLED); + int choice = showGameInfo(SelectedGame, 0); + SetState(STATE_DEFAULT); + rockout(0); + if (choice == 2) + homeBtn->SetState(STATE_CLICKED); + } + } + else if (lockBtn->GetState() == STATE_CLICKED) + { + gprintf("\tlockBtn clicked\n"); + lockBtn->ResetState(); + if (Settings.godmode) + { + if(WindowPrompt(tr( "Parental Control" ), tr( "Are you sure you want to lock USB Loader GX?" ), tr( "Yes" ), tr( "No" )) == 1) + { + Settings.godmode = 0; + gameList.FilterList(); + ReloadBrowser(); + } + } + else + { + //password check to unlock Install,Delete and Format + SetState(STATE_DISABLED); + int result = PasswordCheck(Settings.unlockCode); + SetState(STATE_DEFAULT); + if (result > 0) + { + if(result == 1) + WindowPrompt( tr( "Correct Password" ), tr( "All the features of USB Loader GX are unlocked." ), tr( "OK" )); + Settings.godmode = 1; + gameList.FilterList(); + ReloadBrowser(); + } + else if(result < 0) + WindowPrompt(tr( "Wrong Password" ), tr( "USB Loader GX is protected" ), tr( "OK" )); + } + } + + else if(categBtn->GetState() == STATE_CLICKED) + { + if (!Settings.godmode && (Settings.ParentalBlocks & BLOCK_CATEGORIES_MENU)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + categBtn->ResetState(); + return returnMenu; + } + + mainWindow->SetState(STATE_DISABLED); + CategorySwitchPrompt promptMenu; + promptMenu.SetAlignment(thAlign("center - category switch prompt align hor"), thAlign("middle - category switch prompt align ver")); + promptMenu.SetPosition(thInt("0 - category switch prompt pos x"), thInt("0 - category switch prompt pos y")); + promptMenu.SetEffect(EFFECT_FADE, 20); + mainWindow->Append(&promptMenu); + + promptMenu.Show(); + + promptMenu.SetEffect(EFFECT_FADE, -20); + while(promptMenu.GetEffect() > 0) usleep(100); + mainWindow->Remove(&promptMenu); + categBtn->ResetState(); + mainWindow->SetState(STATE_DEFAULT); + if(promptMenu.categoriesChanged()) + { + gameList.FilterList(); + ReloadBrowser(); + } + } + + else if(loaderModeBtn->GetState() == STATE_CLICKED) + { + if (!Settings.godmode && (Settings.ParentalBlocks & BLOCK_LOADER_MODE_BUTTON)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + loaderModeBtn->ResetState(); + return returnMenu; + } + + int choice = CheckboxWindow(tr( "Select titles sources." ), 0, tr( "Wii Games" ), tr( "Nand Channels" ), tr("EmuNand Channels"), tr("GC Games"), 0, 0, Settings.LoaderMode); + if(choice != CheckedNone && choice != Settings.LoaderMode) + { + Settings.LoaderMode = choice; + + if((Settings.LoaderMode & MODE_WIIGAMES) && (gameList.GameCount() == 0)) + { + s32 wbfsinit = WBFS_Init(WBFS_DEVICE_USB); + if (wbfsinit < 0) + { + ShowError("%s %s", tr( "USB Device not initialized." ), tr("Switching to channel list mode.")); + Settings.LoaderMode &= ~MODE_WIIGAMES; + Settings.LoaderMode |= MODE_NANDCHANNELS; + } + else + { + WBFS_ReInit(WBFS_DEVICE_USB); + } + gameList.ReadGameList(); + + if(Settings.ShowFreeSpace) + { + ThreadedTask::Instance()->AddCallback(&HDDSizeCallback); + ThreadedTask::Instance()->Execute(); + } + } + + wString oldFilter(gameList.GetCurrentFilter()); + GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path, false); + gameList.FilterList(oldFilter.c_str()); + ReloadBrowser(); + } + loaderModeBtn->ResetState(); + } + + else if (Settings.gameDisplay == LIST_MODE && idBtn->GetState() == STATE_CLICKED) + { + gprintf("\tidBtn Clicked\n"); + struct discHdr * header = gameList[GetSelectedGame()]; + //enter new game ID + char entered[7]; + snprintf(entered, sizeof(entered), "%s", (char *) header->id); + int result = OnScreenKeyboard(entered, sizeof(entered), 0); + if (result == 1) + { + WBFS_ReIDGame(header->id, entered); + wString oldFilter(gameList.GetCurrentFilter()); + gameList.ReadGameList(); + gameList.FilterList(oldFilter.c_str()); + ReloadBrowser(); + } + idBtn->ResetState(); + } + + else if (Settings.gameDisplay == LIST_MODE && GetSelectedGame() != gameSelectedOld) + { + gameSelectedOld = GetSelectedGame(); + int gameSelected = gameSelectedOld; + if(gameSelected >= 0 && gameSelected < (s32) gameList.size()) + { + struct discHdr *header = gameList[gameSelected]; + LoadCover(header); + UpdateGameInfoText(header->id); + } + } + + if(gameBrowser) + { + //! This is bad, but for saving pupose it will be in main loop + Settings.GameListOffset = gameBrowser->getListOffset(); + Settings.SelectedGame = gameBrowser->GetSelectedOption()-Settings.GameListOffset; + } + + gameClicked = gameBrowser ? gameBrowser->GetClickedOption() : -1; + + if(gameClicked >= 0 && gameClicked < (s32) gameList.size()) + OpenClickedGame(gameList[gameClicked]); + + return returnMenu; +} + +void GameBrowseMenu::CheckDiscSlotUpdate() +{ + // No need to update every 1 ms + static u32 delayCounter = 0; + if(++delayCounter < 100) + return; + + delayCounter = 0; + u32 DiscDriveCover = 0; + WDVD_GetCoverStatus(&DiscDriveCover);//for detecting if i disc has been inserted + + if ((DiscDriveCover & 0x02) && (DiscDriveCover != DiscDriveCoverOld)) + { + int choice = WindowPrompt(tr( "Disc Insert Detected" ), 0, tr( "Install" ), tr( "Mount DVD drive" ), tr( "Cancel" )); + if (choice == 1) + installBtn->SetState(STATE_CLICKED); + else if (choice == 2) + dvdBtn->SetState(STATE_CLICKED); + } + else if (dvdBtn->GetState() == STATE_CLICKED) + { + gprintf("\tdvdBtn Clicked\n"); + if(DiscDriveCover & 0x02) + { + if(!dvdheader) + dvdheader = new struct discHdr; + + if(Disc_Mount(dvdheader) < 0) + { + delete dvdheader; + dvdheader = NULL; + ShowError(tr("Can't mount or unknown disc format.")); + } + else + OpenClickedGame(dvdheader); + } + else + WindowPrompt(tr( "No disc inserted." ), 0, tr( "OK" )); + + dvdBtn->ResetState(); + } + + if(DiscDriveCoverOld != DiscDriveCover) + { + if(DiscDriveCover & 0x02) + dvdBtn->SetImage(dvdBtnImg); + else + dvdBtn->SetImage(dvdBtnImg_g); + + DiscDriveCoverOld = DiscDriveCover; + } +} + +void GameBrowseMenu::UpdateClock() +{ + if(Settings.hddinfo != CLOCK_HR12 && Settings.hddinfo != CLOCK_HR24) + return; + + time_t rawtime = time(0); + if(rawtime == lastrawtime) //! Only update every 1 second + return; + + lastrawtime = rawtime; + + char theTime[50]; + theTime[0] = 0; + + struct tm * timeinfo = localtime(&rawtime); + if (Settings.hddinfo == CLOCK_HR12) + { + if (rawtime & 1) + strftime(theTime, sizeof(theTime), "%I:%M", timeinfo); + else + strftime(theTime, sizeof(theTime), "%I %M", timeinfo); + } + if (Settings.hddinfo == CLOCK_HR24) + { + if (rawtime & 1) + strftime(theTime, sizeof(theTime), "%H:%M", timeinfo); + else + strftime(theTime, sizeof(theTime), "%H %M", timeinfo); + } + clockTime->SetText(theTime); + + if (Settings.screensaver != 0 && ControlActivityTimeout()) + { + WindowScreensaver(); + } +} + +void GameBrowseMenu::UpdateGameInfoText(const u8 * gameId) +{ + if(!gameId) + { + Remove(GameRegionTxt); + delete GameRegionTxt; + GameRegionTxt = NULL; + Remove(GameIDTxt); + delete GameIDTxt; + GameIDTxt = NULL; + return; + } + + char gameregion[10]; + char IDfull[7]; + snprintf(IDfull, sizeof(IDfull), (char *) gameId); + + switch (IDfull[3]) + { + case 'A': + case 'B': + case 'U': + case 'X': + strcpy(gameregion, tr("Region Free")); + break; + case 'E': + case 'N': + strcpy(gameregion, "NTSC U"); + break; + case 'J': + strcpy(gameregion, "NTSC J"); + break; + case 'K': + case 'Q': + case 'T': + strcpy(gameregion, "NTSC K"); + break; + case 'W': + strcpy(gameregion, "NTSC T"); + break; + default: + strcpy(gameregion, " PAL "); + } + + HaltGui(); + if (Settings.sinfo == GAMEINFO_ID || Settings.sinfo == GAMEINFO_BOTH) + { + Remove(GameIDTxt); + delete GameIDTxt; + GameIDTxt = new GuiText(IDfull, 22, thColor("r=55 g=190 b=237 a=255 - game id text color")); + GameIDTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + GameIDTxt->SetPosition(thInt("68 - gameID btn pos x"), thInt("305 - gameID btn pos y")); + GameIDTxt->SetEffect(EFFECT_FADE, 20); + Append(GameIDTxt); + } + //don't try to show region for channels because all the custom channels wont follow the rules + if ((Settings.sinfo == GAMEINFO_REGION) || (Settings.sinfo == GAMEINFO_BOTH)) + { + Remove(GameRegionTxt); + delete GameRegionTxt; + GameRegionTxt = new GuiText(gameregion, 22, thColor("r=55 g=190 b=237 a=255 - region info text color")); + GameRegionTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + GameRegionTxt->SetPosition(thInt("68 - region info text pos x"), thInt("30 - region info text pos y")); + GameRegionTxt->SetEffect(EFFECT_FADE, 20); + Append(GameRegionTxt); + } + ResumeGui(); +} + +int GameBrowseMenu::OpenClickedGame(struct discHdr *header) +{ + int choice = -1; + + if (searchBar) + { + HaltGui(); + mainWindow->Remove(searchBar); + ResumeGui(); + } + + rockout(header); + + SetAllowDim(false); + SetState(STATE_DISABLED); + if(gameBrowser) + gameBrowser->SetState(STATE_DISABLED); + + if (Settings.wiilight == ON) + wiilight(1); + + if (Settings.quickboot) { //quickboot game + GameWindow::BootGame(header); + } + else if((Settings.GameWindowMode == GAMEWINDOW_BANNER) || + (Settings.GameWindowMode == GAMEWINDOW_BOTH && Settings.gameDisplay == BANNERGRID_MODE)) + { + BannerWindow GamePrompt(this, header); + mainWindow->Append(&GamePrompt); + + choice = GamePrompt.Run(); + } + else if((Settings.GameWindowMode == GAMEWINDOW_DISC) || + (Settings.GameWindowMode == GAMEWINDOW_BOTH && Settings.gameDisplay != BANNERGRID_MODE)) + { + SetAllowDim(true); + GameWindow GamePrompt(this, header); + mainWindow->Append(&GamePrompt); + + choice = GamePrompt.Run(); + } + + if (choice == 1) + { + gameList.FilterList(); + ReloadBrowser(); + if(Settings.ShowFreeSpace) + { + ThreadedTask::Instance()->AddCallback(&HDDSizeCallback); + ThreadedTask::Instance()->Execute(); + } + } + + wiilight(0); + rockout(0); + + SetState(STATE_DEFAULT); + SetAllowDim(true); + + if(gameBrowser) + gameBrowser->SetState(STATE_DEFAULT); + + if (searchBar) + { + HaltGui(); + mainWindow->Append(searchBar); + ResumeGui(); + } + + return 0; +} + +void GameBrowseMenu::LoadCover(struct discHdr *header) +{ + gameCoverImg->SetImage(NULL); + + delete gameCover; + gameCover = LoadCoverImage(header); + + gameCoverImg->SetImage(gameCover);// put the new image on the download button +} + +void GameBrowseMenu::UpdateCallback(void * e) +{ + //! Draw the selected Icon allways on top + GameBrowseMenu * w = (GameBrowseMenu *) e; + + for(u32 i = 0; i < w->ToolBar.size(); ++i) + { + if(w->ToolBar[i]->GetState() == STATE_SELECTED) + { + w->Remove(w->ToolBar[i]); + w->Append(w->ToolBar[i]); + break; + } + } +} + +void GameBrowseMenu::UpdateFreeSpace(void * arg) +{ + char spaceinfo[30]; + spaceinfo[0] = 0; + + if(Settings.ShowFreeSpace) + { + float freespace = 0.0, used = 0.0; + int ret = WBFS_DiskSpace(&used, &freespace); + if(ret >= 0) + { + if (strcmp(Settings.db_language, "JA") == 0) + { + // needs to be "total...used" for Japanese + snprintf(spaceinfo, sizeof(spaceinfo), "%.2fGB %s %.2fGB %s", (freespace + used), tr( "of" ), freespace, tr( "free" )); + } + else + { + snprintf(spaceinfo, sizeof(spaceinfo), "%.2fGB %s %.2fGB %s", freespace, tr( "of" ), (freespace + used), tr( "free" )); + } + } + } + + if(Exiting) + return; + + usedSpaceTxt->SetText(spaceinfo); +} + diff --git a/source/menu/GameBrowseMenu.hpp b/source/menu/GameBrowseMenu.hpp new file mode 100644 index 0000000..55c58c3 --- /dev/null +++ b/source/menu/GameBrowseMenu.hpp @@ -0,0 +1,174 @@ +#ifndef GAMEBROWSEMENU_HPP_ +#define GAMEBROWSEMENU_HPP_ + +#include "GUI/gui_gamebrowser.h" +#include "GUI/gui_searchbar.h" +#include "utils/ThreadedTask.hpp" + +class GameBrowseMenu : public GuiWindow +{ + public: + GameBrowseMenu(); + virtual ~GameBrowseMenu(); + static int Execute(); + void ReloadBrowser(); + GuiGameBrowser *GetGameBrowser() { return gameBrowser; } + private: + int MainLoop(); + int OpenClickedGame(struct discHdr *header); + int GetSelectedGame() { return (gameBrowser ? gameBrowser->GetSelectedOption() : -1); } + void UpdateGameInfoText(const u8 * gameId); + void LoadCover(struct discHdr *header); + void CheckDiscSlotUpdate(); + void UpdateFreeSpace(void *arg); + void UpdateClock(); + static void UpdateCallback(void * e); + + TCallback HDDSizeCallback; + u32 DiscDriveCoverOld; + int returnMenu; + int gameSelectedOld; + int gameClicked; + int GridRowsPreSearch; + time_t lastrawtime; + bool show_searchwindow; + wchar_t searchChar; + std::vector ToolBar; + + GuiGameBrowser * gameBrowser; + GuiSearchBar * searchBar; + + GuiImageData * listBackground; + GuiImageData * carouselBackground; + GuiImageData * gridBackground; + GuiImageData * btnInstall; + GuiImageData * btnInstallOver; + GuiImageData * btnSettings; + GuiImageData * btnSettingsOver; + GuiImageData * btnpwroff; + GuiImageData * btnpwroffOver; + GuiImageData * btnhome; + GuiImageData * btnhomeOver; + GuiImageData * btnsdcardOver; + GuiImageData * btnsdcard; + GuiImageData * imgfavIcon; + GuiImageData * imgfavIcon_gray; + GuiImageData * imgsearchIcon; + GuiImageData * imgsearchIcon_gray; + GuiImageData * imgabcIcon; + GuiImageData * imgrankIcon; + GuiImageData * imgplayCountIcon; + GuiImageData * imgplayersSortIcon; + GuiImageData * imgarrangeGrid; + GuiImageData * imgarrangeGrid_gray; + GuiImageData * imgarrangeCarousel; + GuiImageData * imgarrangeCarousel_gray; + GuiImageData * imgarrangeList; + GuiImageData * imgarrangeList_gray; + GuiImageData * imgdvd; + GuiImageData * imgdvd_gray; + GuiImageData * imgBannerGrid; + GuiImageData * imgBannerGrid_gray; + GuiImageData * imgLock; + GuiImageData * imgLock_gray; + GuiImageData * imgUnlock; + GuiImageData * imgUnlock_gray; + GuiImageData * imgCategory; + GuiImageData * imgCategory_gray; + GuiImageData * imgLoaderMode; + GuiImageData * homebrewImgData; + GuiImageData * homebrewImgDataOver; + GuiImageData * gameCover; + + GuiTrigger * trigA; + GuiTrigger * trigHome; + GuiTrigger * trig1; + GuiTrigger * trig2; + + GuiImage * installBtnImg; + GuiImage * installBtnImgOver; + GuiImage * settingsBtnImg; + GuiImage * settingsBtnImgOver; + GuiImage * homeBtnImg; + GuiImage * homeBtnImgOver; + GuiImage * poweroffBtnImg; + GuiImage * poweroffBtnImgOver; + GuiImage * sdcardImg; + GuiImage * sdcardImgOver; + GuiImage * favoriteBtnImg; + GuiImage * favoriteBtnImg_g; + GuiImage * searchBtnImg; + GuiImage * searchBtnImg_g; + GuiImage * sortBtnImg; + GuiImage * listBtnImg; + GuiImage * listBtnImg_g; + GuiImage * gridBtnImg; + GuiImage * gridBtnImg_g; + GuiImage * carouselBtnImg; + GuiImage * carouselBtnImg_g; + GuiImage * bannerGridBtnImg; + GuiImage * bannerGridBtnImg_g; + GuiImage * lockBtnImg; + GuiImage * lockBtnImg_g; + GuiImage * unlockBtnImg; + GuiImage * unlockBtnImg_g; + GuiImage * dvdBtnImg; + GuiImage * dvdBtnImg_g; + GuiImage * categBtnImg; + GuiImage * categBtnImg_g; + GuiImage * loaderModeBtnImg; + GuiImage * homebrewImg; + GuiImage * homebrewImgOver; + GuiImage * gameCoverImg; + + GuiText * usedSpaceTxt; + GuiText * gamecntTxt; + GuiText * clockTimeBack; + GuiText * clockTime; + GuiText * GameRegionTxt; + GuiText * GameIDTxt; + + GuiButton * gamecntBtn; + GuiButton * installBtn; + GuiButton * settingsBtn; + GuiButton * homeBtn; + GuiButton * poweroffBtn; + GuiButton * sdcardBtn; + GuiButton * gameInfo; + GuiButton * favoriteBtn; + GuiButton * searchBtn; + GuiButton * sortBtn; + GuiButton * listBtn; + GuiButton * gridBtn; + GuiButton * carouselBtn; + GuiButton * bannerGridBtn; + GuiButton * lockBtn; + GuiButton * dvdBtn; + GuiButton * categBtn; + GuiButton * loaderModeBtn; + GuiButton * homebrewBtn; + GuiButton * DownloadBtn; + GuiButton * idBtn; + + GuiTooltip * installBtnTT; + GuiTooltip * settingsBtnTT; + GuiTooltip * homeBtnTT; + GuiTooltip * poweroffBtnTT; + GuiTooltip * sdcardBtnTT; + GuiTooltip * favoriteBtnTT; + GuiTooltip * searchBtnTT; + GuiTooltip * sortBtnTT; + GuiTooltip * listBtnTT; + GuiTooltip * gridBtnTT; + GuiTooltip * carouselBtnTT; + GuiTooltip * bannerGridBtnTT; + GuiTooltip * lockBtnTT; + GuiTooltip * dvdBtnTT; + GuiTooltip * categBtnTT; + GuiTooltip * loaderModeBtnTT; + GuiTooltip * homebrewBtnTT; + GuiTooltip * DownloadBtnTT; + GuiTooltip * IDBtnTT; +}; + +#endif diff --git a/source/menu/WDMMenu.cpp b/source/menu/WDMMenu.cpp new file mode 100644 index 0000000..7e2cc7a --- /dev/null +++ b/source/menu/WDMMenu.cpp @@ -0,0 +1,264 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "WDMMenu.hpp" +#include "FileOperations/fileops.h" +#include "menu/menus.h" +#include "themes/CTheme.h" +#include "language/gettext.h" +#include "usbloader/wbfs.h" +#include "libs/libwbfs/libwbfs.h" +#include "libs/libwbfs/wiidisc.h" +#include "usbloader/fstfile.h" +#include "settings/GameTitles.h" +#include "gecko.h" + +u32 WDMMenu::AlternateDolOffset = 0; +u32 WDMMenu::AlternateDolParameter = 0; + +WDMMenu::WDMMenu(const struct discHdr * header) + : GuiWindow(screenwidth, screenheight) +{ + Options = new OptionList; + + btnOutline = Resources::GetImageData("button_dialogue_box.png"); + + trigA = new GuiTrigger(); + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + trigB = new GuiTrigger(); + trigB->SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + defaultBtnTxt = new GuiText(tr("Default"), 22, (GXColor){0, 0, 0, 255}); + defaultBtnImg = new GuiImage(btnOutline); + defaultBtn = new GuiButton(defaultBtnImg, defaultBtnImg, 2, 3, 130, 400, trigA, btnSoundOver, btnSoundClick2, 1); + defaultBtn->SetLabel(defaultBtnTxt); + Append(defaultBtn); + + backBtnTxt = new GuiText(tr("Back"), 22, (GXColor){0, 0, 0, 255}); + backBtnImg = new GuiImage(btnOutline); + backBtn = new GuiButton(backBtnImg, backBtnImg, 2, 3, -130, 400, trigA, btnSoundOver, btnSoundClick2, 1); + backBtn->SetLabel(backBtnTxt); + backBtn->SetTrigger(trigB); + Append(backBtn); + + optionBrowser = new GuiOptionBrowser(396, 280, Options, "bg_options_settings.png"); + optionBrowser->SetPosition(0, 90); + optionBrowser->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + Append(optionBrowser); + + SetEffect(EFFECT_FADE, 50); + + char WDMPath[200]; + snprintf(WDMPath, sizeof(WDMPath), "%s/%.3s.wdm", Settings.WDMpath, (char *) header->id); + + if(!CheckFile(WDMPath)) + { + snprintf(WDMPath, sizeof(WDMPath), "%s/%.6s.wdm", Settings.WDMpath, (char *) header->id); + if(!CheckFile(WDMPath)) + snprintf(WDMPath, sizeof(WDMPath), "%s/%.4s.wdm", Settings.WDMpath, (char *) header->id); + } + + wdmFile = new WDMFile(WDMPath); + + CheckGameFiles(header); +} + +WDMMenu::~WDMMenu() +{ + ResumeGui(); + + SetEffect(EFFECT_FADE, -50); + while(this->GetEffect() > 0) + usleep(100); + + HaltGui(); + if(parentElement) + ((GuiWindow *) parentElement)->Remove(this); + + RemoveAll(); + + delete btnOutline; + + delete backBtnTxt; + delete backBtnImg; + delete backBtn; + + delete defaultBtnTxt; + delete defaultBtnImg; + delete defaultBtn; + + delete trigA; + delete trigB; + + delete optionBrowser; + delete wdmFile; + + ResumeGui(); +} + +int WDMMenu::GetChoice() +{ + if (shutdown) + Sys_Shutdown(); + else if (reset) + Sys_Reboot(); + + if(backBtn->GetState() == STATE_CLICKED) + return 0; + + else if(defaultBtn->GetState() == STATE_CLICKED) + return 1; + + int choice = optionBrowser->GetClickedOption(); + if(choice >= 0 && choice < (int) DOLOffsetList.size()) + { + AlternateDolOffset = DOLOffsetList[choice].first; + AlternateDolParameter = DOLOffsetList[choice].second; + return 1; + } + + return -1; +} + +int WDMMenu::Show(const struct discHdr * header) +{ + WDMMenu Menu(header); + + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&Menu); + + int ret = -1; + + while(ret == -1) + { + usleep(100); + ret = Menu.GetChoice(); + } + mainWindow->SetState(STATE_DEFAULT); + + return ret; +} + +static inline bool stringcompare(const char * replace, const char * dolname) +{ + if(strlen(replace) == 0 || strlen(dolname) == 0) + return false; + + for( ; *replace != 0 && *dolname != 0; replace++, dolname++) + { + if(*replace == '?') + continue; + + if(toupper((int) *replace) != toupper((int) *dolname)) + return false; + } + + return true; +} + +void WDMMenu::CheckGameFiles(const struct discHdr * header) +{ + wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) header->id); + if (!disc) + { + WindowPrompt(tr( "ERROR:" ), tr( "Could not open Disc" ), tr( "OK" )); + return; + } + + wiidisc_t *wdisc = wd_open_disc((s32(*)(void *, u32, u32, void *)) wbfs_disc_read, disc); + if (!wdisc) + { + WindowPrompt(tr( "ERROR:" ), tr( "Could not open Disc" ), tr( "OK" )); + return; + } + + FST_ENTRY * fstbuffer = (FST_ENTRY *) wd_extract_file(wdisc, ONLY_GAME_PARTITION, (char*) "FST"); + if (!fstbuffer) + { + WindowPrompt(tr( "ERROR:" ), tr( "Not enough free memory." ), tr( "OK" )); + return; + } + + wd_close_disc(wdisc); + WBFS_CloseDisc(disc); + + int position = 0; + vector > FilesNotInWDM; + + for(int i = 0; i < wdmFile->size(); ++i) + { + if(stringcompare(wdmFile->GetDolName(i), "main") == true) + { + DOLOffsetList.push_back(pair(0, wdmFile->GetParameter(i))); + Options->SetName(position, "%i.", position+1); + Options->SetValue(position, wdmFile->GetReplaceName(i)); + position++; + } + } + + for (u32 i = 1; i < fstbuffer[0].filelen; i++) + { + //don't add files that aren't .dol to the list + const char * filename = fstfiles(fstbuffer, i); + const char * fileext = NULL; + + if(filename) + fileext = strrchr(filename, '.'); + + if (fileext && strcasecmp(fileext, ".dol") == 0) + { + char NameCpy[strlen(filename)+1]; + strcpy(NameCpy, filename); + char *extension = strrchr(NameCpy, '.'); + if(extension) *extension = 0; + + int j; + for(j = 0; j < wdmFile->size(); ++j) + { + if(stringcompare(wdmFile->GetDolName(j), NameCpy) == true) + { + DOLOffsetList.push_back(pair(i, wdmFile->GetParameter(j))); + Options->SetName(position, "%i.", position+1); + Options->SetValue(position, wdmFile->GetReplaceName(j)); + position++; + break; + } + } + + if(j == wdmFile->size()) + FilesNotInWDM.push_back(pair(i, filename)); + } + } + + for(u32 i = 0; i < FilesNotInWDM.size(); ++i) + { + DOLOffsetList.push_back(pair(FilesNotInWDM[i].first, 1)); + Options->SetName(position, "%i.", position+1); + Options->SetValue(position, FilesNotInWDM[i].second.c_str()); + position++; + } + + free(fstbuffer); +} diff --git a/source/menu/WDMMenu.hpp b/source/menu/WDMMenu.hpp new file mode 100644 index 0000000..fc78ad9 --- /dev/null +++ b/source/menu/WDMMenu.hpp @@ -0,0 +1,44 @@ +#ifndef WDMMENU_HPP_ +#define WDMMENU_HPP_ + +#include "GUI/gui.h" +#include "GUI/gui_optionbrowser.h" +#include "usbloader/disc.h" +#include "usbloader/WDMFile.hpp" + +class WDMMenu : public GuiWindow +{ + public: + WDMMenu(const struct discHdr * header); + virtual ~WDMMenu(); + int GetChoice(); + static int Show(const struct discHdr * header); + static u32 GetAlternateDolOffset() { return AlternateDolOffset; } + static u32 GetDolParameter() { return AlternateDolParameter; } + private: + void CheckGameFiles(const struct discHdr * header); + + static u32 AlternateDolOffset; + static u32 AlternateDolParameter; + + WDMFile * wdmFile; + vector > DOLOffsetList; + GuiImageData * btnOutline; + + GuiTrigger * trigA; + GuiTrigger * trigB; + + OptionList * Options; + + GuiText * backBtnTxt; + GuiImage * backBtnImg; + GuiButton * backBtn; + + GuiText * defaultBtnTxt; + GuiImage * defaultBtnImg; + GuiButton * defaultBtn; + + GuiOptionBrowser * optionBrowser; +}; + +#endif diff --git a/source/menu/menu_install.cpp b/source/menu/menu_install.cpp new file mode 100644 index 0000000..ae27f0b --- /dev/null +++ b/source/menu/menu_install.cpp @@ -0,0 +1,309 @@ +#include +#include "menus.h" +#include "GameCube/GCGames.h" +#include "GameCube/GCDumper.hpp" +#include "usbloader/usbstorage2.h" +#include "usbloader/wbfs.h" +#include "usbloader/disc.h" +#include "usbloader/GameList.h" +#include "prompts/ProgressWindow.h" +#include "prompts/GCMultiDiscMenu.h" +#include "themes/CTheme.h" +#include "utils/tools.h" +#include "system/IosLoader.h" + +#define WII_MAGIC 0x5D1C9EA3 + +extern int install_abort_signal; +float gamesize = 0.0f; + +/**************************************************************************** + * MenuGCInstall + ***************************************************************************/ +int MenuGCInstall() +{ + GCDumper gcDumper; + if(gcDumper.ReadDiscHeader() < 0) + { + WindowPrompt(tr("Error"), tr("Error reading disc"), tr("OK")); + return MENU_DISCLIST; + } + + std::vector installGames; + + if(gcDumper.GetDiscHeaders().size() == 0) + { + WindowPrompt(tr("Error"), tr("No games found on the disc"), tr("OK")); + return MENU_DISCLIST; + } + else if(gcDumper.GetDiscHeaders().size() > 1) + { + //! Multi game disc, lets ask the user which games to install + GCMultiDiscMenu gcMenu(gcDumper.GetDiscHeaders()); + gcMenu.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + gcMenu.SetEffect(EFFECT_FADE, 20); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&gcMenu); + + int choice = gcMenu.ShowSelection(); + + gcMenu.SetEffect(EFFECT_FADE, -20); + while(gcMenu.GetEffect() > 0) usleep(1000); + + mainWindow->Remove(&gcMenu); + mainWindow->SetState(STATE_DEFAULT); + + installGames = gcMenu.GetSelectedGames(); + + if(choice == 0 || installGames.size() == 0) + return MENU_DISCLIST; + } + else + { + if(!WindowPrompt(tr( "Continue to install game?" ), gcDumper.GetDiscHeaders().at(0).title, tr("Yes"), tr( "Cancel" ))) + return MENU_DISCLIST; + + installGames.push_back(0); + } + + //! setup dumper settings + gcDumper.SetCompressed(Settings.GCInstallCompressed); + gcDumper.SetCompressed(Settings.GCInstallAligned); + + //! If a different main path than the SD path is selected ask where to install + int destination = 1; + if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) != 0) + destination = WindowPrompt(tr("Where should the game be installed to?"), 0, tr("Main Path"), tr("SD Path"), tr("Cancel")); + if(!destination) + return MENU_DISCLIST; + + //! Alert the user if he is dumping on SD with DIOS MIOS (USB) installed + if(destination == 2 && IosLoader::GetMIOSInfo() == DIOS_MIOS) + { + if(!WindowPrompt(tr("Are you sure you want to install on SD?"), ("You have DIOS-MIOS installed so the game need to be on a FAT32 USB. You will need to install DIOS-MIOS Lite to run this game from SD."), tr("Yes"), tr( "Cancel" ))) + return MENU_DISCLIST; + } + + // Load only available games from the selected device + int oldGameCubeSource = Settings.GameCubeSource; + Settings.GameCubeSource = destination-1; + GCGames::Instance()->LoadAllGames(); + + const char *InstallPath = destination == 1 ? Settings.GameCubePath : Settings.GameCubeSDPath; + + //! Start of install process, enable wii slot light + wiilight(1); + + int result = 0; + int installed_games = 0; + + for(u32 i = 0; i < installGames.size(); ++i) + { + //! check if the game is already installed on SD/USB + if(GCGames::Instance()->IsInstalled((char *)gcDumper.GetDiscHeaders().at(installGames[i]).id, gcDumper.GetDiscHeaders().at(installGames[i]).disc_no)) + { + WindowPrompt(tr("Game is already installed:"), gcDumper.GetDiscHeaders().at(installGames[i]).title, tr("OK")); + if(i+1 < installGames.size()) { + continue; + } + else if(i == 0) + { + result = MENU_DISCLIST; + break; + } + } + + // Check Disc2 installation format (DML 2.6+ auto-swap feature doesn't work with extracted game format) + if(Settings.GCInstallCompressed && gcDumper.GetDiscHeaders().at(installGames[i]).disc_no == 1) + { + int choice = WindowPrompt(tr(gcDumper.GetDiscHeaders().at(installGames[i]).title), tr("Disc2 needs to be installed in uncompressed format to work with DM(L) v2.6+, are you sure you want to install in compressed format?"), tr("Yes"), tr("Cancel")); + if(choice == 0) + { + if(i+1 < installGames.size()) { + continue; + } + else if(i == 0) + { + result = MENU_DISCLIST; + break; + } + } + } + + // Check if another Disc number from the same game is already installed on this device + GCGames::Instance()->LoadAllGames(); // refresh installed game list + char installedGamePath[512]; + if(GCGames::Instance()->IsInstalled((char *)gcDumper.GetDiscHeaders().at(installGames[i]).id, gcDumper.GetDiscHeaders().at(installGames[i]).disc_no == 0 ? 1 : 0)) + { + snprintf(installedGamePath, sizeof(installedGamePath), GCGames::Instance()->GetPath((char *)gcDumper.GetDiscHeaders().at(installGames[i]).id)); + char *pathPtr = strrchr(installedGamePath, '/'); + if(pathPtr) *pathPtr = 0; + } + else + installedGamePath[0] = 0; + + // game is not yet installed so let's install it + int ret = gcDumper.InstallGame(InstallPath, installGames[i], installedGamePath); + if(ret >= 0) { + //! success + installed_games++; + } + else if(ret == PROGRESS_CANCELED) + { + result = MENU_DISCLIST; + break; + } + else if(ret < 0) + { + //! Error occured, ask the user what to do if there are more games to install + if(i+1 < installGames.size()) + { + if(!WindowPrompt(tr( "Install Error!" ), tr("Do you want to continue with next game?"), tr("Yes"), tr( "Cancel" ))) + { + result = MENU_DISCLIST; + break; + } + } + else + { + WindowPrompt(tr( "Install Error!" ), 0, tr( "Back" )); + result = MENU_DISCLIST; + break; + } + } + } + + wiilight(0); + Settings.GameCubeSource = oldGameCubeSource; + GCGames::Instance()->LoadAllGames(); + + //! no game was installed so don't show successfully installed prompt + if(installed_games == 0) + return result; + + gameList.FilterList(); + bgMusic->Pause(); + GuiSound instsuccess(Resources::GetFile("success.ogg"), Resources::GetFileSize("success.ogg"), Settings.sfxvolume); + instsuccess.SetVolume(Settings.sfxvolume); + instsuccess.SetLoop(0); + instsuccess.Play(); + char gamesTxt[20]; + snprintf(gamesTxt, sizeof(gamesTxt), "%i %s", installed_games, tr("Games")); + WindowPrompt(tr("Successfully installed:"), installGames.size() > 1 ? gamesTxt : gcDumper.GetDiscHeaders().at(installGames[0]).title, tr( "OK" )); + instsuccess.Stop(); + bgMusic->Resume(); + + return MENU_DISCLIST; +} + +/**************************************************************************** + * MenuInstall + ***************************************************************************/ +int MenuInstall() +{ + gprintf("\nMenuInstall()\n"); + + static struct discHdr headerdisc ATTRIBUTE_ALIGN( 32 ); + + Disc_SetUSB(NULL); + + int ret, choice = 0; + + ret = DiscWait(tr( "Insert Disk" ), tr( "Waiting..." ), tr( "Cancel" ), 0, 0); + if (ret < 0) + { + WindowPrompt(tr( "Error reading Disc" ), 0, tr( "Back" )); + return MENU_DISCLIST; + } + ret = Disc_Open(); + if (ret < 0) + { + WindowPrompt(tr( "Could not open Disc" ), 0, tr( "Back" )); + return MENU_DISCLIST; + } + + memset(&headerdisc, 0, sizeof(struct discHdr)); + + Disc_ReadHeader(&headerdisc); + + if ((headerdisc.magic != WII_MAGIC) && (headerdisc.gc_magic != GCGames::MAGIC)) + { + choice = WindowPrompt(tr( "Not a Wii or a Game Cube Disc" ), tr( "Insert a Wii or a Game Cube Disc!" ), tr( "OK" ), tr( "Back" )); + if (choice == 1) + return MenuInstall(); + else + return MENU_DISCLIST; + } + + if(headerdisc.gc_magic == GCGames::MAGIC) + { + return MenuGCInstall(); + } + + ret = WBFS_CheckGame(headerdisc.id); + if (ret) + { + WindowPrompt(tr( "Game is already installed:" ), headerdisc.title, tr( "Back" )); + return MENU_DISCLIST; + } + + f32 freespace, used; + + WBFS_DiskSpace(&used, &freespace); + gamesize = (float) WBFS_EstimeGameSize(); + + char gametxt[strlen(headerdisc.title) + 16]; + snprintf(gametxt, sizeof(gametxt), "%s : %.2fGB", headerdisc.title, gamesize/GB_SIZE); + + wiilight(1); + choice = WindowPrompt(tr( "Continue to install game?" ), gametxt, tr( "OK" ), tr( "Cancel" )); + + if (choice == 1) + { + sprintf(gametxt, "%s", tr( "Installing game:" )); + + if (gamesize/GB_SIZE > freespace) + { + char errortxt[50]; + sprintf(errortxt, "%s: %.2fGB, %s: %.2fGB", tr( "Game Size" ), gamesize/GB_SIZE, tr( "Free Space" ), freespace); + WindowPrompt(tr( "Not enough free space!" ), errortxt, tr( "OK" )); + } + else + { + StartProgress(gametxt, headerdisc.title, 0, true, true); + ProgressCancelEnable(true); + ret = WBFS_AddGame(); + ProgressCancelEnable(false); + ProgressStop(); + wiilight(0); + if (install_abort_signal) + { + WindowPrompt(tr( "Install Canceled" ), 0, tr( "OK" )); + } + else if (ret != 0) + { + WindowPrompt(tr( "Install Error!" ), 0, tr( "Back" )); + } + else + { + ShowProgress(tr("Install finished"), headerdisc.title, tr("Reloading game list now, please wait..."), gamesize, gamesize, true, true); + gameList.ReadGameList(); //get the entries again + gameList.FilterList(); + bgMusic->Pause(); + GuiSound instsuccess(Resources::GetFile("success.ogg"), Resources::GetFileSize("success.ogg"), Settings.sfxvolume); + instsuccess.SetVolume(Settings.sfxvolume); + instsuccess.SetLoop(0); + instsuccess.Play(); + WindowPrompt(tr( "Successfully installed:" ), headerdisc.title, tr( "OK" )); + instsuccess.Stop(); + bgMusic->Resume(); + } + } + } + + //Turn off the WiiLight + wiilight(0); + gamesize = 0.0f; + + return MENU_DISCLIST; +} diff --git a/source/menu/menu_partition_selection.cpp b/source/menu/menu_partition_selection.cpp new file mode 100644 index 0000000..be88573 --- /dev/null +++ b/source/menu/menu_partition_selection.cpp @@ -0,0 +1,131 @@ +#include + +#include "menus.h" +#include "usbloader/usbstorage2.h" +#include "usbloader/wbfs.h" +#include "GUI/gui_optionbrowser.h" +#include "Controls/DeviceHandler.hpp" +#include "themes/CTheme.h" +#include "utils/tools.h" + +/**************************************************************************** + * SelectPartitionMenu + ***************************************************************************/ +int SelectPartitionMenu() +{ + bool ExitSelect = false; + OptionList options; + + u32 counter = 0; + int choice = -1; + int ret = -1; + + //create the partitionlist + for (int cnt = 0; cnt < DeviceHandler::GetUSBPartitionCount(); cnt++) + { + PartitionHandle * usbHandle = DeviceHandler::Instance()->GetUSBHandleFromPartition(cnt); + int portPart = DeviceHandler::PartitionToPortPartition(cnt); + /* Calculate size in gigabytes */ + f32 size = usbHandle->GetSize(portPart) / GB_SIZE; + + if (size) + { + options.SetName(counter, "%s %d %s: ", tr( "Partition" ), cnt + 1, usbHandle->GetFSName(portPart)); + options.SetValue(counter, "%.2fGB", size); + } + else + { + options.SetName(counter, "%s %d:", tr( "Partition" ), cnt + 1); + options.SetValue(counter, tr( "Can't be formatted" )); + } + counter++; + } + + GuiImageData btnpwroff(Resources::GetFile("wiimote_poweroff.png"), Resources::GetFileSize("wiimote_poweroff.png")); + GuiImageData btnpwroffOver(Resources::GetFile("wiimote_poweroff_over.png"), Resources::GetFileSize("wiimote_poweroff_over.png")); + GuiImageData btnhome(Resources::GetFile("menu_button.png"), Resources::GetFileSize("menu_button.png")); + GuiImageData btnhomeOver(Resources::GetFile("menu_button_over.png"), Resources::GetFileSize("menu_button_over.png")); + GuiImageData battery(Resources::GetFile("battery.png"), Resources::GetFileSize("battery.png")); + GuiImageData batteryBar(Resources::GetFile("battery_bar.png"), Resources::GetFileSize("battery_bar.png")); + GuiImageData batteryRed(Resources::GetFile("battery_red.png"), Resources::GetFileSize("battery_red.png")); + GuiImageData batteryBarRed(Resources::GetFile("battery_bar_red.png"), Resources::GetFileSize("battery_bar_red.png")); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigHome; + trigHome.SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, 0); + + GuiImage poweroffBtnImg(&btnpwroff); + GuiImage poweroffBtnImgOver(&btnpwroffOver); + poweroffBtnImg.SetWidescreen(Settings.widescreen); + poweroffBtnImgOver.SetWidescreen(Settings.widescreen); + GuiButton poweroffBtn(&poweroffBtnImg, &poweroffBtnImgOver, 0, 3, + thInt("576 - power off btn pos x"), thInt("355 - power off btn pos y"), + &trigA, btnSoundOver, btnSoundClick2, 1); + GuiImage exitBtnImg(&btnhome); + GuiImage exitBtnImgOver(&btnhomeOver); + exitBtnImg.SetWidescreen(Settings.widescreen); + exitBtnImgOver.SetWidescreen(Settings.widescreen); + GuiButton exitBtn(&exitBtnImg, &exitBtnImgOver, 0, 3, + thInt("489 - home menu btn pos x"), thInt("371 - home menu btn pos y"), + &trigA, btnSoundOver, btnSoundClick2, 1); + exitBtn.SetTrigger(&trigHome); + + GuiOptionBrowser optionBrowser(396, 280, &options, "bg_options_settings.png"); + optionBrowser.SetPosition(0, 40); + optionBrowser.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + + HaltGui(); + GuiWindow w(screenwidth, screenheight); + w.Append(&poweroffBtn); + w.Append(&exitBtn); + + mainWindow->Append(&w); + mainWindow->Append(&optionBrowser); + + ResumeGui(); + + while (!ExitSelect) + { + VIDEO_WaitVSync(); + + if (shutdown) + Sys_Shutdown(); + if (reset) + Sys_Reboot(); + + ret = optionBrowser.GetClickedOption(); + + if (ret >= 0) + { + if (strcmp(options.GetValue(ret), tr( "Can't be formatted" )) != 0) + { + choice = ret; + ExitSelect = true; + } + } + + if (poweroffBtn.GetState() == STATE_CLICKED) + { + choice = WindowPrompt(tr( "Shutdown System" ), tr( "Are you sure?" ), tr( "Yes" ), tr( "No" )); + if (choice == 1) + Sys_Shutdown(); + + } + else if (exitBtn.GetState() == STATE_CLICKED) + { + choice = WindowPrompt(tr( "Return to Wii Menu" ), tr( "Are you sure?" ), tr( "Yes" ), tr( "No" )); + if (choice == 1) + Sys_LoadMenu(); + } + } + + HaltGui(); + + mainWindow->Remove(&optionBrowser); + mainWindow->Remove(&w); + ResumeGui(); + + return choice; +} + diff --git a/source/menu/menus.h b/source/menu/menus.h new file mode 100644 index 0000000..3e2ad91 --- /dev/null +++ b/source/menu/menus.h @@ -0,0 +1,17 @@ +#ifndef _MENUS_H +#define _MENUS_H + +#include "GUI/gui.h" +#include "language/gettext.h" +#include "prompts/PromptWindows.h" +#include "menu.h" +#include "gecko.h" +#include "sys.h" + +extern u8 shutdown; +extern u8 reset; + +int MenuInstall(); +int SelectPartitionMenu(); + +#endif // _MENUS_H diff --git a/source/mload/mload.c b/source/mload/mload.c new file mode 100644 index 0000000..cc51ac9 --- /dev/null +++ b/source/mload/mload.c @@ -0,0 +1,493 @@ +/* mload.c (for PPC) (c) 2009, Hermes + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "mload.h" +#include "gecko.h" + +static const char mload_fs[] ATTRIBUTE_ALIGN(32) = "/dev/mload"; + +static s32 mload_fd = -1; +static s32 hid = -1; + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to init/test if the device is running + +int mload_init() +{ + int n; + + if(hid<0) hid = iosCreateHeap(0x10000); + + if(hid<0) + { + if(mload_fd>=0) + IOS_Close(mload_fd); + + mload_fd=-1; + + return hid; + } + + if(mload_fd>=0) + { + return 0; + } + + for(n=0;n<20;n++) // try 5 seconds + { + mload_fd=IOS_Open(mload_fs, 0); + + if(mload_fd>=0) break; + + usleep(250*1000); + } + + return mload_fd; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to close the device (remember call it when rebooting the IOS!) + +int mload_close() +{ + int ret; + + if(mload_fd<0) return -1; + + ret=IOS_Close(mload_fd); + + mload_fd=-1; + + return ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to get the thread id of mload + +int mload_get_thread_id() +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_MLOAD_THREAD_ID, ":"); + + return ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// get the base and the size of the memory readable/writable to load modules + +int mload_get_load_base(u32 *starlet_base, int *size) +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_GET_LOAD_BASE, ":ii",starlet_base, size); + + return ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// load and run a module from starlet (it need to allocate MEM2 to send the elf file) +// the module must be a elf made with stripios + +int mload_module(void *addr, int len) +{ + int ret; + void *buf=NULL; + + buf= iosAlloc(hid, len); + + if(!buf) + return -1; + + memcpy(buf, addr,len); + + ret = IOS_IoctlvFormat(hid, mload_fd, MLOAD_LOAD_MODULE, ":d", buf, len); + if(ret<0) + return ret; + + ret=IOS_IoctlvFormat(hid, mload_fd, MLOAD_RUN_MODULE, ":"); + + return ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// load a module from the PPC +// the module must be a elf made with stripios + +int mload_elf(void *my_elf, data_elf *data_elf) +{ + int n,m; + int p; + u8 *adr; + u32 elf=(u32) my_elf; + + if(elf & 3) return -1; // aligned to 4 please! + + elfheader *head=(void *) elf; + elfphentry *entries; + + if(head->ident0!=0x7F454C46) return -1; + if(head->ident1!=0x01020161) return -1; + if(head->ident2!=0x01000000) return -1; + + p=head->phoff; + + data_elf->start=(void *) head->entry; + + for(n=0; nphnum; n++) + { + entries=(void *) (elf+p); + p+=sizeof(elfphentry); + + if(entries->type == 4) + { + adr=(void *) (elf + entries->offset); + + if(getbe32(0)!=0) return -2; // bad info (sure) + + for(m=4; (u32)m < entries->memsz; m+=8) + { + switch(getbe32(m)) + { + case 0x9: + data_elf->start= (void *) getbe32(m+4); + break; + case 0x7D: + data_elf->prio= getbe32(m+4); + break; + case 0x7E: + data_elf->size_stack= getbe32(m+4); + break; + case 0x7F: + data_elf->stack= (void *) (getbe32(m+4)); + break; + + } + + } + + } + else + if(entries->type == 1 && entries->memsz != 0 && entries->vaddr!=0) + { + + if(mload_memset((void *) entries->vaddr, 0, entries->memsz)<0) return -1; + if(mload_seek(entries->vaddr, SEEK_SET)<0) return -1; + if(mload_write((void *) (elf + entries->offset), entries->filesz)<0) return -1; + + } + } + + return 0; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// run one thread (you can use to load modules or binary files) + +int mload_run_thread(void *starlet_addr, void *starlet_top_stack, int stack_size, int priority) +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_RUN_THREAD, "iiii:", starlet_addr,starlet_top_stack, stack_size, priority); + + return ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// stops one starlet thread + +int mload_stop_thread(int id) +{ +int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_STOP_THREAD, "i:", id); + +return ret; + +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// continue one stopped starlet thread + +int mload_continue_thread(int id) +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_CONTINUE_THREAD, "i:", id); + + return ret; +} +/*--------------------------------------------------------------------------------------------------------------*/ + +// fix starlet address to read/write (uses SEEK_SET, etc as mode) + +int mload_seek(int offset, int mode) +{ + if(mload_init()<0) return -1; + + return IOS_Seek(mload_fd, offset, mode); +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// read bytes from starlet (it update the offset) + +int mload_read(void* buf, u32 size) +{ + if(mload_init()<0) return -1; + + return IOS_Read(mload_fd, buf, size); +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// write bytes from starlet (it update the offset) + +int mload_write(const void * buf, u32 size) +{ + if(mload_init()<0) return -1; + + return IOS_Write(mload_fd, buf, size); +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// fill a block (similar to memset) + +int mload_memset(void *starlet_addr, int set, int len) +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_MEMSET, "iii:", starlet_addr, set, len); + + return ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// get the ehci datas ( ehcmodule.elf uses this address) + +void * mload_get_ehci_data() +{ + int ret; + + if(mload_init()<0) return NULL; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_GET_EHCI_DATA, ":"); + if(ret<0) return NULL; + + return (void *) ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// set the dev/es ioctlv in routine + +int mload_set_ES_ioctlv_vector(void *starlet_addr) +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_SET_ES_IOCTLV, "i:", starlet_addr); + + return ret; +} + + + +int mload_getw(const void * addr, u32 *dat) +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_GETW, "i:i", addr, dat); + + return ret; +} + +int mload_geth(const void * addr, u16 *dat) +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_GETH, "i:h", addr, dat); + + return ret; +} + +int mload_getb(const void * addr, u8 *dat) +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_GETB, "i:b", addr, dat); + + return ret; +} + +int mload_setw(const void * addr, u32 dat) +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_SETW, "ii:", addr, dat); + + return ret; +} + +int mload_seth(const void * addr, u16 dat) +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_SETH, "ih:", addr, dat); + + return ret; +} + +int mload_setb(const void * addr, u8 dat) +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_SETB, "ib:", addr, dat); + + return ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to get log buffer +// this function return the size of the log buffer and prepare it to read with mload_read() the datas + +int mload_get_log() +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_GET_LOG, ":"); + + return ret; + +} + + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to get IOS base for dev/es to create the cIOS + +int mload_get_IOS_base() +{ + int ret; + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_GET_IOS_BASE, ":"); + + return ret; + +} + + +int mload_get_version() +{ + int ret; + if(mload_init()<0) return -1; + ret = IOS_IoctlvFormat(hid, mload_fd, MLOAD_GET_MLOAD_VERSION, ":"); + return ret; +} + +/* IOS info structure */ +typedef struct { + /* Syscall base */ + u32 syscall; + + /* Module versions */ + u32 dipVersion; + u32 esVersion; + u32 ffsVersion; + u32 iopVersion; +} iosInfo; + +int wanin_mload_get_IOS_base() +{ + int ret; + iosInfo ios; + memset(&ios, 0, sizeof(ios)); + + if(mload_init()<0) return -1; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_GET_IOS_BASE, ":d", &ios, sizeof(ios)); + //gprintf("get_ios_base: %d %x\n", ret, ios.dipVersion); + if (ret == 0) { + switch(ios.dipVersion) { + case 0x48776F72: /* DIP: 07/11/08 14:34:26 */ + return 37; + + case 0x4888E14C: /* DIP: 07/24/08 20:08:44 */ + return 38; + + case 0x4A262AF5: /* DIP: 06/03/09 07:49:09 */ + return 57; + + case 0x492ACA9D: /* DIP: 11/24/08 15:39:09 */ + return 60; + } + } + return ret; +} + +int mload_set_gecko_debug() +{ + int ret; + u32 log_mode = 2; // GECKO + if(mload_init()<0) return -1; + + gprintf("Setting debug mode..."); + ret = IOS_IoctlvFormat(hid, mload_fd, MLOAD_SET_LOG_MODE, ":d", &log_mode, sizeof(log_mode)); + gprintf("%d\n", ret); + return ret; +} diff --git a/source/mload/mload.h b/source/mload/mload.h new file mode 100644 index 0000000..26fd71e --- /dev/null +++ b/source/mload/mload.h @@ -0,0 +1,233 @@ +/* mload.c (for PPC) (c) 2009, Hermes + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __MLOAD_H__ +#define __MLOAD_H__ + + +#include +#include +#include +#include +#include +#include "unistd.h" + +#define MLOAD_MLOAD_THREAD_ID 0x4D4C4400 +#define MLOAD_GET_IOS_BASE 0x4D4C4401 +#define MLOAD_GET_MLOAD_VERSION 0x4D4C4402 + +#define MLOAD_LOAD_MODULE 0x4D4C4480 +#define MLOAD_RUN_MODULE 0x4D4C4481 +#define MLOAD_RUN_THREAD 0x4D4C4482 + +#define MLOAD_STOP_THREAD 0x4D4C4484 +#define MLOAD_CONTINUE_THREAD 0x4D4C4485 + +#define MLOAD_GET_LOAD_BASE 0x4D4C4490 +#define MLOAD_MEMSET 0x4D4C4491 + +#define MLOAD_GET_EHCI_DATA 0x4D4C44A0 +#define MLOAD_GET_LOG 0x4D4C44A1 + +#define MLOAD_SET_ES_IOCTLV 0x4D4C44B0 + +#define MLOAD_GETW 0x4D4C44C0 +#define MLOAD_GETH 0x4D4C44C1 +#define MLOAD_GETB 0x4D4C44C2 +#define MLOAD_SETW 0x4D4C44C3 +#define MLOAD_SETH 0x4D4C44C4 +#define MLOAD_SETB 0x4D4C44C5 + +#define MLOAD_SET_LOG_MODE 0x4D4C44D0 +#define MLOAD_GET_LOG_BUFFER 0x4D4C44D1 + +#ifdef __cplusplus +extern "C" { +#endif + +// from IOS ELF stripper of neimod + +#define getbe32(x) ((adr[x]<<24) | (adr[x+1]<<16) | (adr[x+2]<<8) | (adr[x+3])) + +typedef struct +{ + u32 ident0; + u32 ident1; + u32 ident2; + u32 ident3; + u32 machinetype; + u32 version; + u32 entry; + u32 phoff; + u32 shoff; + u32 flags; + u16 ehsize; + u16 phentsize; + u16 phnum; + u16 shentsize; + u16 shnum; + u16 shtrndx; +} elfheader; + +typedef struct +{ + u32 type; + u32 offset; + u32 vaddr; + u32 paddr; + u32 filesz; + u32 memsz; + u32 flags; + u32 align; +} elfphentry; + +typedef struct +{ + void *start; + int prio; + void *stack; + int size_stack; +} data_elf; + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to init/test if the device is running + +int mload_init(); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to close the device (remember call it when rebooting the IOS!) + +int mload_close(); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to get the thread id of mload + +int mload_get_thread_id(); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// get the base and the size of the memory readable/writable to load modules + +int mload_get_load_base(u32 *starlet_base, int *size); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// load and run a module from starlet (it need to allocate MEM2 to send the elf file) +// the module must be a elf made with stripios + +int mload_module(void *addr, int len); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// load a module from the PPC +// the module must be a elf made with stripios + +int mload_elf(void *my_elf, data_elf *data_elf); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// run one thread (you can use to load modules or binary files) + +int mload_run_thread(void *starlet_addr, void *starlet_top_stack, int stack_size, int priority); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// stops one starlet thread + +int mload_stop_thread(int id); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// continue one stopped starlet thread + +int mload_continue_thread(int id); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// fix starlet address to read/write (uses SEEK_SET, etc as mode) + +int mload_seek(int offset, int mode); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// read bytes from starlet (it update the offset) + +int mload_read(void* buf, u32 size); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// write bytes from starlet (it update the offset) + +int mload_write(const void * buf, u32 size); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// fill a block (similar to memset) + +int mload_memset(void *starlet_addr, int set, int len); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// get the ehci datas ( ehcmodule.elf uses this address) + +void * mload_get_ehci_data(); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// set the dev/es ioctlv in routine + +int mload_set_ES_ioctlv_vector(void *starlet_addr); + +/*--------------------------------------------------------------------------------------------------------------*/ + + +// to get log buffer +// this function return the size of the log buffer and prepare it to read with mload_read() the datas + +int mload_get_log(); + +/*--------------------------------------------------------------------------------------------------------------*/ + + +// to get IOS base for dev/es to create the cIOS + +int mload_get_IOS_base(); + +int mload_get_version(); + +/*--------------------------------------------------------------------------------------------------------------*/ + +int mload_getw(const void * addr, u32 *dat); +int mload_geth(const void * addr, u16 *dat); +int mload_getb(const void * addr, u8 *dat); + +int mload_setw(const void * addr, u32 dat); +int mload_seth(const void * addr, u16 dat); +int mload_setb(const void * addr, u8 dat); + +int wanin_mload_get_IOS_base(); +int mload_set_gecko_debug(); + +#ifdef __cplusplus + } +#endif + + +#endif diff --git a/source/mload/mload_modules.c b/source/mload/mload_modules.c new file mode 100644 index 0000000..b8a7c58 --- /dev/null +++ b/source/mload/mload_modules.c @@ -0,0 +1,230 @@ +#include "mload_modules.h" + +static u32 ios_36[16] ATTRIBUTE_ALIGN(32)= +{ + 0, // DI_EmulateCmd + 0, + 0x2022DDAC, // dvd_read_controlling_data + 0x20201010+1, // handle_di_cmd_reentry (thumb) + 0x20200b9c+1, // ios_shared_alloc_aligned (thumb) + 0x20200b70+1, // ios_shared_free (thumb) + 0x20205dc0+1, // ios_memcpy (thumb) + 0x20200048+1, // ios_fatal_di_error (thumb) + 0x20202b4c+1, // ios_doReadHashEncryptedState (thumb) + 0x20203934+1, // ios_printf (thumb) +}; + +static u32 ios_38[16] ATTRIBUTE_ALIGN(32)= +{ + 0, // DI_EmulateCmd + 0, + 0x2022cdac, // dvd_read_controlling_data + 0x20200d38+1, // handle_di_cmd_reentry (thumb) + 0x202008c4+1, // ios_shared_alloc_aligned (thumb) + 0x20200898+1, // ios_shared_free (thumb) + 0x20205b80+1, // ios_memcpy (thumb) + 0x20200048+1, // ios_fatal_di_error (thumb) + 0x20202874+1, // ios_doReadHashEncryptedState (thumb) + 0x2020365c+1, // ios_printf (thumb) +}; + + +static u32 ios_37[16] ATTRIBUTE_ALIGN(32)= +{ + 0, // DI_EmulateCmd + 0, + 0x2022DD60, // dvd_read_controlling_data + 0x20200F04+1, // handle_di_cmd_reentry (thumb) + 0x2020096C+1, // ios_shared_alloc_aligned (thumb) + 0x2020093C+1, // ios_shared_free (thumb) + 0x20205E54+1, // ios_memcpy (thumb) + 0x20200048+1, // ios_fatal_di_error (thumb) + 0x20202A70+1, // ios_doReadHashEncryptedState (thumb) + 0x2020387C+1, // ios_printf (thumb) +}; + +static u32 ios_57[16] ATTRIBUTE_ALIGN(32)= +{ + 0, // DI_EmulateCmd + 0, + 0x2022cd60, // dvd_read_controlling_data + 0x20200f04+1, // handle_di_cmd_reentry (thumb) + 0x2020096c+1, // ios_shared_alloc_aligned (thumb) // no usado + 0x2020093C+1, // ios_shared_free (thumb) // no usado + 0x20205EF0+1, // ios_memcpy (thumb) + 0x20200048+1, // ios_fatal_di_error (thumb) + 0x20202944+1, // ios_doReadHashEncryptedState (thumb) + 0x20203750+1, // ios_printf (thumb) +}; + +static u32 ios_60[16] ATTRIBUTE_ALIGN(32)= +{ + 0, // DI_EmulateCmd + 0, + 0x2022cd60, // dvd_read_controlling_data + 0x20200f04+1, // handle_di_cmd_reentry (thumb) + 0x2020096c+1, // ios_shared_alloc_aligned (thumb) // no usado + 0x2020093C+1, // ios_shared_free (thumb) // no usado + 0x20205e00+1, // ios_memcpy (thumb) + 0x20200048+1, // ios_fatal_di_error (thumb) + 0x20202944+1, // ios_doReadHashEncryptedState (thumb) + 0x20203750+1, // ios_printf (thumb) +}; + + +static u32 patch_datas[8] ATTRIBUTE_ALIGN(32); +static int my_thread_id = 0; +static data_elf my_data_elf; +static u8 * dip_plugin = NULL; +static u32 dip_plugin_size = 0; + +int load_modules(const u8 * ehcmodule, int ehcmodule_size, const u8 * dip, int dip_size) +{ + if(mload_init() < 0) + return -1; + + dip_plugin = (u8 *) dip; + dip_plugin_size = dip_size; + + mload_elf((u8 *) ehcmodule, &my_data_elf); + my_thread_id= mload_run_thread(my_data_elf.start, my_data_elf.stack, my_data_elf.size_stack, my_data_elf.prio); + + if(my_thread_id < 0) + return -2; + usleep(350*1000); + + // Test for IOS + int is_ios = mload_get_IOS_base(); + u32 dip_address = 0x1377C000; + + switch(is_ios) + { + + case 36: + + memcpy(ios_36, dip_plugin, 4); // copy the entry_point + memcpy(dip_plugin, ios_36, 4*10); // copy the adresses from the array + + mload_seek(dip_address, SEEK_SET); // copy dip_plugin in the starlet + mload_write(dip_plugin, dip_plugin_size); + + // enables DIP plugin + mload_seek(0x20209040, SEEK_SET); + mload_write(ios_36, 4); + break; + + case 37: + + memcpy(ios_37, dip_plugin, 4); // copy the entry_point + memcpy(dip_plugin, ios_37, 4*10); // copy the adresses from the array + + mload_seek(dip_address, SEEK_SET); // copy dip_plugin in the starlet + mload_write(dip_plugin,dip_plugin_size); + + // enables DIP plugin + mload_seek(0x20209030, SEEK_SET); + mload_write(ios_37, 4); + break; + + case 38: + + memcpy(ios_38, dip_plugin, 4); // copy the entry_point + memcpy(dip_plugin, ios_38, 4*10); // copy the adresses from the array + + mload_seek(dip_address, SEEK_SET); // copy dip_plugin in the starlet + mload_write(dip_plugin,dip_plugin_size); + + // enables DIP plugin + mload_seek(0x20208030, SEEK_SET); + mload_write(ios_38, 4); + break; + + case 57: + + memcpy(ios_57, dip_plugin, 4); // copy the entry_point + memcpy(dip_plugin, ios_57, 4*10); // copy the adresses from the array + + mload_seek(dip_address, SEEK_SET); // copy dip_plugin in the starlet + mload_write(dip_plugin,dip_plugin_size); + + // enables DIP plugin + mload_seek(0x20208030, SEEK_SET); + mload_write(ios_57, 4); + break; + + case 60: + + memcpy(ios_60, dip_plugin, 4); // copy the entry_point + memcpy(dip_plugin, ios_60, 4*10); // copy the adresses from the array + + mload_seek(dip_address, SEEK_SET); // copy dip_plugin in the starlet + mload_write(dip_plugin,dip_plugin_size); + + // enables DIP plugin + mload_seek(0x20208030, SEEK_SET); + mload_write(ios_60, 4); + break; + + } + mload_close(); + return 0; +} + +void enable_ES_ioctlv_vector(void) +{ + mload_init(); + patch_datas[0]=*((u32 *) (dip_plugin+16*4)); + mload_set_ES_ioctlv_vector((void *) patch_datas[0]); + mload_close(); +} + +void Set_DIP_BCA_Datas(u8 *bca_data) +{ + // write in dip_plugin bca data area + mload_init(); + mload_seek(*((u32 *) (dip_plugin+15*4)), SEEK_SET); // offset 15 (bca_data area) + mload_write(bca_data, 64); + mload_close(); +} + +u8 *search_for_ehcmodule_cfg(u8 *p, int size) +{ + int n; + + for(n=0;n= 5 && mload_get_version() >= v51) + { + char fs[] ATTRIBUTE_ALIGN(32) = "/dev/mload/OFF"; + // shadow /dev/mload supported in hermes cios v5.1char fs[] ATTRIBUTE_ALIGN(32) = "/dev/usb2"; + IOS_Open(fs,0); + return true; + } + return false; +} diff --git a/source/mload/mload_modules.h b/source/mload/mload_modules.h new file mode 100644 index 0000000..74e4f64 --- /dev/null +++ b/source/mload/mload_modules.h @@ -0,0 +1,23 @@ +#ifndef _MLOAD_MODULES_H_ +#define _MLOAD_MODULES_H_ + +#include "mload.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int load_modules(const u8 * ehcmodule, int ehcmodule_size, const u8 * dip_plugin, int dip_plugin_size); +void enable_ES_ioctlv_vector(void); +void Set_DIP_BCA_Datas(u8 *bca_data); +void disableIOSReload(void); +u8 *search_for_ehcmodule_cfg(u8 *p, int size); +bool shadow_mload(); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/source/mload/modules/dip_plugin_249.c b/source/mload/modules/dip_plugin_249.c new file mode 100644 index 0000000..4f6b211 --- /dev/null +++ b/source/mload/modules/dip_plugin_249.c @@ -0,0 +1,338 @@ +#define size_dip_plugin_249 5340 + +unsigned char dip_plugin_249[5340] __attribute__((aligned (32)))={ + 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x02, 0x01, 0x61, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x13, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x34, 0x00, 0x20, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xa0, 0x00, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xa0, + 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xd4, 0x00, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x08, 0x13, 0x70, 0x00, 0x00, + 0x13, 0x70, 0x00, 0x00, 0x00, 0x00, 0x12, 0xe4, 0x00, 0x00, 0x12, 0xe4, 0x00, 0xf0, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x13, 0xec, 0x13, 0x70, 0x20, 0x00, + 0x13, 0x70, 0x20, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xbd, 0xc0, 0x00, 0xf0, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x13, 0x70, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0x13, 0x70, 0xdd, 0xc0, 0xe3, 0xa0, 0x00, 0x00, 0xe3, 0xa0, 0x10, 0x00, + 0xe5, 0x9f, 0x30, 0x00, 0xe1, 0x2f, 0xff, 0x13, 0x13, 0x70, 0x03, 0x8d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0xf0, 0xb0, 0x89, 0x1c, 0x0d, 0x1c, 0x06, + 0x1c, 0x17, 0x46, 0x68, 0x22, 0x20, 0x21, 0x00, 0xf0, 0x01, 0xf9, 0x0e, 0x23, 0xa8, 0x06, 0x1b, + 0x1c, 0x30, 0x1c, 0x29, 0x93, 0x00, 0x95, 0x01, 0x97, 0x02, 0xf0, 0x00, 0xed, 0x82, 0x1c, 0x31, + 0x1c, 0x2a, 0x46, 0x68, 0xf0, 0x00, 0xf9, 0x0b, 0xb0, 0x09, 0xbd, 0xf0, 0xb5, 0xf0, 0xb0, 0x8d, + 0x90, 0x01, 0x0a, 0xcb, 0x20, 0xa0, 0x27, 0xd0, 0x1c, 0x0d, 0x92, 0x03, 0x93, 0x02, 0x02, 0x00, + 0x26, 0x00, 0xac, 0x04, 0x06, 0x3f, 0xe0, 0x13, 0x22, 0x20, 0x21, 0x00, 0x1c, 0x20, 0xf0, 0x01, + 0xf8, 0xeb, 0x9b, 0x02, 0x98, 0x01, 0x60, 0xe3, 0x9b, 0x03, 0x1c, 0x29, 0x61, 0x23, 0x60, 0x27, + 0xf0, 0x00, 0xed, 0x5e, 0x1c, 0x20, 0x99, 0x01, 0x1c, 0x2a, 0xf0, 0x00, 0xf8, 0xe8, 0x36, 0x01, + 0x23, 0x0f, 0x42, 0xb3, 0xd3, 0x01, 0x28, 0x00, 0xd1, 0xe6, 0xb0, 0x0d, 0xbd, 0xf0, 0xb5, 0xf0, + 0xb0, 0x83, 0x24, 0x80, 0x93, 0x01, 0x01, 0x24, 0x18, 0x53, 0x90, 0x00, 0x1c, 0x0f, 0x1c, 0x16, + 0x42, 0xa3, 0xd8, 0x15, 0x1c, 0x20, 0x21, 0x20, 0xf0, 0x00, 0xe8, 0xa2, 0x1e, 0x05, 0xd0, 0x11, + 0x1c, 0x21, 0x1c, 0x28, 0x9a, 0x01, 0xf7, 0xff, 0xff, 0xc1, 0x1e, 0x04, 0xd1, 0x04, 0x19, 0xa9, + 0x98, 0x00, 0x1c, 0x3a, 0xf0, 0x01, 0xf8, 0x76, 0x1c, 0x28, 0xf0, 0x00, 0xe8, 0x9e, 0xe0, 0x03, + 0x24, 0x65, 0xe0, 0x00, 0x24, 0x16, 0x42, 0x64, 0xb0, 0x03, 0x1c, 0x20, 0xbd, 0xf0, 0x00, 0x00, + 0xb5, 0x10, 0x1c, 0x03, 0x1c, 0x0c, 0x48, 0x0a, 0x1c, 0x19, 0x22, 0x20, 0xf0, 0x01, 0xf8, 0x62, + 0x4b, 0x08, 0x68, 0x1b, 0x07, 0xda, 0xd4, 0x09, 0x2c, 0x00, 0xd0, 0x04, 0x1c, 0x20, 0x49, 0x04, + 0x22, 0x20, 0xf0, 0x01, 0xf8, 0x57, 0x4b, 0x04, 0x68, 0x18, 0xbd, 0x10, 0xe7, 0xfe, 0x46, 0xc0, + 0x0d, 0x00, 0x60, 0x00, 0x0d, 0x00, 0x60, 0x1c, 0x0d, 0x00, 0x60, 0x20, 0xb5, 0x00, 0x23, 0xe3, + 0xb0, 0x89, 0x06, 0x1b, 0x93, 0x00, 0x46, 0x68, 0x23, 0x00, 0x21, 0x00, 0x22, 0x00, 0x93, 0x01, + 0x93, 0x02, 0xf0, 0x00, 0xf8, 0x8c, 0xb0, 0x09, 0xbd, 0x00, 0xb5, 0xf0, 0xb0, 0x87, 0x92, 0x02, + 0x0a, 0x56, 0x23, 0xff, 0x22, 0x80, 0x01, 0x12, 0x03, 0xdb, 0x90, 0x05, 0x91, 0x04, 0x20, 0x00, + 0x27, 0x00, 0x92, 0x00, 0x93, 0x03, 0xe0, 0x30, 0x9a, 0x04, 0x02, 0x73, 0x1b, 0xd4, 0x9a, 0x02, + 0x25, 0x00, 0x42, 0x9a, 0xd9, 0x01, 0x1a, 0xd5, 0x00, 0xad, 0x9b, 0x05, 0x22, 0x80, 0x19, 0xdb, + 0x1c, 0x18, 0x1c, 0x21, 0x01, 0x12, 0x93, 0x01, 0xf0, 0x00, 0xf8, 0x7e, 0x28, 0x00, 0xd0, 0x01, + 0x2d, 0x00, 0xd0, 0x0b, 0x9a, 0x00, 0x19, 0x2b, 0x42, 0x93, 0xd9, 0x00, 0x1b, 0x54, 0x98, 0x01, + 0x1c, 0x21, 0x1c, 0x2a, 0x1c, 0x33, 0xf7, 0xff, 0xff, 0x7a, 0xe0, 0x0a, 0x9b, 0x03, 0x1c, 0x04, + 0x42, 0x98, 0xd9, 0x01, 0x24, 0xff, 0x03, 0xe4, 0x98, 0x01, 0x1c, 0x21, 0x1c, 0x32, 0xf7, 0xff, + 0xff, 0x45, 0x19, 0x65, 0x0a, 0xed, 0x19, 0x76, 0x19, 0x3f, 0x9a, 0x04, 0x42, 0x97, 0xd3, 0xcb, + 0xb0, 0x07, 0xbd, 0xf0, 0xb5, 0x08, 0xf7, 0xff, 0xff, 0x1f, 0xbd, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x2d, 0x40, 0x80, 0xe5, 0x9f, 0x70, 0x7c, + 0xe5, 0x97, 0x70, 0x00, 0xeb, 0x00, 0x00, 0x13, 0xe8, 0xbd, 0x40, 0x80, 0xe1, 0x2f, 0xff, 0x1e, + 0xe9, 0x2d, 0x40, 0x80, 0xe5, 0x9f, 0x70, 0x68, 0xe5, 0x97, 0x70, 0x00, 0xeb, 0x00, 0x00, 0x0d, + 0xe8, 0xbd, 0x40, 0x80, 0xe1, 0x2f, 0xff, 0x1e, 0xe9, 0x2d, 0x40, 0x80, 0xe5, 0x9f, 0x70, 0x54, + 0xe5, 0x97, 0x70, 0x00, 0xeb, 0x00, 0x00, 0x07, 0xe8, 0xbd, 0x40, 0x80, 0xe1, 0x2f, 0xff, 0x1e, + 0xe9, 0x2d, 0x40, 0x80, 0xe5, 0x9f, 0x70, 0x40, 0xe5, 0x97, 0x70, 0x00, 0xeb, 0x00, 0x00, 0x01, + 0xe8, 0xbd, 0x40, 0x80, 0xe1, 0x2f, 0xff, 0x1e, 0xe1, 0x2f, 0xff, 0x17, 0xb5, 0xf0, 0x46, 0x57, + 0x46, 0x46, 0xb4, 0xc0, 0x68, 0x05, 0x46, 0x8a, 0x4b, 0x09, 0x68, 0x1b, 0x47, 0x18, 0xb5, 0xf0, + 0x46, 0x5f, 0x46, 0x56, 0x46, 0x4d, 0x46, 0x44, 0xb4, 0xf0, 0x4b, 0x06, 0x68, 0x1b, 0x47, 0x18, + 0x13, 0x70, 0x21, 0x14, 0x13, 0x70, 0x21, 0x20, 0x13, 0x70, 0x21, 0x24, 0x13, 0x70, 0x21, 0x28, + 0x13, 0x70, 0x21, 0x18, 0x13, 0x70, 0x21, 0x1c, 0xb5, 0x30, 0x1c, 0x03, 0x20, 0x00, 0x06, 0xdc, + 0xd1, 0x17, 0x48, 0x0c, 0x24, 0x00, 0x42, 0x83, 0xd8, 0x02, 0x24, 0xc0, 0x04, 0x64, 0x1a, 0xe4, + 0x20, 0xf0, 0x06, 0x00, 0x18, 0x1d, 0x48, 0x08, 0x42, 0x85, 0xd8, 0x01, 0x4c, 0x07, 0x1a, 0xe4, + 0x20, 0x00, 0x42, 0x94, 0xd3, 0x03, 0x1c, 0x20, 0x42, 0x8c, 0xd9, 0x00, 0x1c, 0x08, 0x3a, 0x01, + 0x43, 0x90, 0xbd, 0x30, 0x01, 0x7f, 0xff, 0xff, 0x03, 0x61, 0x7f, 0xff, 0x13, 0x61, 0x80, 0x00, + 0xb5, 0x08, 0x21, 0x00, 0xf0, 0x00, 0xeb, 0xf4, 0x4b, 0x03, 0x60, 0x18, 0x1e, 0x43, 0x43, 0x03, + 0x17, 0xdb, 0x40, 0x18, 0xbd, 0x08, 0x46, 0xc0, 0x13, 0x70, 0x20, 0x00, 0xb5, 0x08, 0x4b, 0x05, + 0x68, 0x18, 0x28, 0x00, 0xdb, 0x01, 0xf0, 0x00, 0xeb, 0xe8, 0x4a, 0x02, 0x23, 0x01, 0x42, 0x5b, + 0x60, 0x13, 0xbd, 0x08, 0x13, 0x70, 0x20, 0x00, 0xb5, 0x70, 0x4c, 0x0a, 0x1c, 0x05, 0x1c, 0x0e, + 0x68, 0x20, 0x00, 0x91, 0x22, 0x00, 0xf0, 0x00, 0xeb, 0xe4, 0x28, 0x00, 0xdb, 0x08, 0x68, 0x20, + 0x1c, 0x29, 0x1c, 0x32, 0xf0, 0x00, 0xeb, 0xd4, 0x1e, 0x43, 0x43, 0x03, 0x17, 0xdb, 0x40, 0x18, + 0xbd, 0x70, 0x46, 0xc0, 0x13, 0x70, 0x20, 0x00, 0xb5, 0x10, 0xf0, 0x00, 0xec, 0x32, 0xf0, 0x00, + 0xec, 0x36, 0x1c, 0x04, 0x20, 0x01, 0x42, 0x40, 0xf0, 0x00, 0xec, 0x34, 0x4b, 0x04, 0x68, 0x58, + 0xf0, 0x00, 0xf8, 0x22, 0x1c, 0x20, 0xf0, 0x00, 0xec, 0x2e, 0x20, 0x00, 0xbd, 0x10, 0x46, 0xc0, + 0x13, 0x70, 0x21, 0x00, 0xb5, 0x08, 0x48, 0x05, 0xf0, 0x00, 0xfb, 0x32, 0x48, 0x04, 0x21, 0x00, + 0x22, 0x00, 0xf0, 0x00, 0xfb, 0x23, 0x20, 0x00, 0xbd, 0x08, 0x46, 0xc0, 0x13, 0x70, 0x21, 0x00, + 0x13, 0x70, 0x03, 0x41, 0xb5, 0x08, 0x48, 0x03, 0xf0, 0x00, 0xeb, 0xea, 0xf7, 0xff, 0xff, 0xea, + 0xbd, 0x08, 0x46, 0xc0, 0x13, 0x70, 0x20, 0xa8, 0xb5, 0x10, 0x4b, 0x41, 0x42, 0x98, 0xd0, 0x32, + 0x42, 0x98, 0xd8, 0x03, 0x4b, 0x3f, 0x42, 0x98, 0xd1, 0x79, 0xe0, 0x06, 0x4b, 0x3e, 0x42, 0x98, + 0xd0, 0x4f, 0x4b, 0x3e, 0x42, 0x98, 0xd1, 0x72, 0xe0, 0x4b, 0x48, 0x3d, 0x4c, 0x3d, 0x21, 0x04, + 0x60, 0x04, 0xf0, 0x00, 0xeb, 0xea, 0x4b, 0x3c, 0x48, 0x3c, 0x21, 0x04, 0x60, 0x03, 0xf0, 0x00, + 0xeb, 0xe4, 0x48, 0x3b, 0x21, 0x04, 0x60, 0x04, 0xf0, 0x00, 0xeb, 0xde, 0x4b, 0x39, 0x48, 0x3a, + 0x21, 0x04, 0x60, 0x03, 0xf0, 0x00, 0xeb, 0xd8, 0x4b, 0x38, 0x4a, 0x39, 0x60, 0x1a, 0x4a, 0x39, + 0x60, 0x5a, 0x4a, 0x39, 0x60, 0x9a, 0x4a, 0x39, 0x60, 0xda, 0x3a, 0x30, 0x61, 0x1a, 0x4a, 0x38, + 0x61, 0x5a, 0x4a, 0x38, 0xe0, 0x4a, 0x48, 0x38, 0x4c, 0x2a, 0x21, 0x04, 0x60, 0x04, 0xf0, 0x00, + 0xeb, 0xc4, 0x4b, 0x29, 0x48, 0x35, 0x21, 0x04, 0x60, 0x03, 0xf0, 0x00, 0xeb, 0xbe, 0x48, 0x34, + 0x21, 0x04, 0x60, 0x04, 0xf0, 0x00, 0xeb, 0xb8, 0x4b, 0x26, 0x48, 0x32, 0x21, 0x04, 0x60, 0x03, + 0xf0, 0x00, 0xeb, 0xb2, 0x4b, 0x25, 0x4a, 0x30, 0x60, 0x1a, 0x4a, 0x30, 0x60, 0x5a, 0x4a, 0x30, + 0x60, 0x9a, 0x4a, 0x30, 0x60, 0xda, 0x3a, 0x2c, 0x61, 0x1a, 0x4a, 0x2f, 0x61, 0x5a, 0x4a, 0x2f, + 0xe0, 0x24, 0x48, 0x17, 0x4c, 0x17, 0x21, 0x04, 0x60, 0x04, 0xf0, 0x00, 0xeb, 0x9e, 0x4b, 0x16, + 0x48, 0x16, 0x21, 0x04, 0x60, 0x03, 0xf0, 0x00, 0xeb, 0x98, 0x48, 0x15, 0x21, 0x04, 0x60, 0x04, + 0xf0, 0x00, 0xeb, 0x92, 0x4b, 0x13, 0x48, 0x14, 0x21, 0x04, 0x60, 0x03, 0xf0, 0x00, 0xeb, 0x8c, + 0x4b, 0x12, 0x4a, 0x23, 0x60, 0x1a, 0x4a, 0x13, 0x60, 0x5a, 0x4a, 0x13, 0x60, 0x9a, 0x4a, 0x13, + 0x60, 0xda, 0x3a, 0x30, 0x61, 0x1a, 0x4a, 0x1f, 0x61, 0x5a, 0x4a, 0x1f, 0x61, 0x9a, 0xbd, 0x10, + 0x48, 0x88, 0xe1, 0x4c, 0x48, 0x77, 0x6f, 0x72, 0x49, 0x2a, 0xca, 0x9d, 0x4a, 0x26, 0x2a, 0xf5, + 0x20, 0x20, 0x04, 0x00, 0x4b, 0x00, 0x47, 0x18, 0x13, 0x70, 0x09, 0x45, 0x20, 0x20, 0x04, 0x04, + 0x20, 0x20, 0x0e, 0xf8, 0x13, 0x70, 0x06, 0x55, 0x20, 0x20, 0x0e, 0xfc, 0x13, 0x70, 0x21, 0x14, + 0x20, 0x20, 0x2a, 0x71, 0x20, 0x20, 0x04, 0x0d, 0x20, 0x20, 0x0f, 0x05, 0x20, 0x20, 0x09, 0x6d, + 0x20, 0x20, 0x38, 0x7d, 0x20, 0x22, 0xdd, 0x60, 0x20, 0x20, 0x03, 0xb8, 0x20, 0x20, 0x03, 0xbc, + 0x20, 0x20, 0x0d, 0x2c, 0x20, 0x20, 0x0d, 0x30, 0x20, 0x20, 0x28, 0x75, 0x20, 0x20, 0x03, 0xc5, + 0x20, 0x20, 0x0d, 0x39, 0x20, 0x20, 0x08, 0xc5, 0x20, 0x20, 0x36, 0x5d, 0x20, 0x22, 0xcd, 0xac, + 0x20, 0x20, 0x29, 0x45, 0x20, 0x20, 0x37, 0x51, 0x20, 0x22, 0xcd, 0x60, 0xb5, 0x00, 0x4b, 0x0b, + 0x68, 0x5b, 0x2b, 0x01, 0xd0, 0x02, 0x2b, 0x02, 0xd1, 0x0c, 0xe0, 0x01, 0x4a, 0x08, 0xe0, 0x00, + 0x4a, 0x08, 0x23, 0x00, 0x42, 0x90, 0xd3, 0x06, 0x4b, 0x04, 0x4a, 0x07, 0x61, 0x1a, 0x23, 0xa0, + 0x02, 0x1b, 0xe0, 0x00, 0x23, 0x00, 0x1c, 0x18, 0xbd, 0x00, 0x46, 0xc0, 0x13, 0x70, 0x21, 0x30, + 0x46, 0x09, 0x00, 0x00, 0x7e, 0xd3, 0x80, 0x00, 0x00, 0x05, 0x21, 0x00, 0xb5, 0x70, 0x1c, 0x04, + 0x1c, 0x10, 0x1c, 0x0d, 0x1c, 0x16, 0xf7, 0xff, 0xff, 0xd9, 0x28, 0x00, 0xd1, 0x25, 0x4b, 0x13, + 0x68, 0xd9, 0x68, 0x9a, 0x68, 0x1b, 0x18, 0x8a, 0x19, 0x92, 0x06, 0xd9, 0xd5, 0x04, 0x1c, 0x20, + 0x1c, 0x29, 0xf0, 0x00, 0xfd, 0xd5, 0xe0, 0x18, 0x07, 0x19, 0xd5, 0x04, 0x1c, 0x20, 0x1c, 0x29, + 0xf7, 0xff, 0xfe, 0xba, 0xe0, 0x11, 0x07, 0x59, 0xd5, 0x04, 0x1c, 0x20, 0x1c, 0x29, 0xf0, 0x00, + 0xfb, 0x55, 0xe0, 0x0a, 0x07, 0xd9, 0xd5, 0x04, 0x1c, 0x20, 0x1c, 0x29, 0xf7, 0xff, 0xfd, 0xcd, + 0xe0, 0x03, 0x1c, 0x20, 0x1c, 0x29, 0xf7, 0xff, 0xfe, 0x0d, 0xbd, 0x70, 0x13, 0x70, 0x21, 0x30, + 0xb5, 0x10, 0x22, 0x00, 0x1c, 0x04, 0xf7, 0xff, 0xff, 0xc9, 0x28, 0x00, 0xdb, 0x0d, 0x69, 0xa2, + 0x4b, 0x06, 0x42, 0x9a, 0xd1, 0x09, 0x4b, 0x06, 0x21, 0x01, 0x68, 0x1a, 0x70, 0x11, 0x68, 0x1b, + 0x78, 0x5b, 0x2b, 0x00, 0xd1, 0x01, 0xf7, 0xff, 0xee, 0x00, 0xbd, 0x10, 0x5d, 0x1c, 0x9e, 0xa3, + 0x13, 0x70, 0x21, 0x2c, 0xb5, 0x10, 0x20, 0x80, 0x01, 0x00, 0x21, 0x20, 0xf7, 0xff, 0xee, 0x00, + 0x1e, 0x04, 0xd0, 0x0f, 0x21, 0x80, 0x22, 0xa0, 0x1c, 0x20, 0x01, 0x09, 0x05, 0xd2, 0xf7, 0xff, + 0xff, 0xa5, 0x1e, 0x43, 0x41, 0x98, 0x23, 0x02, 0x1a, 0x18, 0x4b, 0x03, 0x60, 0x58, 0x1c, 0x20, + 0xf7, 0xff, 0xed, 0xfa, 0xbd, 0x10, 0x46, 0xc0, 0x13, 0x70, 0x21, 0x30, 0x4b, 0x06, 0x21, 0x03, + 0x68, 0x1a, 0x43, 0x8a, 0x60, 0x1a, 0x22, 0x00, 0x60, 0x9a, 0x60, 0xda, 0x60, 0x5a, 0x61, 0x1a, + 0x61, 0x5a, 0x61, 0x9a, 0x47, 0x70, 0x46, 0xc0, 0x13, 0x70, 0x21, 0x30, 0xb5, 0xf0, 0xb0, 0x83, + 0x78, 0x03, 0x1c, 0x06, 0x1c, 0x0f, 0x92, 0x00, 0x2b, 0xe0, 0xd1, 0x00, 0xe0, 0xd4, 0x4c, 0xb4, + 0x22, 0x00, 0x61, 0x22, 0x2b, 0xe4, 0xd1, 0x00, 0xe0, 0xb5, 0x2b, 0xe4, 0xd8, 0x2a, 0x2b, 0xa8, + 0xd1, 0x00, 0xe0, 0x98, 0x2b, 0xa8, 0xd8, 0x10, 0x2b, 0x8a, 0xd0, 0x51, 0x2b, 0x8a, 0xd8, 0x05, + 0x2b, 0x70, 0xd0, 0x60, 0x2b, 0x71, 0xd0, 0x00, 0xe1, 0x48, 0xe0, 0x81, 0x2b, 0x8d, 0xd1, 0x00, + 0xe0, 0x89, 0x2b, 0xa4, 0xd0, 0x00, 0xe1, 0x41, 0xe0, 0xa4, 0x2b, 0xd9, 0xd1, 0x00, 0xe0, 0x8d, + 0x2b, 0xd9, 0xd8, 0x06, 0x2b, 0xab, 0xd1, 0x00, 0xe0, 0x95, 0x2b, 0xd0, 0xd0, 0x00, 0xe1, 0x35, + 0xe0, 0x79, 0x2b, 0xdb, 0xd1, 0x00, 0xe0, 0xa0, 0x2b, 0xdb, 0xd3, 0x7b, 0x2b, 0xe0, 0xd0, 0x00, + 0xe1, 0x2c, 0xe0, 0xa1, 0x2b, 0xf6, 0xd1, 0x00, 0xe1, 0x1e, 0x2b, 0xf6, 0xd8, 0x12, 0x2b, 0xf2, + 0xd1, 0x00, 0xe0, 0xaa, 0x2b, 0xf2, 0xd8, 0x06, 0x2b, 0xf0, 0xd1, 0x00, 0xe0, 0xa0, 0x2b, 0xf1, + 0xd0, 0x00, 0xe1, 0x1b, 0xe0, 0x9f, 0x2b, 0xf4, 0xd1, 0x00, 0xe0, 0xad, 0x2b, 0xf4, 0xd9, 0x00, + 0xe0, 0xbf, 0xe0, 0xa6, 0x2b, 0xf9, 0xd1, 0x00, 0xe0, 0xd7, 0x2b, 0xf9, 0xd8, 0x06, 0x2b, 0xf7, + 0xd1, 0x00, 0xe0, 0xb9, 0x2b, 0xf8, 0xd0, 0x00, 0xe1, 0x08, 0xe0, 0xca, 0x2b, 0xfb, 0xd1, 0x00, + 0xe0, 0xf3, 0x2b, 0xfb, 0xd2, 0x00, 0xe0, 0xed, 0x2b, 0xff, 0xd0, 0x00, 0xe0, 0xfe, 0xe0, 0xf6, + 0x69, 0xa3, 0x25, 0x00, 0x2b, 0x00, 0xd0, 0x00, 0xe0, 0xff, 0xf7, 0xff, 0xff, 0x7f, 0x68, 0x22, + 0x23, 0x1c, 0x42, 0x1a, 0xd1, 0x00, 0xe0, 0xf1, 0xf7, 0xff, 0xfc, 0xf8, 0x69, 0x62, 0x23, 0x04, + 0x43, 0x13, 0x61, 0x63, 0xe0, 0xf1, 0x68, 0xa3, 0x68, 0xe2, 0x25, 0x00, 0x43, 0x1a, 0x92, 0x01, + 0x68, 0x22, 0x23, 0x1c, 0x42, 0x1a, 0xd1, 0x09, 0x9a, 0x00, 0xf7, 0xff, 0xfd, 0x80, 0x1e, 0x05, + 0xd0, 0x04, 0x4b, 0x73, 0x22, 0x01, 0x68, 0x19, 0x43, 0x0a, 0x60, 0x1a, 0x4b, 0x70, 0x68, 0x1a, + 0x23, 0x1d, 0x40, 0x13, 0x9a, 0x01, 0x43, 0x1a, 0xd0, 0x04, 0x1c, 0x38, 0x99, 0x00, 0xf7, 0xff, + 0xff, 0x1f, 0x1c, 0x05, 0x2d, 0x00, 0xd0, 0x00, 0xe0, 0xcf, 0xf7, 0xff, 0xff, 0x33, 0xe0, 0xcc, + 0x68, 0x23, 0x07, 0x9a, 0xd4, 0x00, 0xe0, 0xc1, 0x68, 0x41, 0x68, 0x82, 0x1c, 0x38, 0xf7, 0xff, + 0xfe, 0xdd, 0x1c, 0x05, 0xe0, 0xc1, 0x68, 0x71, 0x68, 0xb2, 0x2b, 0xd0, 0xd1, 0xf6, 0x02, 0xc9, + 0x02, 0x52, 0xe7, 0xf3, 0x1c, 0x08, 0x22, 0x40, 0x99, 0x00, 0xe7, 0xf0, 0x68, 0x22, 0x23, 0x1d, + 0x42, 0x1a, 0xd1, 0x00, 0xe0, 0xaa, 0x68, 0x43, 0x68, 0x82, 0x07, 0x9b, 0x43, 0x13, 0x0b, 0xdb, + 0x03, 0xdb, 0x60, 0xe3, 0xe0, 0xa8, 0x68, 0x22, 0x23, 0x1d, 0x25, 0x00, 0x42, 0x1a, 0xd0, 0x00, + 0xe0, 0xa3, 0xe0, 0x9b, 0x68, 0x22, 0x23, 0x1d, 0x42, 0x1a, 0xd1, 0x00, 0xe0, 0x96, 0x4a, 0x51, + 0x4b, 0x4f, 0x25, 0xa0, 0x61, 0x1a, 0x02, 0x2d, 0xe0, 0x97, 0x68, 0x21, 0x23, 0x1c, 0x42, 0x19, + 0xd1, 0x00, 0xe0, 0x8b, 0x60, 0x3a, 0xe0, 0x8f, 0x4b, 0x49, 0x22, 0x1c, 0x68, 0x19, 0x42, 0x11, + 0xd1, 0x03, 0x69, 0x1b, 0x2b, 0x00, 0xd1, 0x00, 0xe0, 0x80, 0x4b, 0x45, 0x69, 0x1b, 0xe0, 0x6a, + 0x68, 0x43, 0x60, 0xa3, 0xe0, 0x80, 0x68, 0xa3, 0xe0, 0x65, 0x68, 0x43, 0x2b, 0x00, 0xd0, 0x03, + 0x68, 0x22, 0x23, 0x02, 0x43, 0x13, 0xe0, 0x02, 0x68, 0x23, 0x22, 0x02, 0x43, 0x93, 0x60, 0x23, + 0xe0, 0x72, 0x68, 0x23, 0x22, 0x02, 0xe0, 0x2e, 0x68, 0x47, 0xf0, 0x00, 0xf9, 0xf1, 0x68, 0x23, + 0x22, 0x04, 0x43, 0x93, 0x60, 0x23, 0x25, 0x00, 0x2f, 0x00, 0xd0, 0x66, 0x1c, 0x31, 0x1e, 0x78, + 0x31, 0x08, 0xf0, 0x00, 0xf9, 0xb9, 0x1e, 0x05, 0xd1, 0x5f, 0x4b, 0x31, 0x22, 0x04, 0x68, 0x19, + 0xe0, 0x3d, 0x68, 0x23, 0x22, 0x04, 0xe0, 0x16, 0x68, 0x46, 0xf7, 0xff, 0xfd, 0x37, 0x68, 0x23, + 0x22, 0x08, 0x43, 0x93, 0x60, 0x23, 0x25, 0x00, 0x2e, 0x00, 0xd0, 0x4e, 0x1c, 0x30, 0xf0, 0x00, + 0xe9, 0x9a, 0xf7, 0xff, 0xfd, 0x1d, 0x1e, 0x05, 0xd1, 0x47, 0x4b, 0x25, 0x22, 0x08, 0x68, 0x19, + 0xe0, 0x25, 0x68, 0x23, 0x22, 0x08, 0x40, 0x13, 0xe0, 0x25, 0x68, 0x43, 0x68, 0x82, 0x93, 0x00, + 0x92, 0x01, 0x68, 0xc6, 0xf0, 0x00, 0xfa, 0xc4, 0x68, 0x23, 0x22, 0x10, 0x43, 0x93, 0x60, 0x23, + 0x9b, 0x01, 0x2b, 0x00, 0xd0, 0x30, 0x9a, 0x00, 0x2a, 0x00, 0xd0, 0x2d, 0x25, 0x00, 0x2e, 0x00, + 0xd0, 0x2b, 0x1c, 0x18, 0xf0, 0x00, 0xe9, 0x76, 0x1c, 0x32, 0x1c, 0x01, 0x98, 0x00, 0xf0, 0x00, + 0xfa, 0xd9, 0x60, 0x38, 0x28, 0x00, 0xdd, 0x20, 0x4b, 0x11, 0x22, 0x10, 0x68, 0x19, 0x43, 0x0a, + 0x60, 0x1a, 0xe0, 0x1a, 0x68, 0x23, 0x60, 0x3b, 0xe0, 0x16, 0x4b, 0x0f, 0x60, 0x0b, 0x68, 0x23, + 0x60, 0x4b, 0x68, 0x63, 0x60, 0x8b, 0xe0, 0x0f, 0x68, 0x43, 0x61, 0xa3, 0xe0, 0x0c, 0x68, 0x40, + 0xf0, 0x00, 0xe9, 0x58, 0x1c, 0x39, 0xf7, 0xff, 0xfb, 0xeb, 0xe7, 0x42, 0x1c, 0x30, 0x1c, 0x39, + 0x9a, 0x00, 0xf7, 0xff, 0xfc, 0x9c, 0xe7, 0x3c, 0x25, 0x00, 0xb0, 0x03, 0x1c, 0x28, 0xbd, 0xf0, + 0x13, 0x70, 0x21, 0x30, 0x00, 0x05, 0x31, 0x00, 0x48, 0x45, 0x4c, 0x4f, 0xb5, 0x38, 0x1c, 0x03, + 0x68, 0x1a, 0x68, 0xc0, 0x2a, 0x86, 0xd0, 0x19, 0x2a, 0x86, 0xd8, 0x04, 0x2a, 0x79, 0xd0, 0x07, + 0x2a, 0x7a, 0xd1, 0x2d, 0xe0, 0x0b, 0x2a, 0x88, 0xd0, 0x1b, 0x2a, 0x95, 0xd1, 0x28, 0xe0, 0x20, + 0x4a, 0x15, 0x20, 0x01, 0x68, 0x14, 0x22, 0x1c, 0x42, 0x14, 0xd1, 0x24, 0xe0, 0x20, 0x4a, 0x12, + 0x24, 0x1c, 0x68, 0x15, 0x42, 0x25, 0xd0, 0x1b, 0x69, 0x53, 0xe0, 0x10, 0x4a, 0x0e, 0x20, 0x1c, + 0x68, 0x14, 0x42, 0x04, 0xd0, 0x14, 0x69, 0x53, 0x21, 0x04, 0x43, 0x8b, 0x61, 0x53, 0x20, 0x01, + 0xe0, 0x11, 0x4a, 0x09, 0x68, 0x14, 0x22, 0x1c, 0x42, 0x14, 0xd0, 0x09, 0x23, 0x02, 0x60, 0x03, + 0xe7, 0xf5, 0x4a, 0x05, 0x68, 0x14, 0x22, 0x1c, 0x42, 0x14, 0xd0, 0x01, 0x23, 0x0a, 0xe7, 0xf6, + 0x1c, 0x18, 0xf7, 0xff, 0xfc, 0x4b, 0xbd, 0x38, 0x13, 0x70, 0x21, 0x30, 0xb5, 0x38, 0x1c, 0x05, + 0x1c, 0x0c, 0x1c, 0x13, 0x1c, 0x29, 0x1c, 0x22, 0x20, 0x10, 0xf0, 0x00, 0xe8, 0xf8, 0xbd, 0x38, + 0xb5, 0x08, 0x1c, 0x01, 0x22, 0x00, 0x20, 0x12, 0x23, 0x00, 0xf0, 0x00, 0xe8, 0xf0, 0xbd, 0x08, + 0xe6, 0x00, 0x00, 0x10, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x00, 0x30, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x00, 0x50, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x00, 0x70, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x00, 0x90, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x00, 0xb0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x00, 0xd0, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x00, 0xf0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x01, 0x10, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x01, 0x30, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x01, 0x50, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x01, 0x70, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x01, 0x90, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x01, 0xb0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x01, 0xd0, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x01, 0xf0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x02, 0x10, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x02, 0x30, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x02, 0x50, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x02, 0x70, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x02, 0x90, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x02, 0xb0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x02, 0xd0, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x02, 0xf0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x03, 0x10, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x03, 0x30, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x03, 0x50, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x03, 0x70, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x03, 0x90, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x03, 0xb0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x03, 0xd0, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x03, 0xf0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x04, 0x10, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x04, 0x30, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x04, 0x50, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x04, 0x70, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x04, 0x90, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x04, 0xb0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x04, 0xd0, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x04, 0xf0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x05, 0x10, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x05, 0x30, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x05, 0x50, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x06, 0x90, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x07, 0xf0, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x08, 0x10, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x09, 0xf0, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x0a, 0x10, 0xe1, 0x2f, 0xff, 0x1e, + 0xe1, 0xa0, 0x20, 0x0e, 0xe2, 0x90, 0x10, 0x00, 0xe3, 0xb0, 0x00, 0x04, 0xef, 0x00, 0x00, 0xab, + 0xe1, 0x2f, 0xff, 0x12, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x9f, 0xc0, 0x54, 0xe5, 0x9c, 0xc0, 0x00, + 0xe1, 0xa0, 0x00, 0x00, 0xe7, 0x9c, 0xc1, 0x0b, 0xe1, 0xa0, 0x00, 0x00, 0xe1, 0x2f, 0xff, 0x1c, + 0xe3, 0xa0, 0xb0, 0x3f, 0xea, 0xff, 0xff, 0xf7, 0xe3, 0xa0, 0xb0, 0x40, 0xea, 0xff, 0xff, 0xf5, + 0xe3, 0xa0, 0x00, 0x00, 0xee, 0x07, 0x0f, 0x15, 0xe1, 0x2f, 0xff, 0x1e, 0xee, 0x13, 0x0f, 0x10, + 0xe1, 0x2f, 0xff, 0x1e, 0xee, 0x03, 0x0f, 0x10, 0xe1, 0x2f, 0xff, 0x1e, 0xef, 0x00, 0x00, 0xcc, + 0xe1, 0x2f, 0xff, 0x1e, 0xe3, 0xc0, 0x01, 0x02, 0xe1, 0x2f, 0xff, 0x1e, 0xe3, 0x80, 0x01, 0x02, + 0xe1, 0x2f, 0xff, 0x1e, 0x13, 0x70, 0x21, 0x00, 0xb5, 0x70, 0xb0, 0x82, 0x4b, 0x10, 0x00, 0x80, + 0x58, 0xc0, 0x1c, 0x0e, 0x21, 0x01, 0xf7, 0xff, 0xef, 0x6c, 0x4b, 0x0e, 0x1c, 0x05, 0x60, 0x18, + 0x28, 0x00, 0xdb, 0x11, 0x4c, 0x0c, 0x1c, 0x31, 0x1c, 0x20, 0x22, 0x06, 0xf0, 0x00, 0xfa, 0xe2, + 0x23, 0x06, 0x64, 0x63, 0x64, 0x24, 0x1c, 0x28, 0x34, 0x40, 0x49, 0x08, 0x22, 0x01, 0x23, 0x00, + 0x94, 0x00, 0xf7, 0xff, 0xef, 0x6e, 0x1c, 0x05, 0xb0, 0x02, 0x1c, 0x28, 0xbd, 0x70, 0x46, 0xc0, + 0x13, 0x70, 0x20, 0xa0, 0x13, 0x70, 0x20, 0x04, 0x13, 0x70, 0x21, 0x60, 0x57, 0x46, 0x53, 0x01, + 0xb5, 0x08, 0x4b, 0x05, 0x68, 0x18, 0x28, 0x00, 0xdb, 0x01, 0xf7, 0xff, 0xef, 0x46, 0x4a, 0x02, + 0x23, 0x01, 0x42, 0x5b, 0x60, 0x13, 0xbd, 0x08, 0x13, 0x70, 0x20, 0x04, 0xb5, 0xf0, 0xb0, 0x83, + 0x4c, 0x14, 0x23, 0x04, 0x60, 0x22, 0x1c, 0x26, 0x1c, 0x22, 0x32, 0x20, 0x36, 0x40, 0x64, 0x63, + 0x64, 0xa2, 0x64, 0xe3, 0x62, 0x21, 0x65, 0x20, 0x65, 0x61, 0x64, 0x24, 0x1c, 0x07, 0x1c, 0x0d, + 0x1c, 0x30, 0x21, 0x20, 0xf7, 0xff, 0xef, 0x68, 0x1c, 0x20, 0x21, 0x24, 0xf7, 0xff, 0xef, 0x64, + 0x4b, 0x09, 0x49, 0x0a, 0x68, 0x18, 0x22, 0x02, 0x23, 0x01, 0x96, 0x00, 0xf7, 0xff, 0xef, 0x30, + 0x1e, 0x04, 0xd1, 0x03, 0x1c, 0x38, 0x1c, 0x29, 0xf7, 0xff, 0xef, 0x52, 0xb0, 0x03, 0x1c, 0x20, + 0xbd, 0xf0, 0x46, 0xc0, 0x13, 0x70, 0x21, 0x60, 0x13, 0x70, 0x20, 0x04, 0x57, 0x46, 0x53, 0x02, + 0xb5, 0x70, 0xb0, 0x82, 0x1c, 0x03, 0x48, 0x1c, 0x68, 0x04, 0x20, 0x00, 0x2c, 0x00, 0xdb, 0x31, + 0x4e, 0x1a, 0x60, 0x33, 0x23, 0x04, 0x62, 0x73, 0x62, 0xf3, 0x6b, 0xb3, 0x60, 0x71, 0x43, 0x59, + 0x1c, 0x34, 0x1d, 0x30, 0x34, 0x20, 0x62, 0x36, 0x62, 0xb0, 0x63, 0x32, 0x63, 0x71, 0x1c, 0x25, + 0x36, 0x38, 0x68, 0x28, 0x68, 0x69, 0xf7, 0xff, 0xef, 0x30, 0x35, 0x08, 0x42, 0xb5, 0xd1, 0xf8, + 0x4d, 0x0e, 0x21, 0x18, 0x35, 0x20, 0x1c, 0x28, 0xf7, 0xff, 0xef, 0x26, 0x4b, 0x0a, 0x49, 0x0c, + 0x68, 0x18, 0x22, 0x02, 0x23, 0x01, 0x95, 0x00, 0xf7, 0xff, 0xee, 0xf2, 0x1c, 0x03, 0x20, 0x00, + 0x2b, 0x00, 0xdb, 0x07, 0x68, 0x20, 0x68, 0x61, 0xf7, 0xff, 0xef, 0x12, 0x34, 0x08, 0x42, 0xb4, + 0xd1, 0xf8, 0x20, 0x01, 0xb0, 0x02, 0xbd, 0x70, 0x13, 0x70, 0x20, 0x20, 0x13, 0x70, 0x21, 0xc0, + 0x55, 0x4d, 0x53, 0x03, 0xb5, 0x30, 0xb0, 0x83, 0x4c, 0x0e, 0x25, 0x00, 0x68, 0x23, 0x2b, 0x00, + 0xda, 0x14, 0x1c, 0x20, 0x30, 0x20, 0x21, 0x01, 0xf7, 0xff, 0xee, 0xba, 0x60, 0x20, 0x28, 0x00, + 0xdb, 0x0a, 0x22, 0x00, 0x23, 0x00, 0x49, 0x08, 0x95, 0x00, 0xf7, 0xff, 0xee, 0xca, 0x4a, 0x07, + 0x23, 0x80, 0x00, 0x9b, 0x63, 0x93, 0xe0, 0x01, 0x25, 0x0b, 0x42, 0x6d, 0xb0, 0x03, 0x1c, 0x28, + 0xbd, 0x30, 0x46, 0xc0, 0x13, 0x70, 0x20, 0x20, 0x55, 0x4d, 0x53, 0x01, 0x13, 0x70, 0x21, 0xc0, + 0xb5, 0x30, 0xb0, 0x83, 0x4c, 0x0d, 0x25, 0x00, 0x68, 0x23, 0x2b, 0x00, 0xda, 0x13, 0x1c, 0x20, + 0x30, 0x20, 0x21, 0x01, 0xf7, 0xff, 0xee, 0x94, 0x60, 0x20, 0x28, 0x00, 0xdb, 0x09, 0x23, 0x00, + 0x21, 0x01, 0x22, 0x00, 0x95, 0x00, 0xf7, 0xff, 0xee, 0xa4, 0x23, 0x80, 0x00, 0x9b, 0x63, 0x23, + 0xe0, 0x01, 0x25, 0x0b, 0x42, 0x6d, 0xb0, 0x03, 0x1c, 0x28, 0xbd, 0x30, 0x13, 0x70, 0x20, 0x60, + 0xb5, 0x70, 0xb0, 0x82, 0x4c, 0x1c, 0x1c, 0x03, 0x68, 0x25, 0x20, 0x00, 0x2d, 0x00, 0xdb, 0x31, + 0x4e, 0x1a, 0x60, 0x33, 0x23, 0x04, 0x62, 0x73, 0x62, 0xf3, 0x6b, 0x23, 0x60, 0x71, 0x43, 0x59, + 0x1c, 0x34, 0x1d, 0x30, 0x34, 0x20, 0x62, 0x36, 0x62, 0xb0, 0x63, 0x32, 0x63, 0x71, 0x1c, 0x25, + 0x36, 0x38, 0x68, 0x28, 0x68, 0x69, 0xf7, 0xff, 0xee, 0xa8, 0x35, 0x08, 0x42, 0xb5, 0xd1, 0xf8, + 0x4d, 0x0e, 0x21, 0x18, 0x35, 0x20, 0x1c, 0x28, 0xf7, 0xff, 0xee, 0x9e, 0x4b, 0x0a, 0x21, 0x02, + 0x68, 0x18, 0x22, 0x02, 0x23, 0x01, 0x95, 0x00, 0xf7, 0xff, 0xee, 0x6a, 0x1c, 0x03, 0x20, 0x00, + 0x2b, 0x00, 0xdb, 0x07, 0x68, 0x20, 0x68, 0x61, 0xf7, 0xff, 0xee, 0x8a, 0x34, 0x08, 0x42, 0xb4, + 0xd1, 0xf8, 0x20, 0x01, 0xb0, 0x02, 0xbd, 0x70, 0x13, 0x70, 0x20, 0x60, 0x13, 0x70, 0x22, 0x00, + 0x4b, 0x02, 0x22, 0x00, 0x60, 0x1a, 0x60, 0x5a, 0x60, 0x9a, 0x47, 0x70, 0x13, 0x70, 0x22, 0x40, + 0xb5, 0xf0, 0x48, 0x0f, 0x21, 0xa0, 0x68, 0x44, 0x23, 0x00, 0x30, 0x0c, 0x22, 0x00, 0x00, 0x89, + 0x03, 0xd6, 0xe0, 0x01, 0x04, 0x2b, 0x0c, 0x1b, 0x00, 0x5d, 0x18, 0xed, 0x00, 0xad, 0x19, 0x65, + 0x69, 0x6f, 0x68, 0xed, 0x19, 0x7d, 0x42, 0xae, 0xd3, 0x03, 0x68, 0x67, 0x1c, 0x5d, 0x42, 0xbd, + 0xd3, 0xf0, 0x32, 0x01, 0x80, 0x03, 0x30, 0x02, 0x42, 0x8a, 0xd1, 0xe9, 0xbd, 0xf0, 0x46, 0xc0, + 0x13, 0x70, 0x22, 0x40, 0xb5, 0xf8, 0x4b, 0x20, 0x1c, 0x06, 0x68, 0x1b, 0x1c, 0x0f, 0x1c, 0x15, + 0x2b, 0x00, 0xd0, 0x01, 0xf7, 0xff, 0xff, 0xcc, 0x1e, 0x73, 0x2b, 0x01, 0xd8, 0x2e, 0x2d, 0x00, + 0xd0, 0x2c, 0x4b, 0x1a, 0x42, 0x9d, 0xd8, 0x2b, 0x4c, 0x19, 0x2e, 0x01, 0xd1, 0x02, 0xf7, 0xff, + 0xff, 0x39, 0xe0, 0x01, 0xf7, 0xff, 0xff, 0x5c, 0x4b, 0x15, 0x60, 0xe0, 0x68, 0xd8, 0x28, 0x00, + 0xd1, 0x20, 0x4c, 0x11, 0x33, 0x10, 0x60, 0x63, 0x60, 0xa6, 0x1c, 0x38, 0x1c, 0x29, 0xf7, 0xff, + 0xee, 0x30, 0x68, 0x66, 0x21, 0x00, 0x4a, 0x0d, 0x1c, 0x30, 0xf0, 0x00, 0xf9, 0xad, 0x1c, 0x2a, + 0x1c, 0x39, 0x1c, 0x30, 0xf0, 0x00, 0xf9, 0x66, 0x1c, 0x38, 0x1c, 0x29, 0xf7, 0xff, 0xee, 0x24, + 0xf7, 0xff, 0xff, 0xa6, 0x23, 0x01, 0x60, 0x23, 0x1c, 0x28, 0xe0, 0x03, 0x20, 0x01, 0xe0, 0x00, + 0x20, 0x02, 0x42, 0x40, 0xbd, 0xf8, 0x46, 0xc0, 0x13, 0x70, 0x22, 0x40, 0x00, 0x00, 0xa4, 0x1c, + 0x13, 0x70, 0x27, 0x40, 0xb5, 0xf0, 0xb0, 0x83, 0x4d, 0x33, 0x24, 0xa0, 0x0b, 0xcf, 0x00, 0xa4, + 0x9e, 0x09, 0x62, 0xef, 0x42, 0xa7, 0xd9, 0x01, 0x4c, 0x30, 0x62, 0xec, 0x4d, 0x2e, 0x4f, 0x30, + 0x6a, 0xec, 0x46, 0x9c, 0x00, 0x64, 0x19, 0x3c, 0x89, 0xa4, 0x63, 0x2c, 0x63, 0x6c, 0x00, 0x67, + 0x68, 0x45, 0x19, 0x3f, 0x00, 0xbf, 0x95, 0x00, 0x19, 0xc7, 0x18, 0x55, 0x37, 0x0c, 0x95, 0x01, + 0xe0, 0x35, 0x68, 0x3d, 0x42, 0x8d, 0xd8, 0x18, 0x68, 0xbb, 0x18, 0xeb, 0x42, 0x8b, 0xd9, 0x2c, + 0x4f, 0x21, 0x1b, 0x4d, 0x46, 0x63, 0x63, 0x7c, 0x63, 0xbd, 0x60, 0x19, 0x00, 0x63, 0x19, 0x1c, + 0x00, 0xa4, 0x19, 0x00, 0x69, 0x03, 0x99, 0x08, 0x18, 0xeb, 0x60, 0x0b, 0x69, 0x43, 0x20, 0x00, + 0x1b, 0x5d, 0x60, 0x35, 0x42, 0x95, 0xd9, 0x2d, 0xe0, 0x15, 0x9b, 0x01, 0x42, 0x9d, 0xd2, 0x14, + 0x4f, 0x15, 0x46, 0x63, 0x1a, 0x69, 0x63, 0x7c, 0x63, 0xb9, 0x60, 0x1d, 0x00, 0x63, 0x19, 0x1c, + 0x00, 0xa4, 0x19, 0x00, 0x69, 0x03, 0x9c, 0x08, 0x1a, 0x52, 0x60, 0x23, 0x69, 0x43, 0x20, 0x00, + 0x60, 0x33, 0x42, 0x93, 0xd9, 0x16, 0x60, 0x32, 0xe0, 0x14, 0x34, 0x01, 0x37, 0x0c, 0x9d, 0x00, + 0x42, 0xac, 0xd3, 0xc6, 0x4d, 0x08, 0x18, 0x51, 0x68, 0x02, 0x46, 0x63, 0x63, 0x6c, 0x42, 0x91, + 0xd8, 0x06, 0x60, 0x19, 0x99, 0x08, 0x23, 0x00, 0x60, 0x0b, 0x20, 0x00, 0x60, 0x33, 0xe0, 0x01, + 0x20, 0x02, 0x42, 0x40, 0xb0, 0x03, 0xbd, 0xf0, 0x13, 0x70, 0xcb, 0x40, 0x00, 0x00, 0x02, 0x7f, + 0x13, 0x70, 0x22, 0x40, 0xb5, 0xf0, 0xb0, 0x85, 0x1c, 0x07, 0x1c, 0x0e, 0x92, 0x02, 0x4d, 0x28, + 0xe0, 0x43, 0x4a, 0x28, 0x4b, 0x28, 0x68, 0x50, 0x93, 0x00, 0x1c, 0x2b, 0x33, 0x44, 0x93, 0x01, + 0x1c, 0x39, 0x9a, 0x02, 0x4b, 0x25, 0xf7, 0xff, 0xff, 0x7d, 0x64, 0xa8, 0x28, 0x00, 0xd1, 0x3d, + 0x6b, 0xeb, 0x1b, 0xdb, 0x93, 0x03, 0x64, 0xeb, 0x2b, 0x00, 0xd0, 0x0b, 0x02, 0x5c, 0x1c, 0x30, + 0x1c, 0x22, 0x21, 0x00, 0xf0, 0x00, 0xf9, 0x00, 0x9a, 0x03, 0x9b, 0x02, 0x18, 0xbf, 0x1a, 0x9b, + 0x19, 0x36, 0x93, 0x02, 0x4c, 0x16, 0x6c, 0x61, 0x29, 0x00, 0xd0, 0x18, 0x4b, 0x15, 0x68, 0x9b, + 0x2b, 0x01, 0xd1, 0x04, 0x6c, 0x20, 0x1c, 0x32, 0xf7, 0xff, 0xfe, 0x22, 0xe0, 0x03, 0x6c, 0x20, + 0x1c, 0x32, 0xf7, 0xff, 0xfe, 0xa5, 0x4b, 0x0e, 0x64, 0xa0, 0x6c, 0x9a, 0x2a, 0x00, 0xd0, 0x11, + 0x6c, 0x5b, 0x02, 0x5a, 0x18, 0xb6, 0x9a, 0x02, 0x18, 0xff, 0x1a, 0xd2, 0x92, 0x02, 0x4b, 0x08, + 0x6c, 0x5a, 0x6c, 0xdb, 0x18, 0xd3, 0x2b, 0x00, 0xd0, 0x06, 0x9b, 0x02, 0x2b, 0x00, 0xd1, 0xb8, + 0x20, 0x00, 0xe0, 0x03, 0x20, 0x03, 0xe0, 0x00, 0x20, 0x04, 0x42, 0x40, 0xb0, 0x05, 0xbd, 0xf0, + 0x13, 0x70, 0xcb, 0x40, 0x13, 0x70, 0x22, 0x40, 0x13, 0x70, 0xcb, 0x80, 0x13, 0x70, 0xcb, 0x7c, + 0xb5, 0xf8, 0x24, 0x7f, 0x1c, 0x0f, 0x1c, 0x1e, 0x09, 0xc1, 0x4b, 0x17, 0x40, 0x20, 0x24, 0x80, + 0x00, 0x80, 0x00, 0xa4, 0x1a, 0x24, 0x65, 0x19, 0x65, 0x58, 0x65, 0x9c, 0x42, 0x94, 0xd9, 0x00, + 0x65, 0x9a, 0x4a, 0x11, 0x23, 0x80, 0x6d, 0x90, 0x00, 0x9b, 0x42, 0x98, 0xd1, 0x01, 0x23, 0x00, + 0x65, 0x93, 0x4c, 0x0d, 0x6d, 0xa3, 0x2b, 0x00, 0xd0, 0x10, 0x1c, 0x25, 0x35, 0x60, 0x1c, 0x08, + 0x22, 0x01, 0x1c, 0x29, 0xf7, 0xff, 0xff, 0x7e, 0x4b, 0x08, 0x66, 0x18, 0x28, 0x00, 0xd1, 0x09, + 0x6d, 0x61, 0x6d, 0xa2, 0x18, 0x69, 0x1c, 0x38, 0xf0, 0x00, 0xf8, 0x54, 0x4b, 0x02, 0x20, 0x00, + 0x6d, 0x9b, 0x60, 0x33, 0xbd, 0xf8, 0x46, 0xc0, 0x13, 0x70, 0xcb, 0x40, 0x13, 0x70, 0xcd, 0x40, + 0xb5, 0xf0, 0xb0, 0x83, 0x4c, 0x21, 0x91, 0x01, 0x1c, 0x06, 0x1c, 0x23, 0x1c, 0x10, 0x1c, 0x17, + 0x33, 0x64, 0x1c, 0x31, 0x9a, 0x01, 0xf7, 0xff, 0xff, 0xbb, 0x1c, 0x05, 0x66, 0xa0, 0x28, 0x00, + 0xd1, 0x31, 0x6e, 0x63, 0x08, 0x9a, 0x18, 0xbf, 0x9a, 0x01, 0x18, 0xf6, 0x96, 0x00, 0x1a, 0xd6, + 0x4b, 0x17, 0x42, 0x9e, 0xd9, 0x11, 0x09, 0xf8, 0x0a, 0x72, 0x66, 0xe0, 0x67, 0x22, 0x99, 0x00, + 0xf7, 0xff, 0xff, 0x48, 0x66, 0xa0, 0x28, 0x00, 0xd1, 0x19, 0x6f, 0x23, 0x01, 0xda, 0x18, 0xbf, + 0x9a, 0x00, 0x02, 0x5b, 0x18, 0xd2, 0x1a, 0xf6, 0x92, 0x00, 0x2e, 0x00, 0xd0, 0x13, 0x4c, 0x0b, + 0x1c, 0x38, 0x1c, 0x23, 0x33, 0x64, 0x99, 0x00, 0x1c, 0x32, 0xf7, 0xff, 0xff, 0x91, 0x1c, 0x05, + 0x66, 0xa0, 0x28, 0x00, 0xd1, 0x07, 0x6e, 0x63, 0x42, 0x9e, 0xd1, 0x02, 0xe0, 0x03, 0x1c, 0x05, + 0xe0, 0x01, 0x25, 0x05, 0x42, 0x6d, 0xb0, 0x03, 0x1c, 0x28, 0xbd, 0xf0, 0x13, 0x70, 0xcd, 0x40, + 0x00, 0x00, 0x01, 0xff, 0xb5, 0xf0, 0x1c, 0x05, 0x1c, 0x0e, 0x1c, 0x14, 0x2a, 0x0f, 0xd9, 0x03, + 0x1c, 0x0b, 0x43, 0x03, 0x07, 0x9f, 0xd0, 0x0a, 0x2c, 0x00, 0xd0, 0x05, 0x23, 0x00, 0x5c, 0xf2, + 0x54, 0xea, 0x33, 0x01, 0x42, 0xa3, 0xd1, 0xfa, 0xbc, 0xf0, 0xbc, 0x02, 0x47, 0x08, 0x1c, 0x15, + 0x1c, 0x0c, 0x1c, 0x03, 0x68, 0x26, 0x60, 0x1e, 0x68, 0x66, 0x60, 0x5e, 0x68, 0xa6, 0x60, 0x9e, + 0x68, 0xe6, 0x3d, 0x10, 0x60, 0xde, 0x34, 0x10, 0x33, 0x10, 0x2d, 0x0f, 0xd8, 0xf2, 0x3a, 0x10, + 0x09, 0x17, 0x1c, 0x7e, 0x01, 0x3f, 0x01, 0x36, 0x1b, 0xd7, 0x19, 0x85, 0x1c, 0x3c, 0x19, 0x8e, + 0x2f, 0x03, 0xd9, 0xd9, 0x1c, 0x34, 0x1c, 0x3b, 0x1c, 0x2a, 0xcc, 0x02, 0x3b, 0x04, 0xc2, 0x02, + 0x2b, 0x03, 0xd8, 0xfa, 0x3f, 0x04, 0x08, 0xbc, 0x1c, 0x63, 0x00, 0x9b, 0x00, 0xa4, 0x18, 0xed, + 0x18, 0xf6, 0x1b, 0x3c, 0xe7, 0xc8, 0x46, 0xc0, 0xb5, 0x70, 0x1c, 0x03, 0x07, 0x84, 0xd0, 0x0d, + 0x2a, 0x00, 0xd0, 0x40, 0x06, 0x0d, 0x3a, 0x01, 0x0e, 0x2d, 0x24, 0x03, 0xe0, 0x02, 0x2a, 0x00, + 0xd0, 0x39, 0x3a, 0x01, 0x70, 0x1d, 0x33, 0x01, 0x42, 0x23, 0xd1, 0xf8, 0x2a, 0x03, 0xd9, 0x29, + 0x25, 0xff, 0x40, 0x0d, 0x02, 0x2c, 0x43, 0x25, 0x04, 0x2c, 0x1c, 0x1e, 0x43, 0x25, 0x2a, 0x0f, + 0xd9, 0x12, 0x1c, 0x1c, 0x1c, 0x16, 0x3e, 0x10, 0x60, 0x25, 0x60, 0x65, 0x60, 0xa5, 0x60, 0xe5, + 0x34, 0x10, 0x2e, 0x0f, 0xd8, 0xf7, 0x3a, 0x10, 0x09, 0x16, 0x36, 0x01, 0x01, 0x36, 0x19, 0x9e, + 0x23, 0x0f, 0x40, 0x1a, 0x2a, 0x03, 0xd9, 0x0c, 0x1c, 0x34, 0x1c, 0x13, 0x3b, 0x04, 0xc4, 0x20, + 0x2b, 0x03, 0xd8, 0xfb, 0x3a, 0x04, 0x08, 0x93, 0x33, 0x01, 0x00, 0x9b, 0x18, 0xf6, 0x23, 0x03, + 0x40, 0x1a, 0x1c, 0x33, 0x2a, 0x00, 0xd0, 0x06, 0x06, 0x09, 0x0e, 0x0c, 0x21, 0x00, 0x54, 0x5c, + 0x31, 0x01, 0x42, 0x8a, 0xd1, 0xfb, 0xbc, 0x70, 0xbc, 0x02, 0x47, 0x08, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x64, 0x65, 0x76, + 0x2f, 0x75, 0x73, 0x62, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x64, 0x65, 0x76, + 0x2f, 0x73, 0x64, 0x69, 0x6f, 0x2f, 0x73, 0x64, 0x68, 0x63, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x70, 0x20, 0xd6, + 0x13, 0x70, 0x20, 0xe0, 0x24, 0x49, 0x4f, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, + 0x20, 0x44, 0x49, 0x50, 0x50, 0x3a, 0x20, 0x53, 0x65, 0x70, 0x20, 0x20, 0x37, 0x20, 0x32, 0x30, + 0x31, 0x30, 0x20, 0x31, 0x32, 0x3a, 0x32, 0x33, 0x3a, 0x31, 0x34, 0x20, 0x36, 0x34, 0x4d, 0x24, + 0x0a, 0x00, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x75, 0x73, 0x62, 0x32, 0x00, 0x2f, 0x64, 0x65, 0x76, + 0x2f, 0x73, 0x64, 0x69, 0x6f, 0x2f, 0x73, 0x64, 0x68, 0x63, 0x00, 0x00 +}; diff --git a/source/mload/modules/dip_plugin_249.h b/source/mload/modules/dip_plugin_249.h new file mode 100644 index 0000000..ceaf4f9 --- /dev/null +++ b/source/mload/modules/dip_plugin_249.h @@ -0,0 +1,16 @@ +#ifndef DIP_PLUGIN249_H_ +#define DIP_PLUGIN249_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned char dip_plugin_249[5340]; + +#define dip_plugin_249_size sizeof(dip_plugin_249) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/mload/modules/ehcmodule_5.c b/source/mload/modules/ehcmodule_5.c new file mode 100644 index 0000000..d87302d --- /dev/null +++ b/source/mload/modules/ehcmodule_5.c @@ -0,0 +1,977 @@ +#define size_ehcmodule_5 27134 + +unsigned char ehcmodule_5[27134] __attribute__((aligned (32)))={ + 127, 69, 76, 70, 1, 2, 1, 97, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 40, 0, 0, 0, 1, 19, 112, 0, 0, 0, 0, 0, 52, 0, 0, 0, + 0, 0, 0, 6, 6, 0, 52, 0, 32, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, + 0, 0, 0, 160, 0, 240, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 212, 0, 0, 0, 160, 0, 0, 0, 160, 0, 0, 0, 52, 0, 0, 0, + 52, 0, 240, 0, 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 212, 0, 240, 0, + 0, 0, 0, 64, 0, 0, 0, 0, 1, 0, 0, 1, 8, 19, 112, 0, 0, 19, 112, 0, 0, 0, 0, 94, 48, 0, 0, 94, 48, 0, 240, 0, 5, 0, 0, + 0, 4, 0, 0, 0, 1, 0, 0, 95, 56, 19, 112, 96, 0, 19, 112, 96, 0, 0, 0, 10, 198, 0, 2, 154, 20, 0, 240, 0, 6, 0, 0, 0, + 4, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 6, 0, 0, 0, 11, 0, 0, 0, 4, 0, 0, 0, 9, 19, 112, 0, 0, 0, 0, 0, 125, 0, 0, 0, 120, + 0, 0, 0, 126, 0, 0, 48, 0, 0, 0, 0, 127, 19, 114, 248, 20, 227, 160, 0, 0, 227, 160, 16, 0, 229, 159, 49, 0, 225, 47, + 255, 19, 229, 159, 192, 252, 229, 156, 192, 0, 225, 160, 0, 0, 231, 156, 193, 11, 225, 160, 0, 0, 225, 47, 255, 28, + 225, 160, 0, 0, 225, 160, 0, 0, 227, 160, 176, 63, 234, 255, 255, 245, 225, 160, 0, 0, 225, 160, 0, 0, 227, 160, 176, + 64, 234, 255, 255, 241, 227, 160, 0, 0, 238, 7, 15, 21, 225, 47, 255, 30, 225, 160, 0, 0, 225, 160, 0, 0, 225, 160, + 0, 0, 227, 24, 0, 16, 10, 0, 0, 18, 227, 200, 128, 16, 227, 160, 32, 16, 229, 135, 32, 0, 225, 160, 0, 0, 225, 160, + 32, 13, 225, 160, 0, 0, 229, 159, 208, 144, 225, 160, 0, 0, 233, 45, 95, 254, 225, 160, 0, 0, 235, 0, 0, 15, 232, 189, + 95, 254, 225, 160, 0, 0, 225, 160, 208, 2, 227, 16, 0, 1, 10, 0, 0, 2, 225, 160, 0, 0, 227, 160, 0, 4, 235, 0, 0, 5, + 227, 24, 0, 1, 10, 0, 0, 1, 229, 159, 240, 88, 225, 160, 0, 0, 229, 159, 240, 84, 225, 160, 0, 0, 229, 159, 240, 80, + 225, 160, 0, 0, 229, 159, 32, 76, 225, 47, 255, 18, 225, 160, 0, 0, 238, 19, 15, 16, 225, 47, 255, 30, 225, 160, 0, + 0, 225, 160, 0, 0, 238, 3, 15, 16, 225, 47, 255, 30, 225, 160, 0, 0, 225, 160, 0, 0, 69, 72, 67, 95, 67, 70, 71, 0, + 18, 52, 0, 1, 0, 0, 0, 0, 19, 112, 17, 61, 19, 114, 195, 160, 19, 114, 250, 20, 255, 255, 30, 128, 255, 255, 30, 156, + 255, 255, 29, 68, 19, 112, 13, 221, 225, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 181, 0, 40, 2, 208, + 16, 40, 2, 216, 4, 40, 0, 208, 7, 40, 1, 209, 19, 224, 7, 40, 16, 208, 12, 40, 17, 209, 14, 224, 11, 75, 8, 104, 24, + 224, 11, 72, 7, 224, 9, 75, 7, 34, 1, 96, 26, 32, 0, 224, 4, 72, 6, 224, 2, 72, 6, 224, 0, 72, 6, 188, 2, 71, 8, 19, + 112, 96, 48, 19, 112, 76, 109, 19, 112, 106, 232, 19, 112, 68, 253, 19, 112, 70, 133, 255, 255, 253, 102, 181, 112, + 28, 12, 28, 5, 240, 5, 253, 211, 28, 6, 32, 1, 66, 64, 240, 5, 253, 210, 14, 43, 115, 35, 12, 43, 115, 99, 10, 43, 115, + 163, 124, 34, 124, 99, 6, 18, 4, 27, 67, 19, 124, 162, 115, 229, 2, 18, 67, 19, 124, 226, 6, 45, 67, 19, 28, 32, 96, + 29, 48, 12, 33, 4, 240, 5, 253, 216, 124, 35, 124, 96, 6, 27, 4, 0, 67, 24, 124, 163, 33, 4, 2, 27, 67, 24, 124, 227, + 67, 24, 240, 5, 253, 203, 28, 48, 240, 5, 253, 170, 32, 0, 188, 112, 188, 2, 71, 8, 181, 8, 75, 12, 28, 1, 34, 32, 104, + 24, 240, 5, 253, 249, 40, 0, 209, 13, 72, 9, 240, 5, 254, 4, 240, 4, 254, 15, 32, 200, 240, 0, 255, 113, 240, 4, 254, + 20, 32, 200, 240, 0, 255, 108, 231, 244, 188, 8, 188, 2, 71, 8, 19, 112, 96, 48, 19, 112, 96, 84, 181, 8, 75, 4, 28, + 1, 104, 24, 240, 5, 253, 118, 188, 8, 188, 1, 71, 0, 70, 192, 19, 112, 96, 48, 181, 240, 176, 139, 144, 4, 145, 5, 28, + 8, 28, 17, 28, 23, 146, 7, 240, 5, 253, 156, 76, 129, 104, 35, 43, 0, 209, 0, 224, 241, 168, 9, 240, 3, 255, 34, 75, + 126, 96, 24, 40, 0, 208, 4, 35, 128, 154, 9, 1, 27, 66, 154, 208, 4, 35, 1, 74, 122, 66, 91, 96, 19, 224, 224, 78, 121, + 72, 122, 104, 51, 24, 26, 42, 0, 208, 104, 43, 0, 219, 102, 75, 116, 104, 26, 28, 81, 209, 98, 28, 53, 75, 112, 104, + 48, 104, 28, 33, 31, 34, 16, 52, 31, 24, 18, 67, 140, 146, 2, 33, 16, 28, 34, 240, 4, 249, 24, 40, 0, 209, 0, 224, 195, + 120, 35, 43, 67, 209, 11, 120, 99, 43, 73, 209, 8, 120, 163, 43, 83, 209, 5, 120, 227, 43, 79, 209, 2, 75, 103, 96, + 51, 224, 8, 104, 43, 43, 0, 208, 2, 35, 0, 96, 43, 231, 218, 35, 1, 66, 91, 96, 43, 121, 98, 121, 163, 2, 18, 4, 27, + 24, 211, 121, 34, 77, 95, 24, 155, 121, 226, 28, 40, 6, 18, 24, 155, 10, 219, 147, 3, 154, 3, 75, 91, 33, 0, 96, 26, + 34, 128, 1, 18, 240, 5, 252, 63, 75, 84, 104, 26, 75, 85, 66, 154, 209, 30, 32, 7, 35, 0, 70, 132, 70, 102, 64, 30, + 209, 4, 16, 218, 152, 2, 73, 82, 0, 146, 80, 80, 24, 226, 122, 18, 42, 0, 208, 10, 16, 218, 92, 168, 33, 1, 64, 177, + 67, 8, 84, 168, 154, 2, 28, 16, 154, 3, 24, 128, 144, 2, 34, 128, 51, 1, 1, 210, 66, 147, 209, 227, 75, 63, 34, 31, + 104, 27, 153, 5, 51, 31, 67, 147, 34, 128, 2, 18, 147, 3, 145, 2, 78, 60, 146, 6, 224, 97, 155, 4, 32, 15, 10, 93, 104, + 51, 67, 133, 66, 157, 208, 63, 73, 56, 75, 57, 104, 10, 96, 53, 66, 154, 209, 33, 75, 57, 28, 40, 104, 28, 28, 33, 240, + 5, 252, 185, 75, 55, 8, 193, 0, 138, 88, 210, 35, 0, 147, 1, 35, 7, 64, 24, 70, 140, 35, 0, 144, 0, 224, 9, 72, 47, + 70, 97, 92, 64, 28, 1, 65, 25, 32, 1, 66, 8, 208, 0, 25, 18, 51, 1, 153, 0, 66, 139, 211, 242, 60, 1, 64, 44, 25, 21, + 75, 34, 104, 28, 27, 100, 44, 16, 220, 10, 44, 16, 208, 9, 34, 128, 152, 3, 33, 0, 2, 18, 240, 5, 251, 210, 44, 0, 221, + 8, 224, 0, 36, 16, 28, 40, 28, 33, 154, 3, 240, 4, 248, 113, 40, 0, 208, 29, 154, 4, 152, 6, 4, 209, 12, 73, 26, 67, + 28, 60, 66, 187, 216, 0, 28, 28, 154, 3, 152, 2, 24, 137, 28, 34, 240, 5, 251, 118, 152, 2, 28, 33, 240, 5, 252, 176, + 155, 2, 152, 4, 25, 27, 27, 63, 16, 164, 25, 0, 147, 2, 144, 4, 47, 0, 209, 155, 224, 5, 32, 128, 2, 0, 176, 11, 188, + 240, 188, 2, 71, 8, 152, 5, 153, 7, 240, 5, 252, 163, 32, 0, 231, 245, 70, 192, 19, 112, 107, 116, 19, 112, 106, 240, + 19, 112, 96, 24, 19, 112, 96, 12, 128, 0, 0, 1, 127, 255, 255, 255, 19, 112, 123, 160, 19, 112, 106, 244, 19, 112, 131, + 160, 181, 56, 28, 12, 240, 5, 252, 162, 30, 5, 209, 38, 44, 0, 208, 36, 104, 34, 42, 0, 208, 33, 120, 17, 120, 83, 6, + 9, 4, 27, 67, 11, 120, 145, 2, 9, 67, 11, 120, 209, 67, 11, 43, 6, 209, 21, 123, 17, 123, 83, 6, 9, 4, 27, 67, 11, 123, + 145, 2, 9, 67, 11, 123, 209, 67, 11, 43, 122, 208, 2, 43, 136, 209, 7, 224, 2, 72, 5, 33, 21, 224, 1, 72, 4, 33, 20, + 240, 4, 252, 154, 28, 40, 188, 56, 188, 2, 71, 8, 70, 192, 19, 112, 1, 153, 181, 240, 176, 145, 75, 206, 33, 128, 120, + 27, 36, 1, 147, 8, 75, 205, 104, 24, 240, 5, 252, 75, 33, 32, 240, 5, 252, 48, 144, 6, 240, 0, 251, 207, 240, 5, 252, + 25, 33, 120, 240, 5, 252, 72, 153, 6, 72, 198, 240, 5, 252, 6, 72, 197, 154, 6, 28, 1, 35, 0, 240, 5, 252, 94, 73, 195, + 28, 7, 32, 205, 240, 4, 252, 21, 33, 0, 145, 9, 145, 7, 145, 5, 152, 6, 169, 15, 34, 0, 240, 5, 252, 68, 144, 14, 155, + 14, 43, 0, 209, 246, 44, 0, 208, 2, 28, 56, 240, 5, 252, 79, 74, 185, 158, 15, 35, 0, 96, 19, 46, 0, 209, 93, 75, 183, + 104, 27, 43, 0, 208, 5, 75, 182, 104, 27, 43, 0, 209, 1, 74, 181, 96, 19, 155, 5, 36, 0, 43, 0, 208, 221, 75, 178, 104, + 27, 43, 0, 208, 217, 75, 175, 104, 27, 43, 0, 209, 213, 75, 175, 104, 27, 43, 0, 208, 9, 240, 3, 254, 179, 40, 0, 208, + 5, 240, 3, 254, 175, 40, 0, 208, 1, 240, 3, 254, 171, 75, 168, 104, 27, 147, 4, 43, 0, 209, 41, 77, 166, 75, 167, 104, + 42, 58, 1, 66, 154, 216, 35, 78, 158, 76, 165, 35, 1, 33, 1, 96, 51, 104, 32, 74, 163, 240, 3, 255, 137, 153, 4, 96, + 49, 40, 0, 208, 14, 75, 161, 104, 26, 75, 161, 0, 146, 88, 211, 43, 0, 209, 7, 32, 128, 4, 64, 104, 41, 240, 5, 251, + 143, 104, 35, 24, 192, 96, 32, 75, 151, 74, 155, 104, 25, 104, 18, 66, 145, 211, 1, 34, 0, 96, 26, 75, 142, 36, 0, 104, + 27, 43, 0, 209, 147, 28, 56, 73, 135, 240, 5, 251, 241, 36, 1, 231, 141, 120, 51, 120, 112, 6, 27, 4, 0, 67, 24, 120, + 179, 2, 27, 67, 24, 120, 243, 67, 24, 56, 1, 40, 6, 217, 0, 227, 2, 240, 5, 248, 237, 0, 10, 0, 74, 3, 1, 3, 1, 3, 1, + 0, 7, 0, 93, 38, 1, 37, 1, 227, 0, 123, 51, 123, 116, 6, 27, 4, 36, 67, 28, 123, 179, 73, 116, 2, 27, 67, 28, 123, 243, + 67, 28, 28, 32, 240, 5, 250, 221, 40, 0, 209, 11, 125, 51, 125, 117, 6, 27, 4, 45, 67, 29, 125, 179, 2, 27, 67, 29, + 125, 243, 38, 1, 67, 29, 226, 228, 28, 32, 73, 119, 240, 5, 250, 203, 40, 0, 208, 0, 226, 214, 125, 51, 125, 117, 6, + 27, 4, 45, 67, 29, 125, 179, 34, 1, 2, 27, 67, 29, 125, 243, 38, 1, 67, 29, 75, 100, 96, 26, 75, 100, 96, 24, 72, 109, + 240, 0, 251, 121, 75, 109, 34, 4, 104, 27, 104, 155, 96, 154, 240, 1, 248, 110, 34, 0, 146, 5, 226, 192, 122, 50, 122, + 115, 6, 18, 4, 27, 67, 19, 122, 178, 153, 7, 2, 18, 67, 19, 122, 242, 67, 19, 66, 153, 209, 0, 226, 175, 240, 1, 248, + 115, 38, 1, 37, 0, 226, 173, 126, 51, 126, 116, 6, 27, 4, 36, 67, 28, 126, 179, 124, 50, 2, 27, 67, 28, 126, 243, 6, + 18, 67, 28, 124, 115, 4, 27, 67, 19, 124, 178, 2, 18, 67, 19, 124, 242, 67, 26, 146, 4, 125, 51, 125, 117, 6, 27, 4, + 45, 67, 29, 125, 179, 154, 7, 2, 27, 67, 29, 125, 243, 67, 29, 42, 0, 209, 16, 123, 51, 43, 0, 209, 13, 122, 50, 122, + 115, 122, 176, 6, 18, 4, 27, 67, 19, 2, 0, 67, 3, 122, 240, 67, 24, 240, 1, 248, 79, 28, 6, 224, 0, 38, 0, 155, 4, 28, + 32, 25, 91, 0, 217, 147, 11, 240, 5, 251, 23, 33, 0, 28, 37, 145, 10, 224, 7, 104, 40, 104, 105, 240, 5, 251, 15, 154, + 10, 53, 8, 50, 1, 146, 10, 155, 10, 153, 11, 66, 139, 219, 243, 72, 45, 104, 1, 41, 0, 208, 0, 226, 63, 154, 15, 123, + 21, 123, 83, 6, 45, 4, 27, 67, 43, 123, 149, 2, 45, 67, 43, 123, 213, 67, 43, 77, 50, 66, 171, 209, 0, 225, 32, 66, + 171, 216, 33, 43, 6, 216, 12, 43, 5, 211, 0, 225, 247, 43, 1, 209, 0, 224, 165, 43, 0, 209, 0, 224, 124, 43, 2, 208, + 0, 225, 88, 225, 237, 43, 27, 216, 7, 38, 0, 43, 26, 211, 0, 224, 175, 43, 12, 208, 0, 225, 78, 224, 162, 74, 35, 66, + 147, 209, 0, 224, 169, 50, 1, 66, 147, 208, 0, 225, 69, 224, 238, 77, 32, 66, 171, 209, 0, 224, 218, 66, 171, 216, 71, + 74, 30, 66, 147, 209, 0, 224, 190, 66, 147, 216, 56, 58, 12, 66, 147, 209, 0, 225, 34, 50, 2, 66, 147, 208, 0, 225, + 48, 225, 37, 19, 112, 1, 12, 19, 112, 96, 48, 19, 112, 96, 109, 0, 152, 150, 128, 19, 112, 1, 65, 19, 112, 107, 12, + 19, 112, 106, 228, 19, 112, 106, 232, 19, 112, 96, 20, 19, 112, 107, 108, 19, 114, 200, 12, 0, 0, 15, 255, 19, 112, + 106, 224, 19, 112, 107, 160, 19, 112, 107, 104, 19, 112, 107, 44, 19, 114, 200, 16, 19, 112, 96, 121, 19, 112, 21, 229, + 19, 112, 96, 60, 85, 77, 83, 3, 85, 77, 83, 1, 85, 77, 83, 130, 85, 77, 83, 16, 74, 208, 66, 147, 209, 0, 224, 247, + 50, 1, 66, 147, 208, 0, 224, 247, 224, 130, 73, 205, 66, 139, 209, 0, 225, 100, 66, 139, 216, 8, 73, 203, 66, 139, 209, + 0, 224, 124, 73, 202, 66, 139, 208, 0, 224, 232, 224, 233, 74, 200, 66, 147, 209, 0, 225, 51, 50, 1, 66, 147, 208, 0, + 224, 223, 225, 34, 46, 0, 209, 0, 225, 116, 105, 162, 105, 35, 136, 21, 106, 34, 136, 27, 136, 16, 104, 34, 2, 25, 10, + 27, 120, 18, 67, 11, 2, 41, 10, 45, 67, 13, 146, 10, 4, 45, 104, 162, 12, 45, 120, 18, 149, 0, 2, 5, 10, 0, 67, 40, + 4, 0, 12, 0, 144, 1, 107, 32, 4, 27, 144, 2, 12, 27, 28, 48, 153, 10, 240, 1, 251, 132, 224, 10, 46, 0, 209, 0, 225, + 78, 104, 35, 28, 48, 120, 25, 104, 163, 136, 26, 105, 35, 240, 1, 251, 100, 28, 5, 38, 1, 225, 117, 104, 35, 105, 34, + 120, 24, 104, 163, 120, 25, 105, 163, 240, 0, 255, 121, 231, 243, 37, 1, 225, 106, 152, 8, 240, 3, 250, 131, 28, 5, + 40, 2, 216, 8, 40, 2, 208, 2, 34, 1, 40, 0, 209, 0, 34, 0, 75, 159, 96, 26, 224, 3, 34, 0, 146, 5, 40, 0, 219, 3, 75, + 157, 34, 1, 96, 26, 146, 5, 155, 15, 122, 25, 122, 90, 6, 9, 4, 18, 67, 10, 122, 153, 122, 219, 2, 9, 67, 10, 67, 19, + 147, 7, 231, 206, 75, 148, 37, 0, 96, 25, 240, 3, 250, 47, 38, 1, 149, 5, 225, 62, 104, 35, 104, 26, 75, 144, 224, 105, + 104, 35, 120, 219, 147, 8, 43, 1, 216, 2, 75, 139, 153, 8, 96, 25, 75, 137, 224, 27, 35, 1, 96, 3, 75, 136, 72, 138, + 96, 25, 240, 0, 249, 243, 75, 137, 34, 4, 104, 27, 104, 155, 96, 154, 240, 0, 254, 232, 34, 0, 146, 5, 77, 133, 28, + 40, 240, 3, 251, 98, 75, 132, 96, 24, 104, 35, 43, 0, 208, 1, 104, 42, 96, 26, 75, 129, 104, 29, 231, 154, 28, 123, + 208, 11, 75, 121, 104, 27, 43, 0, 208, 7, 28, 56, 240, 5, 249, 245, 28, 56, 240, 5, 249, 186, 39, 1, 66, 127, 104, 35, + 105, 34, 104, 24, 104, 163, 104, 25, 240, 3, 253, 97, 75, 118, 28, 5, 120, 26, 42, 0, 208, 11, 34, 0, 112, 26, 104, + 35, 40, 0, 221, 2, 104, 25, 72, 113, 224, 1, 104, 25, 72, 113, 240, 1, 248, 108, 28, 121, 208, 0, 231, 113, 75, 102, + 104, 27, 43, 0, 209, 0, 231, 108, 72, 108, 154, 6, 28, 1, 35, 0, 240, 5, 249, 194, 28, 7, 231, 100, 104, 35, 105, 34, + 104, 24, 104, 163, 104, 25, 240, 3, 253, 253, 231, 91, 75, 101, 104, 26, 66, 81, 65, 74, 96, 26, 224, 153, 104, 35, + 104, 26, 75, 87, 96, 26, 38, 1, 231, 91, 122, 17, 122, 83, 6, 9, 4, 27, 67, 11, 122, 145, 122, 210, 2, 9, 67, 11, 67, + 26, 104, 37, 35, 0, 146, 7, 147, 13, 120, 42, 42, 95, 209, 26, 120, 106, 42, 68, 209, 23, 120, 170, 42, 86, 209, 20, + 120, 234, 42, 68, 209, 17, 77, 83, 74, 72, 96, 43, 104, 227, 33, 1, 96, 17, 43, 4, 209, 6, 104, 161, 168, 13, 34, 4, + 240, 5, 248, 27, 155, 13, 96, 43, 240, 4, 248, 153, 224, 17, 104, 227, 43, 4, 209, 4, 104, 161, 168, 13, 34, 4, 240, + 5, 248, 14, 28, 40, 153, 13, 240, 4, 248, 208, 144, 9, 40, 0, 208, 94, 75, 56, 34, 1, 96, 26, 38, 1, 37, 0, 150, 5, + 224, 134, 240, 3, 252, 130, 38, 1, 28, 5, 40, 0, 208, 0, 224, 127, 35, 1, 74, 60, 66, 91, 96, 19, 224, 122, 75, 46, + 34, 1, 96, 26, 28, 122, 208, 7, 28, 56, 240, 5, 249, 94, 28, 56, 240, 5, 249, 35, 39, 1, 66, 127, 104, 35, 105, 33, + 104, 24, 104, 163, 38, 1, 104, 26, 247, 255, 251, 119, 75, 36, 28, 5, 104, 27, 43, 0, 208, 96, 72, 42, 154, 6, 28, 1, + 35, 0, 240, 5, 249, 62, 28, 7, 224, 88, 155, 9, 43, 0, 208, 82, 28, 121, 208, 11, 75, 27, 104, 27, 43, 0, 208, 7, 28, + 56, 240, 5, 249, 56, 28, 56, 240, 5, 248, 253, 39, 1, 66, 127, 104, 35, 105, 34, 104, 25, 104, 163, 152, 9, 104, 27, + 240, 4, 252, 125, 75, 17, 104, 27, 43, 0, 208, 6, 72, 24, 154, 6, 28, 1, 35, 0, 240, 5, 249, 25, 28, 7, 38, 1, 37, 0, + 224, 49, 38, 1, 37, 6, 224, 45, 37, 1, 34, 1, 38, 1, 66, 109, 146, 5, 224, 40, 85, 77, 83, 128, 87, 70, 83, 2, 85, 77, + 83, 131, 87, 70, 83, 1, 87, 70, 83, 3, 19, 112, 107, 104, 19, 112, 96, 20, 19, 112, 106, 228, 19, 112, 21, 229, 19, + 112, 96, 60, 19, 114, 200, 12, 19, 114, 200, 16, 19, 112, 96, 16, 19, 112, 96, 137, 19, 112, 96, 164, 0, 152, 150, 128, + 19, 112, 106, 236, 19, 112, 96, 12, 19, 112, 96, 24, 38, 1, 37, 1, 66, 109, 153, 4, 0, 203, 24, 228, 224, 7, 104, 32, + 104, 97, 240, 5, 248, 175, 154, 4, 52, 8, 50, 1, 146, 4, 155, 4, 153, 11, 66, 139, 219, 243, 224, 9, 38, 1, 37, 1, 224, + 1, 38, 1, 37, 6, 66, 109, 224, 2, 37, 0, 38, 1, 149, 7, 75, 8, 36, 0, 104, 27, 43, 0, 208, 4, 28, 56, 73, 6, 240, 5, + 248, 203, 36, 1, 46, 0, 209, 0, 228, 101, 152, 15, 28, 41, 240, 5, 248, 167, 228, 96, 19, 112, 96, 20, 0, 152, 150, + 128, 74, 3, 35, 128, 104, 17, 2, 27, 67, 11, 96, 19, 71, 112, 70, 192, 13, 4, 0, 204, 75, 2, 74, 3, 104, 25, 64, 10, + 96, 26, 71, 112, 13, 4, 0, 204, 255, 255, 127, 255, 181, 16, 247, 255, 255, 243, 32, 128, 240, 3, 255, 104, 33, 32, + 240, 5, 248, 85, 76, 9, 96, 32, 32, 4, 240, 5, 248, 92, 104, 33, 34, 0, 32, 4, 240, 5, 248, 79, 247, 255, 255, 215, + 32, 4, 240, 5, 248, 110, 188, 16, 188, 1, 71, 0, 70, 192, 19, 112, 96, 32, 181, 16, 28, 4, 75, 15, 28, 8, 0, 137, 24, + 9, 104, 26, 0, 73, 35, 1, 240, 5, 248, 117, 75, 12, 33, 16, 96, 24, 72, 11, 240, 4, 248, 110, 33, 16, 72, 10, 240, 4, + 248, 117, 75, 10, 34, 55, 96, 28, 75, 9, 32, 4, 104, 27, 104, 155, 96, 154, 240, 5, 248, 73, 188, 16, 188, 1, 71, 0, + 19, 112, 96, 32, 19, 112, 96, 28, 13, 128, 0, 56, 13, 128, 0, 60, 19, 112, 107, 0, 19, 112, 96, 60, 181, 112, 76, 21, + 75, 21, 38, 2, 66, 118, 28, 33, 104, 24, 34, 0, 96, 38, 240, 5, 248, 59, 75, 18, 77, 18, 104, 27, 104, 154, 35, 0, 96, + 147, 74, 17, 104, 40, 96, 19, 240, 5, 248, 68, 104, 40, 240, 5, 248, 9, 35, 1, 66, 91, 96, 43, 104, 35, 43, 0, 209, + 3, 75, 11, 104, 27, 96, 35, 224, 0, 96, 38, 32, 4, 240, 5, 248, 19, 75, 2, 104, 24, 188, 112, 188, 2, 71, 8, 19, 112, + 106, 248, 19, 112, 96, 32, 19, 112, 96, 60, 19, 112, 96, 28, 19, 112, 107, 0, 19, 112, 106, 252, 75, 2, 34, 0, 96, 24, + 75, 2, 96, 26, 71, 112, 19, 112, 107, 4, 19, 112, 107, 0, 181, 248, 76, 34, 38, 16, 104, 35, 77, 33, 67, 179, 96, 35, + 104, 43, 73, 32, 104, 154, 121, 19, 121, 87, 6, 27, 4, 63, 67, 31, 121, 147, 2, 27, 67, 31, 121, 211, 67, 31, 104, 11, + 43, 0, 208, 18, 28, 56, 240, 0, 248, 56, 40, 0, 220, 20, 74, 22, 35, 0, 96, 19, 75, 22, 96, 24, 32, 4, 240, 4, 255, + 216, 104, 43, 34, 55, 104, 155, 64, 23, 96, 95, 224, 22, 75, 17, 104, 27, 43, 0, 208, 8, 28, 56, 240, 0, 248, 33, 104, + 43, 34, 55, 104, 155, 64, 23, 96, 95, 224, 2, 35, 55, 64, 31, 96, 87, 104, 35, 67, 51, 96, 35, 75, 9, 104, 26, 67, 22, + 96, 30, 32, 0, 188, 248, 188, 2, 71, 8, 70, 192, 13, 128, 0, 60, 19, 112, 96, 60, 19, 112, 107, 0, 19, 112, 106, 252, + 19, 112, 107, 4, 13, 128, 0, 56, 71, 24, 70, 192, 181, 112, 28, 12, 28, 5, 240, 4, 255, 93, 28, 6, 32, 1, 66, 64, 240, + 4, 255, 92, 104, 34, 75, 17, 66, 154, 209, 25, 75, 16, 73, 17, 34, 1, 67, 19, 96, 75, 28, 32, 34, 8, 240, 4, 254, 59, + 28, 32, 27, 100, 8, 164, 33, 8, 60, 2, 240, 4, 255, 102, 2, 36, 35, 234, 10, 36, 6, 27, 67, 35, 96, 43, 28, 40, 33, + 4, 240, 4, 255, 92, 28, 48, 240, 4, 255, 59, 188, 112, 188, 1, 71, 0, 230, 0, 1, 112, 19, 112, 4, 153, 19, 112, 96, + 36, 181, 56, 28, 4, 240, 4, 255, 148, 44, 38, 208, 72, 44, 38, 216, 5, 44, 36, 208, 9, 44, 37, 208, 0, 224, 169, 224, + 14, 44, 57, 208, 112, 44, 60, 208, 0, 224, 163, 224, 110, 73, 83, 75, 84, 72, 84, 96, 75, 34, 8, 240, 4, 254, 3, 72, + 82, 224, 150, 72, 82, 73, 82, 247, 255, 255, 171, 76, 77, 75, 81, 77, 82, 96, 99, 34, 8, 28, 40, 28, 33, 240, 4, 253, + 244, 28, 40, 33, 8, 240, 4, 255, 34, 75, 77, 77, 78, 96, 99, 34, 8, 28, 40, 28, 33, 240, 4, 253, 232, 28, 40, 33, 8, + 240, 4, 255, 22, 75, 73, 77, 74, 96, 99, 34, 8, 28, 33, 28, 40, 240, 4, 253, 220, 28, 40, 33, 8, 240, 4, 255, 10, 75, + 59, 72, 69, 96, 99, 28, 33, 34, 8, 240, 4, 253, 209, 72, 66, 224, 100, 72, 66, 73, 66, 247, 255, 255, 121, 76, 52, 75, + 65, 77, 57, 96, 99, 34, 8, 28, 40, 28, 33, 240, 4, 253, 194, 28, 40, 33, 8, 240, 4, 254, 240, 75, 60, 77, 53, 96, 99, + 34, 8, 28, 40, 28, 33, 240, 4, 253, 182, 28, 40, 33, 8, 240, 4, 254, 228, 75, 55, 77, 49, 96, 99, 34, 8, 28, 33, 28, + 40, 240, 4, 253, 170, 28, 40, 33, 8, 240, 4, 254, 216, 75, 34, 72, 50, 96, 99, 28, 33, 34, 8, 240, 4, 253, 159, 72, + 47, 224, 50, 72, 47, 224, 0, 72, 47, 73, 47, 247, 255, 255, 69, 76, 26, 75, 46, 77, 31, 96, 99, 34, 8, 28, 40, 28, 33, + 240, 4, 253, 142, 28, 40, 33, 8, 240, 4, 254, 188, 75, 41, 77, 27, 96, 99, 34, 8, 28, 40, 28, 33, 240, 4, 253, 130, + 28, 40, 33, 8, 240, 4, 254, 176, 75, 36, 77, 23, 96, 99, 34, 8, 28, 33, 28, 40, 240, 4, 253, 118, 28, 40, 33, 8, 240, + 4, 254, 164, 75, 8, 72, 31, 96, 99, 28, 33, 34, 8, 240, 4, 253, 107, 72, 28, 33, 8, 240, 4, 254, 153, 32, 0, 188, 56, + 188, 2, 71, 8, 70, 192, 19, 112, 96, 36, 19, 112, 0, 96, 255, 255, 30, 120, 32, 32, 93, 232, 32, 32, 64, 140, 255, 255, + 31, 112, 19, 112, 0, 188, 255, 255, 31, 140, 19, 112, 0, 196, 255, 255, 30, 52, 19, 112, 0, 204, 255, 255, 31, 104, + 32, 32, 91, 20, 32, 32, 62, 108, 255, 255, 30, 176, 255, 255, 30, 204, 255, 255, 29, 116, 255, 255, 30, 168, 32, 32, + 94, 132, 32, 32, 93, 148, 32, 32, 63, 96, 255, 255, 33, 48, 255, 255, 33, 76, 255, 255, 31, 244, 255, 255, 33, 40, 181, + 56, 77, 11, 35, 0, 104, 42, 73, 10, 240, 4, 254, 147, 76, 10, 73, 10, 34, 0, 96, 32, 104, 40, 240, 4, 254, 128, 104, + 32, 240, 4, 254, 145, 104, 32, 240, 4, 254, 86, 188, 56, 188, 1, 71, 0, 70, 192, 19, 112, 96, 44, 0, 152, 150, 128, + 19, 112, 96, 52, 19, 112, 107, 8, 181, 8, 1, 67, 26, 27, 0, 155, 24, 24, 0, 192, 247, 255, 255, 216, 188, 8, 188, 1, + 71, 0, 0, 0, 181, 0, 74, 5, 2, 192, 104, 19, 104, 17, 26, 201, 213, 0, 104, 19, 66, 129, 217, 249, 188, 1, 71, 0, 13, + 128, 0, 16, 181, 8, 75, 23, 120, 26, 75, 23, 96, 26, 240, 3, 254, 42, 75, 22, 33, 4, 96, 24, 28, 24, 240, 4, 254, 39, + 240, 3, 254, 44, 34, 0, 28, 1, 72, 18, 240, 3, 254, 97, 33, 160, 2, 73, 72, 16, 240, 4, 254, 63, 75, 16, 33, 128, 96, + 24, 240, 4, 254, 26, 33, 32, 240, 4, 253, 255, 75, 13, 96, 24, 240, 3, 252, 127, 40, 0, 219, 3, 247, 255, 249, 185, + 32, 0, 224, 1, 32, 1, 66, 64, 188, 8, 188, 2, 71, 8, 19, 112, 1, 12, 19, 112, 107, 104, 19, 114, 195, 160, 19, 112, + 14, 237, 19, 113, 131, 160, 19, 112, 96, 48, 19, 112, 96, 44, 181, 240, 7, 67, 213, 29, 33, 128, 79, 15, 78, 16, 34, + 0, 35, 0, 1, 137, 104, 56, 104, 53, 104, 128, 70, 172, 48, 68, 24, 128, 104, 4, 69, 99, 209, 5, 7, 224, 212, 8, 72, + 9, 36, 2, 80, 132, 224, 4, 77, 8, 64, 44, 44, 3, 209, 0, 96, 1, 51, 1, 50, 4, 43, 4, 209, 231, 188, 240, 188, 1, 71, + 0, 19, 112, 96, 60, 19, 112, 107, 104, 19, 112, 107, 108, 0, 0, 32, 3, 181, 240, 176, 131, 147, 1, 155, 8, 76, 14, 0, + 91, 104, 38, 28, 13, 28, 23, 147, 0, 32, 10, 247, 255, 255, 79, 104, 43, 154, 1, 64, 59, 66, 147, 208, 9, 104, 35, 27, + 155, 213, 0, 104, 38, 154, 0, 66, 147, 211, 240, 32, 2, 66, 64, 224, 0, 32, 0, 176, 3, 188, 240, 188, 2, 71, 8, 70, + 192, 13, 128, 0, 16, 181, 56, 28, 4, 240, 3, 252, 115, 33, 0, 28, 5, 34, 96, 28, 32, 240, 4, 252, 160, 35, 64, 96, 163, + 35, 128, 4, 91, 99, 101, 96, 35, 96, 99, 188, 56, 188, 1, 71, 0, 181, 16, 75, 12, 36, 0, 104, 27, 108, 26, 42, 7, 220, + 13, 73, 10, 104, 12, 0, 228, 24, 164, 0, 97, 25, 12, 106, 25, 1, 100, 25, 12, 50, 1, 100, 26, 28, 32, 247, 255, 255, + 215, 28, 32, 188, 16, 188, 2, 71, 8, 70, 192, 19, 112, 96, 60, 19, 112, 107, 88, 181, 240, 28, 4, 176, 133, 28, 8, 28, + 14, 147, 3, 28, 23, 240, 4, 251, 243, 35, 0, 98, 35, 5, 53, 35, 128, 13, 45, 1, 91, 27, 93, 96, 224, 66, 175, 210, 1, + 28, 61, 224, 49, 32, 128, 1, 64, 24, 54, 11, 54, 3, 54, 150, 2, 33, 1, 28, 38, 54, 16, 145, 1, 224, 20, 152, 2, 240, + 4, 251, 217, 34, 0, 198, 1, 97, 50, 155, 2, 33, 128, 28, 24, 35, 128, 1, 91, 1, 73, 24, 192, 24, 109, 144, 2, 66, 189, + 211, 0, 28, 61, 154, 1, 50, 1, 146, 1, 66, 189, 210, 8, 152, 1, 33, 0, 15, 195, 34, 4, 66, 130, 65, 75, 6, 27, 43, 0, + 209, 223, 66, 189, 208, 4, 28, 40, 153, 10, 240, 4, 253, 62, 26, 109, 155, 3, 4, 40, 67, 24, 240, 4, 251, 176, 35, 128, + 4, 91, 96, 160, 100, 37, 96, 35, 96, 99, 176, 5, 28, 40, 188, 240, 188, 2, 71, 8, 0, 0, 181, 240, 176, 139, 28, 5, 247, + 255, 255, 133, 28, 6, 32, 0, 46, 0, 209, 0, 224, 145, 99, 245, 105, 42, 126, 107, 126, 47, 97, 104, 146, 3, 147, 7, + 47, 0, 209, 25, 35, 8, 147, 0, 35, 160, 104, 105, 34, 8, 0, 155, 28, 48, 247, 255, 255, 140, 247, 255, 255, 108, 28, + 4, 28, 56, 44, 0, 208, 121, 107, 96, 99, 229, 240, 4, 251, 126, 154, 3, 96, 48, 99, 180, 42, 0, 208, 4, 79, 58, 224, + 3, 28, 52, 39, 128, 224, 0, 79, 56, 104, 235, 154, 7, 147, 4, 42, 0, 208, 2, 35, 128, 0, 91, 67, 31, 105, 235, 150, + 9, 5, 91, 13, 91, 147, 5, 154, 5, 35, 128, 4, 91, 58, 1, 147, 6, 146, 8, 155, 5, 154, 3, 147, 0, 28, 32, 28, 59, 153, + 4, 247, 255, 255, 92, 154, 3, 155, 4, 26, 18, 146, 3, 154, 7, 24, 27, 147, 4, 42, 0, 208, 1, 155, 6, 96, 99, 154, 8, + 155, 5, 24, 128, 66, 3, 209, 2, 34, 128, 6, 18, 24, 191, 155, 3, 43, 0, 221, 11, 247, 255, 255, 38, 30, 6, 208, 52, + 107, 112, 99, 245, 240, 4, 251, 58, 99, 166, 96, 32, 28, 52, 231, 213, 35, 128, 4, 91, 96, 99, 105, 43, 158, 9, 148, + 3, 43, 0, 208, 29, 126, 42, 146, 4, 42, 0, 209, 25, 247, 255, 255, 14, 28, 4, 32, 0, 44, 0, 208, 27, 107, 96, 99, 229, + 240, 4, 251, 32, 155, 3, 34, 128, 96, 24, 99, 156, 35, 128, 0, 91, 6, 18, 64, 123, 67, 19, 154, 4, 28, 32, 146, 0, 33, + 0, 34, 0, 247, 255, 255, 20, 104, 162, 35, 128, 4, 27, 67, 19, 96, 163, 28, 48, 224, 0, 32, 0, 176, 11, 188, 240, 188, + 2, 71, 8, 128, 0, 0, 128, 128, 0, 1, 128, 181, 56, 76, 19, 37, 32, 104, 35, 104, 155, 120, 25, 120, 90, 6, 9, 4, 18, + 67, 10, 120, 153, 120, 219, 2, 9, 67, 10, 67, 19, 224, 18, 104, 34, 67, 171, 104, 146, 32, 10, 96, 19, 247, 255, 253, + 243, 104, 35, 104, 155, 120, 25, 120, 90, 6, 9, 4, 18, 67, 10, 120, 153, 120, 219, 2, 9, 67, 10, 67, 19, 66, 29, 209, + 234, 188, 56, 188, 1, 71, 0, 19, 112, 96, 60, 181, 56, 76, 19, 37, 32, 104, 35, 104, 155, 120, 25, 120, 90, 6, 9, 4, + 18, 67, 10, 120, 153, 120, 219, 2, 9, 67, 10, 67, 19, 224, 18, 104, 34, 67, 43, 104, 146, 32, 10, 96, 19, 247, 255, + 253, 201, 104, 35, 104, 155, 120, 25, 120, 90, 6, 9, 4, 18, 67, 10, 120, 153, 120, 219, 2, 9, 67, 10, 67, 19, 66, 29, + 208, 234, 188, 56, 188, 1, 71, 0, 19, 112, 96, 60, 181, 248, 28, 12, 40, 0, 209, 33, 77, 28, 76, 29, 79, 29, 38, 0, + 104, 43, 104, 155, 126, 25, 126, 90, 6, 9, 4, 18, 67, 10, 126, 153, 126, 219, 2, 9, 67, 10, 67, 19, 105, 34, 108, 82, + 66, 147, 211, 6, 105, 98, 108, 82, 66, 147, 216, 2, 247, 255, 255, 142, 224, 25, 32, 10, 54, 1, 247, 255, 253, 147, + 66, 190, 209, 226, 224, 18, 40, 1, 209, 16, 224, 6, 32, 10, 54, 1, 247, 255, 253, 137, 66, 190, 209, 3, 224, 8, 77, + 6, 79, 8, 38, 0, 104, 43, 104, 155, 105, 154, 108, 99, 66, 154, 208, 239, 32, 0, 188, 248, 188, 2, 71, 8, 70, 192, 19, + 112, 96, 60, 19, 114, 195, 192, 0, 0, 19, 136, 181, 0, 7, 67, 213, 21, 75, 12, 104, 27, 104, 154, 75, 11, 108, 81, 64, + 11, 43, 3, 209, 2, 35, 128, 1, 155, 100, 83, 75, 6, 104, 27, 104, 154, 75, 6, 108, 145, 64, 11, 43, 3, 209, 2, 35, 128, + 1, 155, 100, 147, 188, 1, 71, 0, 70, 192, 19, 112, 96, 60, 0, 0, 32, 3, 181, 16, 75, 19, 28, 4, 104, 27, 52, 16, 104, + 155, 0, 164, 25, 28, 34, 128, 104, 99, 1, 146, 66, 19, 209, 0, 64, 83, 34, 46, 67, 147, 96, 99, 32, 5, 247, 255, 253, + 106, 34, 128, 104, 99, 1, 146, 66, 19, 208, 0, 64, 83, 34, 46, 67, 147, 96, 99, 32, 5, 247, 255, 253, 94, 75, 4, 32, + 5, 96, 99, 247, 255, 253, 89, 188, 16, 188, 1, 71, 0, 19, 112, 96, 60, 0, 0, 24, 1, 181, 240, 176, 131, 75, 36, 28, + 5, 104, 27, 53, 16, 104, 155, 0, 173, 25, 93, 104, 107, 74, 33, 29, 44, 64, 26, 38, 4, 42, 1, 208, 4, 4, 154, 213, 51, + 247, 255, 255, 192, 224, 48, 39, 136, 1, 127, 34, 4, 67, 147, 67, 59, 96, 35, 32, 60, 247, 255, 253, 40, 104, 35, 74, + 24, 32, 50, 64, 19, 96, 35, 247, 255, 253, 33, 75, 22, 34, 128, 147, 0, 28, 32, 28, 33, 0, 82, 35, 0, 247, 255, 253, + 156, 40, 0, 208, 2, 104, 107, 72, 17, 224, 20, 104, 35, 34, 4, 66, 26, 209, 16, 62, 1, 46, 0, 209, 220, 34, 128, 1, + 146, 67, 19, 33, 42, 67, 139, 96, 107, 32, 10, 96, 106, 247, 255, 253, 2, 72, 8, 224, 1, 32, 1, 66, 64, 176, 3, 188, + 240, 188, 2, 71, 8, 19, 112, 96, 60, 0, 0, 32, 1, 255, 255, 254, 213, 0, 0, 19, 136, 255, 255, 248, 48, 255, 255, 251, + 161, 181, 16, 75, 20, 28, 4, 104, 27, 52, 16, 104, 155, 0, 164, 25, 28, 34, 128, 104, 99, 1, 146, 66, 19, 209, 0, 64, + 83, 34, 46, 67, 147, 96, 99, 32, 5, 247, 255, 252, 230, 34, 128, 104, 99, 1, 146, 66, 19, 208, 0, 64, 83, 34, 46, 67, + 147, 96, 99, 32, 5, 247, 255, 252, 218, 75, 5, 32, 60, 96, 99, 247, 255, 252, 213, 32, 1, 188, 16, 188, 2, 71, 8, 70, + 192, 19, 112, 96, 60, 0, 0, 24, 1, 75, 5, 48, 16, 104, 27, 0, 128, 104, 155, 24, 24, 35, 128, 1, 155, 96, 67, 32, 0, + 71, 112, 70, 192, 19, 112, 96, 60, 74, 5, 32, 0, 104, 19, 104, 153, 35, 128, 1, 155, 100, 75, 104, 18, 104, 146, 100, + 147, 71, 112, 70, 192, 19, 112, 96, 60, 181, 0, 75, 10, 104, 27, 104, 154, 35, 128, 108, 81, 1, 155, 66, 25, 209, 0, + 100, 83, 75, 5, 104, 27, 104, 154, 35, 128, 108, 145, 1, 155, 66, 25, 209, 0, 100, 147, 32, 0, 188, 2, 71, 8, 19, 112, + 96, 60, 75, 6, 33, 0, 104, 26, 35, 1, 66, 91, 28, 16, 103, 17, 103, 147, 48, 152, 50, 160, 96, 1, 96, 19, 71, 112, 70, + 192, 19, 112, 96, 60, 181, 112, 75, 13, 104, 25, 28, 11, 51, 84, 28, 10, 120, 29, 50, 120, 35, 0, 224, 9, 0, 156, 24, + 228, 0, 228, 104, 22, 52, 88, 25, 12, 50, 40, 66, 134, 208, 4, 51, 1, 66, 171, 219, 243, 32, 0, 224, 0, 28, 32, 188, + 112, 188, 2, 71, 8, 19, 112, 96, 60, 181, 240, 176, 133, 77, 24, 28, 1, 36, 0, 32, 0, 70, 172, 145, 1, 224, 26, 0, 166, + 25, 54, 0, 246, 25, 174, 111, 53, 45, 0, 208, 18, 0, 197, 83, 92, 39, 0, 25, 93, 128, 111, 54, 96, 136, 55, 48, 1, 4, + 63, 10, 57, 14, 63, 67, 15, 128, 175, 136, 118, 4, 54, 10, 55, 14, 54, 67, 62, 128, 238, 52, 1, 70, 103, 104, 61, 28, + 46, 54, 84, 120, 54, 66, 180, 218, 2, 153, 1, 66, 136, 219, 218, 112, 16, 176, 5, 188, 240, 188, 2, 71, 8, 70, 192, + 19, 112, 96, 60, 181, 0, 28, 3, 224, 8, 120, 90, 58, 4, 6, 18, 14, 18, 42, 1, 217, 4, 120, 26, 26, 137, 24, 155, 41, + 0, 209, 244, 26, 24, 188, 2, 71, 8, 181, 240, 176, 133, 124, 130, 124, 195, 6, 18, 4, 27, 67, 19, 125, 2, 28, 5, 2, + 18, 67, 19, 125, 66, 67, 26, 208, 103, 34, 0, 146, 3, 146, 1, 224, 83, 6, 36, 4, 9, 2, 18, 67, 12, 67, 20, 158, 3, 67, + 35, 25, 156, 122, 98, 122, 163, 6, 18, 4, 27, 67, 19, 122, 226, 2, 18, 67, 19, 123, 34, 67, 26, 208, 58, 39, 0, 151, + 2, 28, 46, 224, 36, 6, 0, 4, 9, 2, 18, 67, 8, 67, 16, 67, 3, 25, 221, 123, 170, 123, 235, 6, 18, 4, 27, 67, 19, 124, + 42, 124, 104, 2, 18, 67, 19, 67, 24, 208, 1, 240, 3, 249, 66, 122, 106, 122, 171, 6, 18, 4, 27, 67, 19, 122, 234, 123, + 40, 2, 18, 67, 19, 67, 24, 208, 1, 240, 3, 249, 53, 154, 2, 55, 18, 50, 1, 146, 2, 121, 35, 157, 2, 70, 156, 122, 96, + 122, 161, 122, 226, 123, 35, 69, 101, 219, 209, 28, 53, 6, 6, 4, 8, 67, 48, 2, 18, 67, 16, 67, 24, 240, 3, 249, 31, + 158, 1, 154, 3, 54, 1, 50, 13, 150, 1, 146, 3, 124, 104, 158, 1, 124, 172, 124, 233, 125, 42, 125, 107, 66, 134, 219, + 163, 6, 36, 4, 8, 67, 32, 2, 18, 67, 16, 67, 24, 240, 3, 249, 9, 176, 5, 188, 240, 188, 1, 71, 0, 0, 0, 181, 248, 30, + 5, 209, 4, 75, 28, 34, 48, 112, 26, 112, 93, 224, 47, 76, 26, 28, 46, 28, 48, 33, 10, 240, 4, 249, 236, 28, 48, 28, + 15, 33, 10, 240, 4, 249, 255, 23, 251, 24, 255, 64, 95, 55, 48, 75, 20, 112, 39, 60, 1, 28, 6, 66, 156, 209, 236, 75, + 15, 34, 0, 118, 154, 45, 0, 218, 2, 34, 45, 112, 26, 34, 1, 35, 16, 72, 10, 224, 0, 51, 1, 92, 193, 41, 48, 208, 251, + 66, 72, 65, 65, 26, 91, 73, 6, 224, 2, 84, 136, 51, 1, 50, 1, 92, 200, 40, 0, 209, 249, 84, 136, 188, 248, 188, 1, 71, + 0, 70, 192, 19, 114, 197, 128, 19, 114, 197, 153, 19, 114, 197, 143, 181, 248, 30, 4, 209, 4, 75, 24, 34, 48, 112, 26, + 112, 92, 224, 40, 77, 22, 28, 47, 63, 10, 28, 32, 33, 10, 240, 4, 249, 129, 28, 32, 28, 14, 33, 10, 240, 4, 249, 86, + 54, 48, 112, 46, 61, 1, 28, 4, 66, 189, 209, 240, 74, 12, 35, 0, 118, 147, 28, 17, 35, 16, 224, 0, 51, 1, 92, 202, 42, + 48, 208, 251, 66, 81, 65, 74, 26, 155, 73, 6, 34, 0, 224, 2, 84, 136, 51, 1, 50, 1, 92, 200, 40, 0, 209, 249, 84, 136, + 188, 248, 188, 1, 71, 0, 19, 114, 197, 128, 19, 114, 197, 153, 181, 16, 40, 0, 209, 4, 75, 24, 34, 48, 112, 26, 112, + 88, 224, 40, 75, 22, 33, 15, 28, 28, 60, 8, 28, 10, 64, 2, 9, 0, 42, 9, 221, 0, 50, 7, 50, 48, 112, 26, 59, 1, 66, 163, + 209, 244, 74, 14, 35, 0, 118, 19, 35, 48, 112, 19, 35, 120, 112, 83, 35, 16, 224, 0, 51, 1, 92, 209, 41, 48, 208, 251, + 66, 74, 65, 74, 26, 155, 73, 6, 34, 2, 224, 2, 84, 136, 51, 1, 50, 1, 92, 200, 40, 0, 209, 249, 84, 136, 188, 16, 188, + 1, 71, 0, 19, 114, 197, 128, 19, 114, 197, 151, 180, 15, 181, 240, 176, 133, 171, 10, 203, 64, 34, 128, 1, 146, 169, + 3, 128, 10, 147, 2, 36, 0, 77, 46, 79, 46, 224, 81, 28, 114, 146, 1, 43, 37, 208, 12, 70, 106, 115, 19, 168, 3, 240, + 4, 248, 121, 25, 4, 158, 1, 66, 172, 220, 68, 168, 3, 240, 4, 249, 90, 224, 64, 120, 115, 43, 115, 208, 46, 43, 115, + 216, 4, 43, 100, 208, 7, 43, 105, 209, 53, 224, 4, 43, 117, 208, 9, 43, 120, 209, 48, 224, 20, 155, 2, 29, 26, 146, + 2, 104, 24, 247, 255, 255, 26, 224, 19, 155, 2, 29, 26, 146, 2, 104, 24, 247, 255, 255, 85, 28, 56, 240, 4, 248, 82, + 25, 4, 28, 56, 66, 172, 220, 27, 224, 24, 155, 2, 29, 26, 146, 2, 104, 24, 247, 255, 255, 127, 72, 16, 240, 4, 248, + 68, 25, 4, 66, 172, 220, 14, 72, 13, 224, 10, 155, 2, 29, 26, 146, 2, 104, 30, 28, 48, 240, 4, 248, 56, 25, 4, 66, 172, + 220, 2, 28, 48, 240, 4, 249, 26, 158, 1, 54, 1, 120, 51, 43, 0, 209, 170, 176, 5, 188, 240, 188, 8, 176, 4, 71, 24, + 0, 0, 13, 171, 19, 114, 197, 128, 181, 240, 28, 12, 176, 133, 28, 6, 33, 0, 32, 0, 247, 255, 252, 160, 126, 35, 43, + 0, 209, 9, 74, 221, 104, 17, 74, 221, 0, 137, 80, 139, 104, 32, 33, 8, 240, 2, 255, 138, 96, 96, 105, 33, 41, 0, 208, + 9, 126, 99, 104, 160, 43, 0, 208, 2, 240, 2, 255, 128, 224, 1, 240, 2, 255, 133, 96, 224, 126, 35, 43, 0, 209, 3, 75, + 210, 104, 27, 105, 219, 224, 6, 126, 99, 43, 0, 208, 1, 75, 207, 224, 0, 75, 207, 104, 27, 147, 2, 77, 207, 75, 207, + 153, 2, 28, 40, 96, 25, 34, 96, 240, 3, 248, 177, 33, 0, 34, 48, 152, 2, 240, 3, 255, 146, 75, 197, 34, 0, 104, 27, + 28, 32, 100, 26, 75, 200, 34, 1, 104, 25, 64, 74, 96, 26, 247, 255, 251, 102, 75, 197, 100, 168, 96, 24, 126, 34, 35, + 15, 146, 1, 64, 26, 146, 3, 155, 3, 28, 7, 34, 128, 105, 176, 2, 29, 1, 146, 155, 1, 67, 2, 105, 225, 67, 42, 43, 0, + 209, 1, 72, 188, 224, 5, 5, 72, 35, 128, 9, 64, 5, 219, 67, 3, 28, 24, 67, 16, 240, 3, 254, 235, 77, 179, 35, 64, 96, + 171, 75, 182, 33, 255, 104, 27, 34, 255, 108, 91, 2, 9, 4, 18, 64, 25, 64, 26, 2, 9, 10, 18, 67, 10, 14, 25, 67, 10, + 33, 224, 64, 11, 33, 2, 67, 11, 6, 27, 67, 26, 96, 104, 96, 42, 107, 120, 240, 3, 254, 207, 35, 128, 153, 1, 4, 91, + 97, 40, 97, 107, 41, 0, 208, 16, 9, 203, 153, 3, 106, 114, 1, 27, 24, 91, 64, 218, 28, 19, 7, 218, 213, 3, 105, 170, + 35, 128, 67, 19, 224, 2, 105, 171, 34, 128, 67, 147, 97, 171, 77, 153, 75, 158, 105, 170, 28, 40, 64, 19, 97, 171, 33, + 96, 240, 2, 255, 8, 108, 173, 224, 4, 28, 40, 33, 96, 240, 2, 255, 2, 107, 173, 45, 0, 209, 248, 152, 2, 73, 143, 34, + 96, 240, 3, 248, 41, 75, 148, 120, 27, 43, 0, 208, 4, 75, 147, 72, 148, 104, 25, 247, 255, 254, 215, 75, 147, 34, 1, + 96, 26, 77, 132, 35, 0, 147, 1, 153, 1, 74, 141, 49, 1, 145, 1, 72, 143, 104, 17, 247, 254, 255, 173, 104, 43, 33, 32, + 105, 152, 240, 2, 254, 242, 104, 42, 73, 127, 39, 2, 108, 75, 105, 145, 34, 255, 2, 18, 64, 26, 2, 16, 34, 255, 4, 18, + 64, 26, 10, 18, 67, 2, 14, 24, 67, 2, 32, 224, 64, 3, 67, 59, 6, 24, 28, 19, 67, 3, 96, 11, 104, 43, 33, 32, 105, 152, + 240, 2, 254, 194, 247, 255, 251, 144, 247, 254, 255, 182, 154, 1, 42, 4, 208, 6, 28, 3, 51, 9, 209, 3, 72, 120, 247, + 255, 254, 155, 231, 200, 75, 116, 34, 0, 96, 26, 75, 112, 28, 7, 120, 27, 43, 0, 208, 3, 72, 115, 28, 57, 247, 255, + 254, 142, 47, 0, 209, 6, 75, 94, 104, 26, 75, 94, 0, 146, 88, 211, 43, 0, 208, 15, 74, 93, 75, 90, 104, 18, 104, 27, + 104, 146, 0, 155, 50, 68, 24, 210, 104, 18, 33, 5, 64, 10, 42, 5, 208, 2, 74, 85, 33, 1, 80, 153, 66, 121, 65, 121, + 145, 1, 29, 122, 208, 1, 41, 0, 208, 65, 247, 255, 251, 44, 77, 80, 33, 32, 104, 43, 105, 152, 240, 3, 255, 166, 104, + 43, 33, 32, 105, 152, 240, 2, 254, 105, 75, 83, 104, 42, 104, 27, 105, 145, 108, 91, 34, 255, 2, 18, 64, 26, 2, 16, + 34, 255, 4, 18, 64, 26, 10, 18, 67, 2, 14, 24, 67, 2, 32, 224, 64, 3, 32, 2, 67, 3, 6, 24, 28, 19, 67, 3, 96, 11, 104, + 43, 33, 32, 105, 152, 240, 3, 255, 124, 247, 255, 251, 44, 126, 34, 42, 0, 208, 98, 9, 211, 32, 15, 64, 16, 1, 27, 24, + 27, 106, 113, 34, 1, 64, 154, 67, 145, 28, 10, 73, 70, 104, 9, 6, 9, 15, 201, 64, 153, 28, 11, 67, 19, 98, 115, 224, + 79, 247, 255, 250, 234, 75, 50, 108, 157, 224, 4, 107, 104, 33, 96, 240, 2, 254, 81, 107, 173, 45, 0, 209, 248, 77, + 45, 34, 32, 28, 40, 153, 2, 240, 2, 255, 112, 126, 34, 42, 0, 208, 16, 9, 211, 32, 15, 64, 16, 1, 27, 24, 27, 106, 113, + 34, 1, 64, 154, 67, 145, 28, 10, 105, 169, 6, 9, 15, 201, 64, 153, 28, 11, 67, 19, 98, 115, 77, 29, 33, 32, 104, 43, + 38, 2, 105, 152, 240, 3, 255, 63, 104, 43, 33, 32, 105, 152, 240, 2, 254, 2, 75, 31, 104, 42, 104, 27, 105, 145, 108, + 91, 34, 255, 2, 18, 64, 26, 2, 16, 34, 255, 4, 18, 64, 26, 10, 18, 67, 2, 14, 24, 67, 2, 32, 224, 64, 3, 67, 51, 6, + 24, 28, 19, 67, 3, 96, 11, 104, 43, 33, 32, 105, 152, 240, 3, 255, 22, 247, 255, 250, 198, 73, 11, 32, 1, 247, 255, + 250, 236, 105, 33, 41, 0, 208, 48, 126, 99, 104, 224, 43, 0, 208, 42, 240, 2, 253, 241, 224, 41, 19, 112, 107, 104, + 19, 112, 107, 108, 19, 112, 96, 60, 19, 112, 107, 16, 19, 112, 107, 96, 19, 114, 197, 32, 19, 112, 107, 28, 19, 112, + 107, 88, 19, 112, 107, 56, 64, 64, 64, 0, 19, 112, 107, 92, 1, 0, 0, 128, 19, 112, 107, 20, 19, 112, 96, 56, 19, 112, + 96, 194, 19, 112, 107, 52, 19, 112, 42, 177, 19, 112, 98, 156, 19, 112, 96, 240, 19, 112, 107, 36, 240, 2, 253, 204, + 126, 35, 43, 0, 209, 3, 104, 96, 33, 8, 240, 2, 253, 191, 155, 1, 43, 0, 208, 0, 105, 103, 176, 5, 28, 56, 188, 240, + 188, 2, 71, 8, 181, 48, 176, 137, 70, 108, 118, 33, 9, 201, 118, 97, 33, 128, 0, 137, 37, 0, 145, 7, 70, 105, 149, 0, + 146, 4, 147, 2, 247, 255, 253, 240, 176, 9, 188, 48, 188, 2, 71, 8, 181, 240, 176, 139, 28, 6, 70, 104, 48, 70, 136, + 4, 72, 43, 70, 156, 104, 0, 70, 107, 51, 66, 48, 248, 104, 0, 136, 27, 112, 66, 4, 27, 70, 98, 147, 1, 2, 19, 10, 18, + 67, 19, 4, 26, 12, 19, 14, 18, 112, 1, 159, 18, 112, 130, 112, 195, 155, 1, 4, 36, 10, 26, 14, 27, 67, 19, 4, 27, 12, + 37, 12, 26, 14, 27, 113, 3, 14, 36, 2, 43, 67, 35, 4, 27, 113, 66, 14, 26, 12, 27, 113, 195, 172, 2, 35, 0, 113, 130, + 118, 35, 35, 64, 97, 227, 75, 21, 9, 201, 144, 2, 118, 97, 97, 37, 66, 159, 217, 22, 28, 40, 240, 2, 253, 118, 28, 42, + 28, 57, 96, 160, 240, 3, 253, 55, 28, 33, 28, 48, 247, 255, 253, 165, 104, 164, 28, 6, 28, 33, 28, 56, 28, 42, 240, + 3, 253, 44, 28, 32, 240, 2, 253, 129, 224, 5, 28, 48, 96, 167, 28, 33, 247, 255, 253, 149, 28, 6, 176, 11, 28, 48, 188, + 240, 188, 2, 71, 8, 70, 192, 19, 112, 96, 60, 19, 136, 0, 0, 181, 0, 176, 133, 145, 0, 35, 0, 33, 2, 34, 1, 147, 1, + 147, 2, 247, 255, 255, 148, 176, 5, 188, 2, 71, 8, 181, 0, 176, 133, 28, 19, 34, 0, 145, 0, 146, 1, 146, 2, 33, 1, 34, + 11, 247, 255, 255, 134, 176, 5, 188, 2, 71, 8, 181, 0, 176, 133, 34, 0, 146, 0, 146, 1, 146, 2, 28, 11, 34, 9, 33, 0, + 247, 255, 255, 120, 176, 5, 188, 2, 71, 8, 181, 112, 28, 4, 176, 132, 32, 1, 28, 14, 240, 2, 253, 34, 30, 5, 208, 18, + 35, 0, 147, 0, 35, 1, 147, 1, 28, 32, 33, 128, 34, 8, 35, 0, 149, 2, 247, 255, 255, 97, 30, 4, 219, 1, 120, 43, 112, + 51, 28, 40, 240, 2, 253, 44, 224, 1, 36, 4, 66, 100, 176, 4, 28, 32, 188, 112, 188, 2, 71, 8, 181, 16, 176, 132, 70, + 108, 2, 18, 52, 27, 120, 36, 67, 19, 34, 0, 146, 0, 145, 2, 34, 6, 33, 128, 148, 1, 247, 255, 255, 67, 176, 4, 188, + 16, 188, 2, 71, 8, 0, 0, 181, 240, 176, 137, 75, 65, 28, 2, 104, 30, 0, 129, 104, 179, 24, 9, 50, 16, 0, 201, 0, 146, + 24, 154, 28, 11, 51, 88, 28, 7, 24, 240, 144, 5, 24, 113, 32, 0, 103, 8, 104, 81, 29, 21, 74, 56, 64, 10, 42, 1, 209, + 99, 34, 4, 146, 4, 147, 7, 75, 54, 32, 10, 96, 43, 247, 254, 255, 134, 75, 52, 32, 100, 96, 43, 247, 254, 255, 129, + 75, 51, 34, 128, 96, 43, 35, 250, 0, 219, 147, 0, 0, 82, 35, 0, 28, 40, 28, 41, 247, 254, 255, 249, 104, 42, 75, 45, + 28, 4, 64, 19, 43, 5, 209, 50, 35, 192, 1, 27, 64, 26, 35, 128, 0, 219, 66, 154, 208, 43, 40, 0, 209, 43, 32, 100, 247, + 254, 255, 99, 75, 38, 74, 38, 104, 24, 96, 26, 154, 7, 35, 22, 147, 1, 24, 179, 147, 2, 35, 128, 144, 6, 33, 128, 152, + 5, 34, 6, 0, 91, 148, 0, 247, 255, 254, 231, 30, 4, 219, 12, 28, 123, 32, 0, 4, 27, 144, 0, 144, 1, 144, 2, 12, 27, + 152, 5, 33, 0, 34, 5, 247, 255, 254, 217, 28, 4, 75, 21, 154, 6, 96, 26, 44, 0, 219, 2, 224, 8, 36, 1, 66, 100, 155, + 4, 59, 1, 147, 4, 43, 0, 209, 169, 44, 0, 219, 10, 0, 187, 25, 219, 0, 219, 24, 246, 55, 1, 35, 0, 103, 243, 103, 55, + 224, 1, 36, 1, 66, 100, 176, 9, 28, 32, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 96, 60, 0, 0, 32, 1, 0, 0, 24, 3, + 0, 0, 25, 3, 0, 0, 16, 1, 0, 0, 32, 5, 19, 112, 96, 56, 0, 6, 26, 128, 181, 248, 76, 25, 28, 6, 104, 35, 104, 157, 35, + 1, 96, 171, 247, 255, 255, 97, 30, 7, 218, 24, 104, 35, 33, 55, 104, 155, 28, 52, 104, 90, 32, 10, 64, 10, 96, 90, 52, + 16, 247, 254, 254, 252, 0, 164, 75, 15, 25, 44, 96, 99, 32, 50, 247, 254, 254, 245, 75, 13, 32, 100, 96, 99, 247, 254, + 254, 240, 75, 11, 96, 99, 75, 7, 32, 55, 104, 26, 104, 146, 104, 81, 64, 1, 96, 81, 104, 27, 34, 4, 104, 155, 28, 56, + 96, 154, 188, 248, 188, 2, 71, 8, 70, 192, 19, 112, 96, 60, 0, 0, 24, 3, 0, 0, 25, 3, 0, 0, 16, 1, 181, 240, 176, 137, + 75, 126, 34, 0, 104, 31, 0, 131, 24, 27, 0, 219, 28, 30, 147, 5, 54, 88, 24, 251, 28, 4, 25, 190, 103, 26, 32, 50, 247, + 254, 254, 196, 37, 3, 150, 6, 72, 118, 247, 255, 251, 213, 32, 50, 247, 254, 254, 188, 35, 22, 147, 1, 155, 6, 34, 0, + 147, 2, 35, 128, 146, 0, 28, 48, 33, 128, 34, 6, 0, 91, 247, 255, 254, 69, 40, 0, 218, 12, 72, 109, 247, 255, 251, 192, + 32, 50, 247, 254, 254, 167, 61, 1, 32, 100, 247, 254, 254, 163, 45, 0, 209, 222, 224, 2, 154, 5, 24, 187, 224, 38, 28, + 32, 247, 255, 249, 84, 75, 100, 66, 152, 209, 0, 224, 184, 32, 100, 247, 254, 254, 147, 72, 98, 247, 255, 251, 166, + 35, 22, 147, 1, 155, 6, 34, 0, 147, 2, 35, 128, 146, 0, 28, 48, 33, 128, 34, 6, 0, 91, 247, 255, 254, 25, 40, 0, 218, + 6, 72, 90, 53, 1, 247, 255, 251, 147, 45, 3, 209, 221, 224, 12, 0, 163, 25, 27, 0, 219, 24, 251, 110, 26, 75, 85, 66, + 154, 209, 46, 28, 32, 247, 255, 249, 175, 76, 83, 224, 144, 28, 32, 247, 255, 248, 248, 32, 100, 247, 254, 254, 103, + 28, 32, 247, 255, 249, 30, 74, 73, 66, 144, 209, 0, 224, 130, 32, 100, 247, 254, 254, 93, 72, 75, 247, 255, 251, 112, + 35, 0, 154, 6, 147, 0, 35, 22, 147, 1, 35, 128, 146, 2, 28, 48, 33, 128, 34, 6, 0, 91, 247, 255, 253, 227, 40, 0, 218, + 7, 72, 63, 61, 1, 247, 255, 251, 93, 45, 0, 209, 215, 76, 64, 224, 102, 72, 64, 247, 255, 251, 86, 28, 99, 147, 5, 4, + 27, 12, 27, 147, 7, 0, 163, 25, 28, 0, 228, 37, 0, 25, 63, 32, 50, 247, 254, 254, 51, 72, 57, 28, 41, 247, 255, 251, + 69, 35, 0, 147, 0, 147, 1, 147, 2, 28, 48, 33, 0, 34, 5, 155, 7, 247, 255, 253, 187, 30, 4, 218, 7, 76, 50, 28, 41, + 72, 50, 27, 100, 247, 255, 251, 51, 53, 1, 224, 3, 72, 48, 28, 41, 247, 255, 251, 45, 155, 5, 34, 0, 103, 250, 103, + 59, 44, 0, 218, 47, 33, 0, 28, 48, 247, 255, 254, 5, 32, 50, 247, 254, 254, 10, 72, 40, 247, 255, 251, 29, 35, 22, 147, + 1, 155, 6, 34, 0, 147, 2, 35, 128, 146, 0, 28, 48, 33, 128, 34, 6, 0, 91, 247, 255, 253, 144, 30, 4, 218, 6, 72, 32, + 247, 255, 251, 11, 34, 0, 103, 58, 76, 31, 224, 2, 72, 31, 247, 255, 251, 4, 53, 1, 44, 0, 218, 7, 15, 233, 34, 0, 35, + 4, 66, 171, 65, 74, 6, 18, 42, 0, 209, 172, 44, 0, 219, 4, 72, 24, 247, 255, 250, 244, 224, 0, 76, 6, 176, 9, 28, 32, + 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 96, 60, 19, 112, 97, 75, 19, 112, 97, 0, 255, 255, 251, 161, 19, 112, 97, + 30, 19, 112, 97, 69, 149, 11, 32, 119, 255, 255, 251, 160, 19, 112, 97, 106, 255, 255, 247, 103, 19, 112, 97, 155, 19, + 112, 97, 181, 255, 255, 224, 192, 19, 112, 97, 212, 19, 112, 97, 243, 19, 112, 98, 55, 19, 112, 98, 14, 255, 255, 247, + 62, 19, 112, 98, 52, 19, 112, 98, 87, 181, 16, 75, 10, 34, 1, 104, 27, 28, 4, 104, 155, 96, 154, 247, 255, 248, 95, + 40, 0, 219, 2, 28, 32, 247, 255, 254, 202, 75, 3, 34, 4, 104, 27, 104, 155, 96, 154, 188, 16, 188, 2, 71, 8, 19, 112, + 96, 60, 181, 240, 176, 141, 144, 6, 32, 22, 28, 13, 240, 2, 250, 217, 30, 7, 209, 0, 224, 214, 32, 10, 247, 254, 253, + 137, 35, 18, 147, 0, 152, 6, 28, 57, 34, 1, 35, 0, 247, 255, 253, 197, 40, 0, 218, 54, 72, 180, 247, 255, 250, 146, + 76, 179, 104, 32, 247, 255, 255, 202, 28, 6, 32, 20, 247, 254, 253, 116, 75, 176, 104, 32, 104, 27, 0, 130, 104, 155, + 51, 68, 24, 155, 104, 26, 46, 0, 219, 4, 75, 172, 64, 26, 75, 172, 66, 154, 208, 13, 247, 255, 254, 81, 32, 20, 247, + 254, 253, 96, 75, 166, 104, 27, 104, 154, 75, 164, 50, 68, 104, 27, 0, 155, 24, 211, 104, 27, 32, 30, 247, 254, 253, + 84, 35, 18, 147, 0, 152, 6, 28, 57, 34, 1, 35, 0, 247, 255, 253, 144, 30, 4, 218, 1, 72, 158, 224, 165, 28, 57, 34, + 18, 28, 40, 240, 3, 250, 83, 28, 56, 240, 2, 250, 168, 120, 170, 120, 235, 2, 18, 67, 26, 4, 18, 10, 19, 14, 18, 67, + 19, 4, 27, 12, 26, 112, 234, 14, 27, 122, 42, 112, 171, 122, 107, 2, 18, 67, 26, 4, 18, 10, 19, 14, 18, 67, 19, 4, 27, + 12, 26, 114, 106, 14, 27, 122, 170, 114, 43, 122, 235, 2, 18, 67, 26, 4, 18, 10, 19, 14, 18, 67, 19, 4, 27, 12, 26, + 114, 234, 14, 27, 123, 42, 114, 171, 123, 107, 2, 18, 67, 26, 4, 18, 10, 19, 14, 18, 67, 19, 4, 27, 12, 26, 14, 27, + 115, 43, 124, 107, 115, 106, 0, 88, 24, 192, 0, 128, 24, 192, 240, 2, 250, 79, 14, 3, 116, 171, 12, 3, 116, 235, 10, + 3, 117, 43, 117, 104, 40, 0, 209, 1, 72, 120, 224, 204, 124, 107, 33, 0, 0, 90, 24, 210, 0, 146, 24, 210, 240, 3, 250, + 68, 33, 0, 145, 10, 145, 5, 28, 46, 225, 51, 32, 9, 240, 2, 250, 52, 30, 4, 208, 49, 154, 5, 28, 33, 6, 19, 14, 27, + 147, 3, 35, 9, 147, 0, 34, 2, 155, 3, 152, 6, 247, 255, 253, 32, 124, 179, 124, 245, 6, 27, 4, 45, 67, 29, 125, 51, + 28, 33, 2, 27, 67, 29, 125, 115, 34, 9, 67, 29, 155, 10, 24, 237, 28, 40, 240, 3, 249, 219, 28, 32, 240, 2, 250, 48, + 120, 170, 120, 235, 2, 18, 67, 26, 4, 18, 10, 19, 14, 18, 67, 19, 4, 27, 12, 28, 14, 27, 112, 171, 112, 236, 28, 32, + 240, 2, 250, 2, 30, 7, 209, 6, 28, 53, 72, 86, 36, 4, 247, 255, 249, 199, 66, 100, 225, 3, 120, 235, 152, 6, 147, 0, + 28, 57, 34, 2, 155, 3, 247, 255, 252, 235, 40, 0, 218, 5, 28, 4, 72, 78, 28, 53, 247, 255, 249, 182, 224, 238, 120, + 41, 145, 2, 121, 43, 0, 216, 24, 192, 0, 64, 240, 2, 249, 225, 14, 3, 114, 107, 12, 3, 114, 171, 10, 3, 114, 235, 115, + 40, 40, 0, 209, 2, 28, 53, 72, 68, 224, 93, 155, 2, 154, 2, 26, 228, 25, 210, 146, 3, 148, 4, 121, 43, 33, 0, 0, 218, + 24, 210, 0, 82, 240, 3, 249, 208, 33, 0, 145, 11, 145, 8, 224, 177, 122, 107, 122, 172, 6, 27, 4, 36, 67, 28, 122, 235, + 154, 11, 2, 27, 67, 28, 123, 43, 153, 3, 67, 28, 24, 164, 28, 32, 34, 9, 240, 3, 249, 121, 120, 35, 147, 2, 121, 35, + 0, 216, 26, 192, 240, 2, 249, 172, 14, 3, 115, 163, 12, 3, 115, 227, 10, 3, 116, 35, 116, 96, 40, 0, 209, 2, 28, 53, + 72, 42, 224, 40, 153, 3, 155, 4, 28, 10, 153, 2, 24, 82, 153, 2, 146, 3, 26, 91, 147, 4, 121, 35, 33, 0, 0, 218, 26, + 210, 240, 3, 249, 153, 152, 3, 153, 4, 247, 255, 248, 27, 35, 11, 144, 2, 70, 106, 92, 154, 115, 98, 155, 2, 43, 0, + 208, 31, 28, 24, 240, 2, 249, 130, 14, 3, 114, 99, 12, 3, 114, 163, 10, 3, 114, 227, 115, 32, 40, 0, 209, 6, 72, 23, + 28, 53, 36, 4, 247, 255, 249, 64, 66, 100, 224, 119, 153, 3, 154, 2, 240, 3, 249, 52, 153, 3, 155, 4, 28, 10, 153, 2, + 24, 82, 153, 2, 146, 3, 26, 91, 147, 4, 34, 0, 146, 7, 146, 9, 224, 68, 70, 192, 19, 112, 98, 121, 19, 112, 107, 104, + 19, 112, 96, 60, 0, 0, 49, 5, 0, 0, 16, 5, 19, 112, 98, 163, 19, 112, 98, 198, 19, 112, 98, 96, 19, 112, 98, 236, 19, + 112, 99, 22, 19, 112, 99, 56, 19, 112, 99, 89, 123, 162, 123, 227, 6, 18, 4, 27, 67, 19, 124, 34, 153, 7, 2, 18, 67, + 19, 124, 98, 67, 19, 24, 201, 145, 2, 28, 8, 34, 7, 153, 3, 240, 3, 248, 252, 154, 2, 153, 3, 120, 19, 24, 201, 145, + 3, 153, 2, 121, 18, 121, 75, 2, 18, 67, 26, 4, 18, 10, 17, 14, 19, 67, 11, 4, 27, 153, 2, 12, 26, 14, 27, 113, 11, 113, + 74, 154, 9, 155, 7, 50, 1, 51, 7, 146, 9, 147, 7, 121, 35, 153, 9, 66, 153, 211, 207, 154, 8, 155, 11, 50, 1, 51, 18, + 146, 8, 147, 11, 121, 43, 153, 8, 66, 153, 210, 0, 231, 72, 28, 56, 240, 2, 249, 40, 154, 5, 155, 10, 50, 1, 51, 13, + 146, 5, 147, 10, 39, 0, 124, 115, 153, 5, 66, 153, 210, 0, 230, 198, 28, 53, 36, 0, 47, 0, 208, 7, 28, 56, 240, 2, 249, + 21, 44, 0, 208, 2, 28, 40, 247, 254, 255, 145, 176, 13, 28, 32, 188, 240, 188, 2, 71, 8, 70, 192, 181, 248, 28, 4, 38, + 3, 39, 64, 224, 79, 104, 160, 240, 3, 248, 112, 10, 3, 64, 51, 28, 5, 43, 2, 208, 7, 107, 227, 108, 34, 105, 89, 24, + 138, 0, 65, 12, 73, 26, 82, 97, 90, 108, 35, 43, 0, 208, 59, 66, 47, 208, 57, 75, 36, 120, 27, 43, 0, 208, 2, 72, 35, + 247, 255, 248, 151, 6, 235, 213, 6, 75, 32, 120, 27, 43, 0, 208, 2, 72, 32, 247, 255, 248, 142, 7, 107, 213, 6, 75, + 27, 120, 27, 43, 0, 208, 2, 72, 28, 247, 255, 248, 133, 6, 171, 213, 6, 75, 23, 120, 27, 43, 0, 208, 2, 72, 25, 247, + 255, 248, 124, 7, 43, 213, 6, 75, 18, 120, 27, 43, 0, 208, 2, 72, 21, 247, 255, 248, 115, 75, 15, 120, 27, 43, 0, 208, + 2, 72, 19, 247, 255, 248, 108, 75, 11, 120, 27, 43, 0, 208, 8, 72, 16, 247, 255, 248, 101, 224, 4, 107, 164, 44, 0, + 209, 173, 32, 0, 224, 3, 107, 227, 32, 1, 66, 64, 97, 88, 75, 11, 34, 0, 104, 27, 100, 26, 188, 248, 188, 2, 71, 8, + 19, 112, 107, 20, 19, 112, 99, 118, 19, 112, 99, 131, 19, 112, 99, 139, 19, 112, 99, 160, 19, 112, 99, 179, 19, 112, + 99, 190, 19, 112, 105, 116, 19, 112, 96, 60, 181, 240, 176, 131, 144, 1, 35, 9, 7, 192, 213, 60, 75, 59, 120, 27, 43, + 0, 208, 2, 72, 58, 247, 255, 248, 53, 75, 58, 104, 28, 44, 0, 208, 9, 107, 96, 33, 96, 240, 3, 249, 67, 107, 96, 33, + 96, 240, 2, 248, 49, 107, 164, 231, 243, 76, 52, 104, 35, 43, 0, 208, 24, 108, 88, 33, 32, 240, 3, 249, 53, 104, 35, + 33, 32, 108, 88, 240, 2, 248, 34, 104, 35, 34, 128, 4, 82, 97, 26, 74, 44, 108, 88, 104, 18, 33, 32, 107, 82, 97, 90, + 240, 3, 249, 58, 104, 35, 105, 154, 75, 40, 96, 26, 75, 36, 104, 24, 247, 255, 255, 78, 35, 0, 40, 0, 208, 4, 74, 37, + 104, 18, 100, 19, 35, 5, 66, 91, 152, 1, 7, 64, 213, 40, 75, 27, 120, 27, 43, 0, 208, 2, 72, 32, 247, 254, 255, 244, + 32, 128, 1, 128, 79, 28, 78, 30, 33, 0, 35, 1, 34, 0, 70, 132, 104, 56, 104, 132, 104, 48, 52, 68, 24, 100, 104, 37, + 66, 130, 209, 7, 32, 1, 66, 40, 209, 10, 75, 23, 80, 88, 35, 1, 66, 91, 224, 5, 72, 21, 64, 5, 45, 3, 209, 1, 70, 96, + 96, 32, 50, 1, 49, 4, 42, 4, 209, 229, 43, 0, 208, 5, 153, 1, 34, 18, 66, 10, 208, 1, 35, 6, 66, 91, 176, 3, 28, 24, + 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 107, 20, 19, 112, 99, 207, 19, 112, 107, 56, 19, 112, 107, 28, 19, 112, 107, + 40, 19, 112, 107, 36, 19, 112, 96, 60, 19, 112, 99, 240, 19, 112, 107, 104, 19, 112, 107, 108, 0, 0, 32, 3, 181, 240, + 176, 131, 147, 1, 70, 107, 51, 39, 120, 30, 28, 5, 30, 115, 6, 27, 14, 27, 145, 0, 28, 23, 43, 15, 216, 61, 28, 4, 52, + 160, 104, 32, 40, 0, 208, 56, 33, 0, 34, 31, 240, 2, 255, 211, 104, 35, 74, 29, 96, 26, 28, 43, 51, 152, 104, 24, 240, + 2, 255, 79, 104, 35, 96, 88, 28, 56, 240, 2, 255, 74, 104, 35, 70, 105, 96, 152, 29, 202, 120, 17, 104, 35, 70, 106, + 115, 25, 28, 209, 104, 35, 120, 10, 115, 90, 104, 34, 35, 6, 46, 6, 217, 0, 35, 10, 28, 44, 115, 147, 52, 160, 104, + 32, 153, 8, 28, 50, 48, 15, 240, 2, 255, 106, 28, 43, 51, 144, 104, 24, 123, 105, 104, 35, 34, 31, 247, 255, 249, 212, + 40, 31, 208, 6, 40, 0, 219, 5, 72, 5, 224, 3, 32, 3, 66, 64, 224, 0, 32, 0, 176, 3, 188, 240, 188, 2, 71, 8, 85, 83, + 66, 67, 255, 255, 216, 238, 181, 240, 28, 4, 176, 131, 52, 160, 28, 5, 145, 0, 28, 23, 33, 255, 34, 13, 104, 32, 240, + 2, 255, 134, 28, 43, 51, 144, 104, 24, 123, 41, 104, 35, 34, 13, 247, 255, 249, 174, 40, 13, 208, 1, 40, 0, 218, 40, + 40, 0, 219, 43, 28, 43, 51, 160, 104, 28, 104, 32, 240, 2, 254, 246, 144, 1, 104, 96, 240, 2, 254, 242, 28, 6, 104, + 160, 240, 2, 254, 238, 74, 16, 153, 1, 123, 35, 66, 145, 209, 21, 47, 0, 208, 0, 96, 56, 154, 0, 42, 0, 208, 0, 112, + 19, 53, 152, 104, 43, 66, 158, 209, 12, 28, 179, 4, 27, 12, 54, 12, 27, 4, 54, 67, 30, 96, 46, 32, 0, 224, 4, 72, 5, + 224, 2, 72, 5, 224, 0, 72, 5, 176, 3, 188, 240, 188, 2, 71, 8, 83, 66, 83, 85, 255, 255, 216, 237, 255, 255, 216, 236, + 255, 255, 216, 235, 181, 240, 176, 135, 74, 78, 75, 79, 120, 18, 28, 6, 104, 31, 42, 0, 208, 1, 73, 77, 224, 0, 73, + 77, 96, 25, 28, 51, 51, 144, 104, 24, 75, 75, 104, 27, 104, 153, 105, 195, 49, 68, 0, 155, 24, 203, 104, 25, 35, 1, + 66, 11, 209, 9, 74, 71, 36, 1, 104, 17, 74, 70, 0, 137, 80, 139, 75, 64, 66, 100, 96, 31, 224, 116, 75, 62, 42, 0, 208, + 1, 74, 61, 224, 0, 74, 61, 96, 26, 75, 64, 120, 27, 43, 0, 208, 17, 136, 243, 34, 255, 147, 0, 33, 33, 35, 0, 147, 1, + 147, 2, 247, 255, 249, 75, 28, 4, 28, 33, 72, 58, 247, 254, 254, 198, 32, 60, 247, 254, 249, 173, 224, 6, 33, 0, 247, + 255, 249, 161, 32, 5, 247, 254, 249, 166, 36, 0, 75, 43, 120, 26, 75, 43, 42, 0, 208, 1, 74, 42, 224, 0, 74, 42, 28, + 53, 96, 26, 53, 144, 44, 0, 218, 10, 32, 50, 247, 254, 249, 149, 104, 40, 33, 0, 247, 255, 249, 137, 32, 5, 247, 254, + 249, 142, 224, 48, 123, 49, 104, 40, 247, 255, 249, 129, 28, 4, 32, 5, 247, 254, 249, 133, 72, 36, 28, 33, 247, 254, + 254, 151, 44, 0, 219, 34, 123, 113, 104, 40, 247, 255, 249, 115, 28, 4, 32, 5, 247, 254, 249, 119, 72, 30, 28, 33, 247, + 254, 254, 137, 44, 0, 219, 20, 32, 10, 247, 254, 249, 110, 70, 105, 49, 23, 104, 40, 247, 255, 249, 138, 28, 4, 28, + 33, 72, 23, 247, 254, 254, 122, 44, 0, 219, 5, 72, 21, 247, 254, 254, 117, 75, 9, 96, 31, 224, 7, 75, 7, 33, 1, 96, + 31, 75, 10, 104, 26, 75, 10, 0, 146, 80, 209, 176, 7, 28, 32, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 1, 15, 19, + 112, 96, 56, 0, 15, 66, 64, 0, 3, 13, 64, 19, 112, 96, 60, 19, 112, 107, 104, 19, 112, 107, 108, 19, 112, 1, 13, 19, + 112, 100, 17, 19, 112, 100, 50, 19, 112, 100, 89, 19, 112, 100, 129, 19, 112, 100, 176, 181, 240, 176, 141, 146, 6, + 70, 106, 50, 79, 120, 18, 28, 31, 70, 107, 51, 95, 146, 7, 70, 106, 120, 27, 50, 83, 120, 18, 6, 27, 22, 27, 146, 8, + 70, 106, 50, 47, 147, 4, 35, 0, 112, 19, 74, 156, 145, 5, 104, 17, 74, 156, 0, 137, 77, 156, 28, 6, 147, 10, 80, 139, + 147, 3, 36, 0, 28, 163, 43, 1, 216, 5, 75, 149, 33, 1, 104, 26, 75, 149, 0, 146, 224, 30, 44, 0, 208, 36, 28, 48, 33, + 0, 247, 255, 255, 22, 30, 4, 219, 1, 32, 5, 224, 0, 32, 60, 247, 254, 248, 253, 74, 143, 75, 139, 104, 18, 104, 27, + 104, 146, 0, 155, 50, 68, 24, 210, 104, 18, 44, 0, 218, 12, 154, 3, 50, 1, 146, 3, 42, 2, 221, 3, 74, 133, 33, 1, 80, + 153, 224, 231, 32, 10, 247, 254, 248, 230, 224, 219, 35, 0, 147, 3, 155, 4, 154, 8, 59, 1, 6, 27, 22, 27, 147, 4, 42, + 0, 208, 59, 104, 43, 74, 126, 147, 2, 120, 19, 43, 0, 208, 1, 75, 125, 224, 0, 75, 125, 96, 43, 154, 7, 155, 18, 146, + 1, 147, 0, 28, 58, 35, 0, 28, 48, 153, 5, 247, 255, 254, 47, 75, 115, 154, 2, 28, 4, 96, 26, 28, 131, 43, 1, 216, 0, + 224, 189, 40, 0, 218, 0, 224, 178, 155, 6, 34, 144, 25, 146, 28, 60, 147, 2, 146, 9, 224, 18, 155, 9, 123, 113, 104, + 24, 28, 34, 155, 2, 247, 255, 248, 48, 28, 131, 43, 1, 216, 0, 224, 159, 40, 0, 219, 69, 66, 160, 209, 67, 154, 2, 26, + 36, 24, 18, 146, 2, 44, 0, 209, 234, 224, 62, 104, 43, 74, 96, 147, 2, 120, 19, 43, 0, 208, 1, 75, 95, 224, 0, 75, 95, + 96, 43, 154, 7, 155, 18, 146, 1, 147, 0, 28, 58, 35, 128, 28, 48, 153, 5, 247, 255, 253, 243, 75, 85, 154, 2, 28, 4, + 96, 26, 40, 0, 218, 3, 72, 87, 28, 33, 247, 254, 253, 151, 28, 163, 43, 1, 217, 124, 44, 0, 218, 22, 224, 113, 28, 51, + 51, 144, 104, 24, 123, 49, 28, 58, 155, 6, 247, 254, 255, 245, 30, 4, 218, 3, 72, 78, 28, 33, 247, 254, 253, 131, 28, + 163, 43, 1, 217, 96, 44, 0, 219, 5, 66, 188, 208, 5, 224, 2, 47, 0, 209, 231, 224, 1, 76, 71, 224, 86, 75, 63, 74, 65, + 104, 27, 147, 2, 120, 19, 43, 0, 208, 1, 75, 63, 224, 0, 75, 63, 74, 58, 70, 105, 96, 19, 28, 48, 49, 47, 170, 10, 247, + 255, 254, 14, 30, 4, 218, 34, 72, 61, 28, 33, 247, 254, 253, 94, 28, 99, 209, 3, 75, 50, 154, 2, 96, 26, 224, 64, 28, + 52, 52, 144, 104, 32, 123, 49, 247, 255, 248, 52, 123, 51, 32, 15, 104, 34, 64, 24, 9, 219, 1, 27, 106, 81, 24, 27, + 32, 1, 64, 152, 67, 129, 98, 81, 70, 105, 28, 48, 49, 47, 170, 10, 247, 255, 253, 234, 28, 4, 75, 36, 154, 2, 96, 26, + 28, 163, 43, 1, 217, 33, 155, 10, 43, 0, 208, 7, 75, 40, 104, 27, 43, 0, 208, 3, 70, 107, 34, 1, 51, 47, 112, 26, 44, + 0, 219, 12, 75, 35, 36, 0, 104, 27, 43, 0, 208, 7, 70, 107, 51, 47, 120, 27, 43, 0, 208, 2, 76, 31, 224, 0, 28, 4, 155, + 4, 43, 0, 221, 2, 44, 0, 218, 0, 230, 239, 44, 0, 218, 4, 75, 14, 33, 1, 104, 26, 0, 146, 224, 3, 75, 11, 33, 0, 104, + 26, 0, 146, 75, 10, 80, 209, 154, 21, 42, 0, 208, 3, 70, 107, 51, 47, 120, 27, 112, 19, 155, 22, 43, 0, 208, 2, 155, + 10, 154, 22, 96, 19, 176, 13, 28, 32, 188, 240, 188, 2, 71, 8, 19, 112, 107, 104, 19, 112, 107, 108, 19, 112, 96, 56, + 19, 112, 96, 60, 19, 112, 1, 15, 0, 15, 66, 64, 0, 3, 13, 64, 19, 112, 100, 186, 19, 112, 100, 205, 255, 255, 216, 233, + 19, 112, 100, 229, 19, 112, 107, 64, 255, 255, 216, 234, 181, 240, 28, 3, 176, 143, 51, 160, 145, 7, 104, 30, 33, 128, + 70, 111, 1, 9, 55, 55, 37, 0, 172, 9, 24, 118, 144, 6, 112, 61, 28, 32, 33, 0, 34, 16, 240, 2, 253, 8, 46, 0, 208, 87, + 35, 6, 147, 1, 35, 1, 147, 2, 35, 10, 147, 5, 153, 7, 35, 0, 152, 6, 34, 0, 149, 4, 148, 0, 151, 3, 247, 255, 254, 113, + 28, 5, 28, 41, 72, 40, 247, 254, 252, 182, 28, 107, 208, 69, 45, 0, 219, 2, 120, 59, 43, 0, 208, 64, 153, 7, 171, 9, + 34, 3, 112, 26, 1, 74, 112, 90, 34, 18, 113, 26, 34, 0, 113, 90, 28, 48, 33, 0, 34, 18, 240, 2, 252, 220, 75, 28, 53, + 2, 209, 1, 74, 28, 224, 0, 74, 28, 96, 26, 171, 9, 147, 0, 35, 6, 147, 1, 35, 0, 147, 2, 147, 3, 147, 4, 35, 10, 147, + 5, 153, 7, 152, 6, 28, 50, 35, 18, 247, 255, 254, 63, 28, 5, 28, 41, 72, 19, 247, 254, 252, 132, 45, 0, 219, 19, 120, + 179, 33, 15, 70, 108, 64, 25, 52, 55, 72, 15, 112, 33, 247, 254, 252, 121, 120, 35, 59, 2, 6, 27, 14, 27, 43, 2, 217, + 3, 224, 3, 37, 4, 66, 109, 224, 0, 77, 9, 176, 15, 28, 40, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 100, 244, 19, + 112, 96, 56, 0, 38, 37, 160, 0, 152, 150, 128, 19, 112, 101, 21, 19, 112, 101, 52, 255, 255, 216, 239, 181, 240, 176, + 147, 70, 106, 79, 212, 35, 0, 50, 71, 112, 19, 28, 4, 104, 58, 72, 210, 37, 16, 84, 133, 72, 209, 28, 34, 50, 152, 96, + 16, 174, 12, 58, 8, 96, 17, 28, 8, 130, 115, 28, 49, 130, 179, 247, 255, 249, 149, 28, 5, 28, 41, 72, 203, 247, 254, + 252, 60, 45, 0, 218, 0, 225, 230, 104, 59, 74, 200, 0, 153, 88, 138, 42, 0, 208, 42, 74, 199, 24, 201, 0, 137, 24, 81, + 121, 136, 121, 50, 66, 144, 209, 25, 121, 200, 121, 114, 66, 144, 209, 21, 28, 10, 137, 8, 137, 49, 50, 8, 66, 136, + 209, 15, 136, 80, 137, 113, 66, 136, 209, 11, 121, 16, 123, 177, 66, 136, 209, 7, 121, 80, 123, 241, 66, 136, 209, 3, + 121, 145, 124, 50, 66, 145, 208, 8, 168, 12, 247, 254, 250, 225, 37, 1, 72, 181, 247, 254, 252, 10, 66, 109, 225, 195, + 0, 153, 24, 201, 72, 176, 171, 12, 121, 26, 0, 137, 24, 65, 113, 138, 121, 90, 38, 0, 113, 202, 137, 24, 28, 10, 129, + 8, 137, 89, 50, 8, 128, 81, 123, 153, 113, 17, 123, 217, 113, 81, 124, 27, 113, 147, 74, 168, 35, 128, 66, 91, 96, 19, + 35, 0, 147, 8, 147, 5, 224, 232, 138, 111, 138, 171, 154, 8, 4, 63, 67, 31, 24, 191, 122, 58, 72, 161, 0, 82, 153, 5, + 247, 254, 251, 221, 34, 156, 35, 0, 25, 18, 147, 10, 147, 6, 146, 11, 224, 202, 122, 123, 122, 189, 6, 27, 4, 45, 67, + 29, 122, 251, 2, 27, 67, 29, 123, 59, 67, 29, 155, 10, 24, 237, 121, 107, 43, 8, 209, 126, 121, 235, 43, 80, 209, 123, + 121, 43, 43, 1, 217, 120, 154, 11, 35, 1, 112, 19, 121, 169, 72, 144, 34, 1, 247, 254, 251, 185, 35, 0, 115, 102, 115, + 38, 147, 9, 147, 7, 224, 49, 123, 170, 123, 235, 6, 18, 4, 27, 67, 19, 124, 42, 2, 18, 67, 19, 124, 106, 67, 19, 154, + 9, 24, 155, 120, 218, 42, 2, 209, 28, 120, 154, 6, 17, 41, 0, 218, 11, 123, 33, 41, 0, 209, 8, 42, 0, 208, 6, 115, 34, + 121, 25, 121, 91, 2, 9, 67, 25, 72, 125, 224, 10, 123, 97, 41, 0, 209, 9, 42, 0, 208, 7, 115, 98, 121, 25, 121, 91, + 2, 9, 72, 121, 67, 25, 247, 254, 251, 135, 155, 7, 154, 9, 51, 1, 50, 7, 147, 7, 146, 9, 121, 43, 154, 7, 66, 154, 211, + 201, 123, 33, 41, 0, 208, 104, 123, 98, 42, 0, 208, 101, 72, 112, 247, 254, 251, 116, 73, 98, 74, 103, 104, 11, 0, 152, + 24, 195, 0, 155, 123, 32, 24, 211, 116, 24, 123, 96, 116, 88, 121, 123, 112, 35, 104, 9, 120, 171, 0, 136, 24, 65, 0, + 137, 24, 82, 96, 99, 115, 211, 120, 235, 168, 12, 96, 163, 247, 254, 250, 45, 75, 92, 74, 98, 72, 98, 96, 26, 120, 33, + 104, 162, 247, 254, 251, 82, 28, 35, 51, 144, 70, 105, 104, 24, 49, 71, 247, 254, 254, 86, 40, 0, 218, 89, 224, 85, + 123, 170, 123, 235, 6, 18, 4, 27, 67, 19, 124, 42, 124, 104, 2, 18, 67, 19, 67, 24, 208, 1, 240, 1, 251, 141, 122, 106, + 122, 171, 6, 18, 4, 27, 67, 19, 122, 234, 123, 40, 2, 18, 67, 19, 115, 174, 115, 238, 116, 46, 116, 110, 67, 24, 208, + 1, 240, 1, 251, 124, 121, 107, 114, 110, 114, 174, 114, 238, 115, 46, 43, 9, 209, 4, 74, 73, 75, 64, 168, 12, 96, 26, + 224, 39, 43, 8, 209, 10, 121, 235, 43, 80, 209, 7, 121, 43, 43, 1, 217, 4, 121, 171, 74, 67, 26, 211, 74, 57, 96, 19, + 155, 6, 154, 10, 51, 1, 50, 18, 147, 6, 146, 10, 121, 59, 154, 6, 66, 154, 210, 0, 231, 47, 155, 5, 154, 8, 51, 1, 50, + 13, 147, 5, 146, 8, 173, 12, 124, 107, 154, 5, 66, 154, 210, 0, 231, 16, 72, 54, 247, 254, 250, 247, 28, 40, 247, 254, + 249, 199, 77, 50, 224, 159, 72, 51, 247, 254, 250, 239, 70, 107, 51, 71, 120, 25, 120, 34, 72, 49, 247, 254, 250, 232, + 75, 35, 74, 48, 96, 26, 28, 35, 51, 144, 104, 24, 120, 33, 247, 254, 253, 220, 40, 0, 218, 2, 72, 44, 247, 254, 250, + 218, 74, 43, 75, 28, 121, 225, 96, 26, 28, 35, 51, 144, 104, 24, 122, 226, 247, 254, 253, 191, 40, 0, 218, 2, 72, 38, + 247, 254, 250, 203, 72, 38, 70, 109, 247, 254, 250, 199, 53, 70, 35, 0, 112, 43, 28, 35, 51, 144, 104, 24, 136, 227, + 33, 161, 147, 0, 35, 1, 147, 1, 34, 254, 35, 0, 149, 2, 247, 254, 253, 55, 40, 0, 218, 58, 72, 28, 247, 254, 250, 178, + 35, 8, 115, 163, 224, 60, 70, 192, 19, 112, 107, 104, 19, 112, 96, 64, 44, 13, 224, 1, 19, 112, 101, 86, 19, 112, 107, + 76, 19, 114, 198, 232, 19, 112, 101, 128, 19, 112, 107, 32, 19, 112, 101, 166, 19, 112, 101, 205, 19, 112, 102, 4, 19, + 112, 102, 18, 19, 112, 102, 33, 255, 255, 251, 79, 19, 112, 102, 102, 255, 255, 177, 224, 255, 255, 216, 240, 19, 112, + 102, 53, 19, 112, 102, 148, 19, 112, 102, 189, 255, 255, 251, 78, 19, 112, 102, 222, 255, 255, 251, 77, 19, 112, 102, + 252, 19, 112, 103, 43, 19, 112, 103, 102, 120, 41, 72, 29, 49, 1, 6, 9, 14, 9, 115, 161, 247, 254, 250, 114, 28, 35, + 51, 160, 104, 27, 43, 0, 209, 16, 77, 24, 104, 43, 43, 0, 209, 7, 32, 129, 1, 64, 240, 1, 250, 153, 35, 31, 48, 31, + 67, 152, 96, 40, 74, 18, 28, 35, 104, 18, 51, 160, 96, 26, 52, 160, 104, 35, 37, 0, 43, 0, 209, 4, 74, 14, 75, 14, 37, + 4, 96, 26, 66, 109, 74, 13, 75, 14, 96, 26, 45, 0, 208, 5, 75, 10, 72, 12, 104, 25, 247, 254, 250, 72, 224, 2, 72, 11, + 247, 254, 250, 68, 176, 19, 28, 40, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 103, 141, 19, 112, 107, 24, 255, 255, + 251, 75, 19, 112, 107, 32, 0, 15, 66, 64, 19, 112, 96, 56, 19, 112, 103, 164, 19, 112, 103, 198, 181, 8, 33, 0, 247, + 255, 251, 38, 188, 8, 188, 2, 71, 8, 0, 0, 181, 240, 176, 139, 171, 8, 34, 18, 112, 26, 1, 74, 112, 90, 34, 0, 112, + 154, 112, 218, 113, 90, 28, 15, 28, 2, 33, 36, 50, 160, 113, 25, 104, 20, 34, 128, 1, 18, 24, 164, 144, 7, 44, 0, 208, + 48, 38, 0, 33, 0, 34, 36, 28, 32, 240, 2, 250, 69, 171, 8, 34, 6, 147, 0, 35, 10, 37, 0, 146, 1, 147, 5, 152, 7, 28, + 57, 28, 34, 35, 36, 149, 2, 149, 3, 149, 4, 247, 255, 251, 175, 40, 0, 219, 7, 120, 35, 34, 31, 64, 19, 43, 5, 208, + 6, 43, 7, 209, 11, 224, 3, 54, 1, 46, 2, 208, 15, 231, 220, 75, 9, 33, 1, 104, 26, 75, 8, 0, 146, 80, 209, 224, 7, 75, + 5, 104, 26, 75, 5, 0, 146, 80, 213, 224, 1, 32, 4, 66, 64, 176, 11, 188, 240, 188, 2, 71, 8, 19, 112, 107, 104, 19, + 112, 107, 44, 181, 112, 176, 136, 28, 22, 28, 29, 34, 37, 171, 7, 112, 26, 1, 74, 112, 90, 28, 2, 50, 160, 104, 20, + 34, 128, 1, 18, 24, 164, 44, 0, 208, 34, 147, 0, 35, 2, 147, 1, 35, 0, 147, 2, 147, 3, 147, 4, 35, 10, 147, 5, 28, 34, + 35, 8, 247, 255, 251, 108, 40, 0, 219, 21, 168, 6, 28, 33, 34, 4, 240, 2, 249, 169, 45, 0, 208, 1, 155, 6, 96, 43, 29, + 33, 168, 6, 34, 4, 240, 2, 249, 160, 32, 0, 46, 0, 208, 4, 155, 6, 96, 51, 224, 1, 32, 4, 66, 64, 176, 8, 188, 112, + 188, 2, 71, 8, 181, 240, 176, 131, 123, 131, 28, 15, 28, 5, 66, 187, 217, 72, 78, 40, 73, 40, 72, 41, 96, 49, 33, 0, + 247, 254, 249, 140, 75, 39, 28, 40, 96, 51, 28, 57, 247, 255, 252, 166, 30, 4, 219, 53, 74, 33, 28, 57, 96, 50, 28, + 40, 247, 255, 255, 88, 28, 4, 28, 33, 72, 32, 247, 254, 249, 121, 44, 0, 219, 40, 28, 43, 51, 160, 104, 26, 35, 128, + 1, 27, 92, 211, 33, 31, 64, 25, 72, 27, 247, 254, 249, 108, 28, 59, 29, 62, 51, 20, 0, 182, 0, 155, 25, 170, 147, 1, + 28, 57, 24, 235, 28, 40, 247, 255, 255, 140, 153, 1, 28, 4, 89, 75, 89, 114, 72, 18, 28, 33, 247, 254, 249, 88, 89, + 114, 75, 17, 66, 154, 217, 3, 154, 1, 89, 83, 43, 9, 216, 1, 36, 33, 66, 100, 74, 6, 75, 5, 96, 26, 224, 1, 36, 3, 66, + 100, 176, 3, 28, 32, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 96, 56, 0, 15, 66, 64, 19, 112, 103, 231, 1, 49, 45, + 0, 19, 112, 104, 2, 19, 112, 104, 22, 19, 112, 104, 43, 0, 0, 1, 255, 181, 240, 176, 141, 175, 9, 37, 40, 112, 61, 1, + 77, 112, 125, 14, 21, 112, 189, 70, 110, 12, 21, 36, 0, 112, 253, 113, 122, 10, 21, 54, 47, 10, 26, 112, 52, 113, 61, + 113, 188, 113, 250, 114, 59, 114, 124, 123, 130, 66, 138, 217, 28, 29, 10, 0, 146, 88, 18, 146, 7, 42, 0, 208, 22, 77, + 15, 34, 1, 96, 42, 154, 7, 151, 0, 67, 83, 34, 10, 146, 1, 34, 6, 146, 5, 154, 18, 148, 2, 150, 3, 148, 4, 247, 255, + 250, 184, 96, 44, 40, 0, 221, 7, 120, 51, 43, 0, 209, 3, 224, 3, 32, 3, 66, 64, 224, 0, 72, 3, 176, 13, 188, 240, 188, + 2, 71, 8, 70, 192, 19, 112, 107, 64, 255, 255, 216, 234, 181, 240, 176, 141, 147, 7, 1, 75, 175, 9, 37, 42, 70, 156, + 112, 61, 35, 8, 70, 101, 67, 43, 112, 123, 14, 21, 155, 7, 112, 189, 70, 110, 12, 21, 36, 0, 112, 253, 113, 122, 10, + 21, 54, 47, 10, 26, 112, 52, 113, 61, 113, 188, 113, 250, 114, 59, 114, 124, 123, 130, 66, 138, 217, 32, 29, 10, 0, + 146, 88, 18, 70, 148, 69, 164, 208, 26, 77, 17, 35, 1, 96, 43, 155, 7, 151, 0, 70, 98, 67, 90, 70, 148, 34, 1, 146, + 2, 34, 6, 146, 5, 39, 10, 154, 18, 70, 99, 151, 1, 150, 3, 148, 4, 247, 255, 250, 106, 96, 44, 40, 0, 221, 7, 120, 51, + 43, 0, 209, 3, 224, 3, 32, 3, 66, 64, 224, 0, 72, 3, 176, 13, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 107, 64, 255, + 255, 216, 234, 181, 240, 176, 135, 28, 28, 147, 2, 28, 11, 51, 4, 0, 155, 145, 3, 88, 25, 28, 6, 28, 11, 67, 99, 32, + 128, 2, 64, 28, 23, 66, 131, 217, 2, 240, 2, 249, 135, 144, 2, 155, 3, 32, 1, 51, 4, 0, 155, 66, 64, 147, 5, 224, 28, + 154, 2, 28, 37, 66, 148, 217, 0, 28, 21, 4, 43, 12, 27, 147, 4, 155, 12, 28, 48, 147, 0, 153, 3, 28, 58, 155, 4, 247, + 255, 255, 67, 40, 0, 219, 12, 154, 4, 25, 127, 26, 164, 154, 5, 4, 36, 89, 147, 12, 36, 67, 93, 155, 12, 25, 91, 147, + 12, 44, 0, 209, 224, 176, 7, 188, 240, 188, 2, 71, 8, 181, 240, 176, 135, 28, 28, 147, 2, 28, 11, 51, 4, 0, 155, 145, + 3, 88, 25, 28, 6, 28, 11, 67, 99, 32, 128, 2, 64, 28, 23, 66, 131, 217, 2, 240, 2, 249, 73, 144, 2, 155, 3, 32, 1, 51, + 4, 0, 155, 66, 64, 147, 5, 224, 28, 154, 2, 28, 37, 66, 148, 217, 0, 28, 21, 4, 43, 12, 27, 147, 4, 155, 12, 28, 48, + 147, 0, 153, 3, 28, 58, 155, 4, 247, 255, 255, 73, 40, 0, 219, 12, 154, 4, 25, 127, 26, 164, 154, 5, 4, 36, 89, 147, + 12, 36, 67, 93, 155, 12, 25, 91, 147, 12, 44, 0, 209, 224, 176, 7, 188, 240, 188, 2, 71, 8, 181, 240, 176, 139, 76, + 181, 144, 8, 104, 32, 73, 181, 0, 67, 34, 0, 82, 90, 73, 180, 37, 0, 82, 90, 75, 179, 38, 164, 84, 29, 75, 179, 73, + 179, 84, 29, 67, 112, 35, 120, 74, 178, 66, 91, 24, 64, 96, 19, 153, 8, 247, 255, 251, 175, 40, 0, 218, 0, 225, 73, + 104, 35, 74, 172, 67, 94, 33, 1, 24, 182, 0, 154, 115, 177, 24, 210, 78, 170, 0, 146, 89, 144, 24, 178, 40, 0, 208, + 101, 121, 82, 42, 0, 209, 3, 74, 167, 120, 18, 66, 17, 208, 42, 38, 164, 67, 115, 77, 161, 32, 0, 24, 234, 28, 17, 49, + 8, 113, 136, 76, 162, 73, 162, 24, 235, 96, 33, 28, 17, 136, 210, 49, 144, 51, 14, 104, 8, 39, 1, 146, 0, 147, 2, 33, + 161, 35, 0, 34, 254, 151, 1, 247, 254, 250, 87, 75, 155, 96, 35, 75, 143, 40, 0, 218, 4, 104, 27, 67, 94, 25, 173, 115, + 175, 224, 253, 104, 27, 67, 94, 25, 173, 53, 8, 121, 171, 51, 1, 113, 171, 76, 135, 72, 147, 104, 35, 39, 164, 0, 154, + 24, 211, 74, 139, 0, 155, 24, 211, 121, 30, 28, 49, 247, 253, 255, 185, 104, 32, 75, 133, 67, 120, 28, 49, 24, 192, + 247, 255, 254, 24, 28, 5, 28, 41, 72, 137, 247, 253, 255, 173, 28, 171, 43, 1, 216, 13, 104, 32, 73, 126, 67, 71, 24, + 120, 247, 255, 253, 118, 74, 124, 35, 121, 66, 91, 96, 19, 33, 0, 104, 35, 74, 118, 224, 71, 45, 0, 218, 0, 224, 201, + 104, 35, 74, 115, 33, 1, 84, 209, 74, 115, 84, 214, 224, 186, 39, 1, 113, 85, 38, 0, 151, 6, 28, 37, 28, 50, 30, 83, + 65, 154, 146, 9, 42, 0, 209, 5, 75, 112, 120, 27, 7, 220, 213, 1, 47, 0, 209, 51, 72, 115, 28, 49, 247, 253, 255, 125, + 76, 99, 33, 164, 104, 32, 74, 102, 67, 72, 6, 51, 14, 27, 28, 25, 24, 128, 147, 5, 247, 255, 253, 215, 144, 7, 153, + 7, 72, 105, 247, 253, 255, 108, 155, 7, 51, 2, 43, 1, 216, 21, 155, 9, 43, 0, 208, 18, 104, 32, 33, 164, 75, 95, 67, + 72, 74, 96, 96, 26, 74, 89, 24, 128, 247, 255, 253, 45, 74, 88, 35, 121, 66, 91, 96, 19, 104, 35, 74, 82, 33, 0, 84, + 209, 224, 149, 155, 7, 43, 0, 218, 90, 47, 0, 208, 82, 104, 42, 39, 164, 0, 147, 67, 122, 76, 88, 73, 77, 32, 0, 81, + 24, 24, 139, 28, 25, 49, 8, 113, 136, 76, 78, 73, 78, 96, 33, 28, 25, 49, 144, 104, 8, 73, 71, 136, 219, 24, 82, 147, + 0, 50, 14, 35, 1, 147, 1, 146, 2, 35, 0, 33, 161, 34, 254, 247, 254, 249, 174, 75, 70, 144, 5, 96, 35, 40, 0, 218, 10, + 104, 43, 74, 61, 67, 95, 72, 70, 24, 191, 36, 1, 0, 155, 33, 0, 115, 188, 80, 25, 224, 14, 104, 43, 74, 56, 67, 95, + 24, 191, 55, 8, 121, 186, 36, 1, 50, 1, 113, 186, 0, 154, 24, 211, 74, 53, 0, 155, 24, 211, 113, 92, 75, 44, 34, 164, + 104, 27, 72, 58, 67, 83, 74, 46, 153, 5, 24, 211, 123, 155, 39, 0, 28, 26, 147, 6, 247, 253, 255, 1, 75, 45, 120, 27, + 7, 216, 213, 3, 153, 5, 15, 207, 224, 0, 54, 1, 154, 6, 66, 150, 218, 0, 231, 103, 224, 36, 75, 30, 72, 37, 104, 27, + 34, 1, 0, 153, 24, 201, 0, 137, 80, 10, 70, 108, 24, 65, 32, 23, 93, 4, 113, 12, 152, 8, 0, 89, 137, 4, 72, 23, 82, + 12, 152, 8, 137, 68, 72, 22, 82, 12, 73, 22, 36, 23, 84, 202, 70, 105, 74, 21, 92, 97, 84, 209, 74, 27, 75, 24, 32, + 0, 96, 26, 75, 20, 34, 0, 96, 26, 224, 20, 76, 12, 74, 17, 35, 122, 66, 91, 104, 32, 96, 19, 35, 164, 67, 88, 75, 13, + 24, 192, 247, 255, 252, 149, 104, 35, 74, 8, 33, 0, 84, 209, 72, 21, 247, 253, 254, 188, 32, 3, 66, 64, 176, 11, 188, + 240, 188, 2, 71, 8, 19, 112, 107, 104, 19, 112, 107, 60, 19, 112, 107, 68, 19, 112, 107, 84, 19, 112, 96, 64, 19, 114, + 197, 160, 19, 112, 107, 32, 19, 114, 198, 232, 19, 112, 1, 14, 19, 112, 96, 56, 0, 152, 150, 128, 0, 15, 66, 64, 19, + 112, 104, 98, 19, 112, 104, 128, 19, 112, 104, 103, 19, 112, 107, 108, 19, 112, 104, 157, 19, 112, 104, 198, 181, 16, + 75, 16, 104, 28, 75, 16, 0, 160, 88, 195, 43, 0, 208, 22, 74, 14, 93, 19, 43, 0, 208, 14, 75, 13, 33, 16, 85, 25, 35, + 0, 85, 19, 74, 12, 33, 0, 80, 131, 25, 0, 75, 11, 0, 128, 24, 192, 34, 20, 240, 1, 254, 179, 75, 4, 0, 164, 34, 0, 80, + 226, 188, 16, 188, 1, 71, 0, 19, 112, 107, 104, 19, 112, 107, 76, 19, 112, 107, 84, 19, 112, 96, 64, 19, 112, 107, 108, + 19, 114, 198, 232, 181, 240, 176, 135, 40, 1, 208, 4, 40, 2, 208, 6, 32, 0, 144, 2, 224, 5, 33, 1, 145, 2, 37, 1, 224, + 2, 34, 1, 146, 2, 37, 0, 78, 114, 34, 0, 104, 51, 32, 0, 104, 155, 0, 175, 96, 154, 247, 252, 255, 149, 74, 111, 35, + 100, 66, 91, 96, 19, 72, 110, 172, 4, 247, 253, 254, 67, 25, 228, 224, 177, 75, 105, 74, 107, 104, 30, 35, 1, 81, 211, + 72, 106, 75, 107, 33, 0, 81, 193, 85, 89, 0, 169, 25, 73, 74, 105, 0, 136, 35, 0, 80, 131, 35, 1, 66, 91, 96, 35, 0, + 203, 24, 243, 103, 93, 73, 101, 111, 27, 96, 13, 43, 0, 209, 57, 104, 179, 32, 1, 51, 68, 25, 219, 104, 27, 66, 24, + 209, 2, 28, 40, 247, 253, 252, 24, 73, 86, 104, 11, 104, 155, 51, 68, 25, 219, 104, 27, 7, 218, 213, 39, 28, 40, 247, + 254, 251, 77, 35, 140, 0, 219, 96, 32, 24, 192, 40, 1, 216, 4, 35, 100, 74, 78, 66, 91, 96, 19, 224, 115, 28, 40, 247, + 254, 249, 219, 144, 3, 96, 32, 32, 20, 247, 253, 248, 232, 72, 71, 153, 3, 104, 3, 104, 155, 51, 68, 25, 219, 104, 26, + 41, 0, 219, 4, 75, 75, 64, 26, 75, 75, 66, 154, 208, 3, 28, 40, 247, 254, 251, 41, 96, 32, 0, 168, 25, 64, 0, 192, 24, + 51, 111, 27, 43, 0, 208, 82, 74, 66, 73, 61, 104, 19, 48, 88, 0, 155, 34, 1, 80, 90, 24, 48, 247, 255, 253, 183, 40, + 0, 209, 67, 73, 60, 74, 56, 104, 11, 33, 1, 0, 155, 80, 153, 74, 53, 80, 152, 74, 59, 88, 155, 43, 0, 208, 1, 72, 58, + 224, 0, 72, 58, 247, 253, 253, 200, 72, 57, 247, 253, 253, 197, 32, 100, 247, 253, 248, 172, 78, 55, 75, 56, 32, 1, + 96, 51, 75, 55, 112, 24, 72, 55, 247, 253, 253, 185, 75, 44, 32, 164, 104, 27, 74, 53, 67, 88, 24, 128, 74, 53, 92, + 209, 75, 53, 34, 0, 147, 0, 35, 1, 247, 255, 253, 11, 73, 46, 75, 50, 34, 0, 96, 32, 112, 10, 96, 51, 40, 0, 218, 7, + 72, 48, 247, 253, 253, 160, 28, 40, 247, 253, 251, 199, 75, 46, 224, 3, 72, 46, 247, 253, 253, 152, 35, 1, 96, 35, 224, + 2, 28, 40, 247, 253, 251, 188, 53, 1, 52, 4, 55, 4, 152, 2, 66, 133, 220, 0, 231, 73, 72, 39, 247, 252, 254, 210, 73, + 12, 34, 4, 104, 11, 104, 155, 96, 154, 154, 4, 155, 5, 42, 1, 209, 6, 74, 9, 33, 0, 96, 17, 43, 1, 209, 5, 35, 2, 224, + 2, 43, 1, 209, 1, 74, 4, 96, 19, 75, 3, 104, 24, 176, 7, 188, 240, 188, 2, 71, 8, 19, 112, 96, 60, 19, 112, 107, 32, + 19, 112, 104, 227, 19, 112, 107, 108, 19, 112, 107, 76, 19, 112, 107, 84, 19, 114, 198, 232, 19, 112, 107, 104, 0, 0, + 57, 5, 0, 0, 16, 5, 19, 112, 107, 44, 19, 112, 105, 118, 19, 112, 105, 135, 19, 112, 105, 154, 19, 112, 96, 56, 0, 152, + 150, 128, 19, 112, 107, 20, 19, 112, 105, 203, 19, 114, 197, 160, 19, 112, 96, 64, 19, 112, 107, 160, 0, 7, 161, 32, + 19, 112, 105, 176, 255, 255, 251, 162, 19, 112, 105, 200, 19, 112, 17, 185, 181, 0, 30, 2, 208, 1, 35, 0, 96, 19, 75, + 19, 73, 19, 104, 27, 32, 0, 92, 201, 41, 1, 209, 28, 73, 17, 92, 201, 41, 16, 208, 24, 42, 0, 208, 9, 0, 152, 24, 192, + 0, 192, 24, 195, 24, 89, 49, 4, 72, 12, 0, 137, 88, 11, 96, 19, 75, 7, 74, 9, 104, 27, 0, 153, 24, 201, 92, 210, 0, + 201, 24, 203, 24, 155, 51, 20, 74, 5, 0, 155, 88, 152, 188, 2, 71, 8, 70, 192, 19, 112, 107, 104, 19, 112, 107, 84, + 19, 112, 96, 64, 19, 114, 197, 160, 181, 240, 176, 139, 75, 104, 104, 26, 75, 104, 0, 145, 88, 203, 43, 0, 209, 0, 224, + 188, 75, 102, 33, 16, 84, 153, 75, 102, 120, 25, 75, 102, 41, 0, 208, 1, 73, 101, 224, 0, 73, 101, 39, 164, 67, 122, + 78, 101, 96, 25, 172, 4, 35, 0, 24, 178, 130, 99, 130, 163, 50, 144, 104, 16, 28, 33, 247, 254, 250, 55, 77, 88, 104, + 43, 0, 154, 24, 211, 74, 94, 0, 155, 24, 210, 121, 145, 121, 35, 66, 153, 209, 25, 121, 209, 121, 99, 66, 153, 209, + 21, 28, 19, 137, 17, 137, 34, 51, 8, 66, 145, 209, 15, 136, 89, 137, 98, 66, 145, 209, 11, 121, 25, 123, 162, 66, 145, + 209, 7, 121, 89, 123, 226, 66, 145, 209, 3, 121, 154, 124, 35, 66, 154, 208, 6, 168, 4, 247, 253, 251, 142, 72, 77, + 247, 253, 252, 184, 224, 119, 28, 32, 247, 253, 251, 135, 74, 74, 75, 68, 96, 26, 104, 43, 67, 123, 24, 242, 50, 144, + 104, 16, 92, 241, 247, 253, 255, 166, 40, 0, 219, 105, 104, 43, 67, 95, 25, 246, 104, 178, 42, 0, 208, 9, 28, 51, 51, + 144, 6, 18, 104, 24, 121, 241, 14, 18, 247, 253, 255, 136, 40, 0, 219, 91, 75, 53, 120, 26, 75, 53, 42, 0, 208, 1, 74, + 52, 224, 0, 74, 52, 76, 46, 96, 26, 104, 34, 38, 164, 67, 114, 77, 50, 32, 0, 24, 171, 28, 25, 49, 8, 113, 136, 136, + 219, 49, 136, 24, 170, 104, 8, 50, 14, 33, 1, 147, 0, 145, 1, 146, 2, 33, 161, 34, 254, 35, 0, 247, 253, 254, 246, 40, + 0, 218, 9, 104, 32, 35, 1, 67, 70, 25, 168, 115, 131, 33, 0, 247, 254, 253, 104, 72, 39, 224, 51, 104, 35, 79, 35, 28, + 48, 67, 88, 24, 40, 28, 2, 50, 8, 121, 145, 49, 1, 113, 145, 0, 154, 24, 211, 0, 155, 24, 251, 121, 25, 247, 254, 255, + 121, 40, 0, 219, 29, 104, 35, 67, 94, 0, 154, 24, 211, 0, 155, 24, 251, 25, 112, 121, 25, 247, 255, 250, 39, 40, 0, + 219, 19, 104, 35, 0, 154, 24, 210, 0, 146, 24, 191, 121, 57, 74, 11, 84, 209, 74, 20, 33, 1, 84, 209, 224, 8, 72, 19, + 224, 6, 72, 19, 224, 4, 72, 19, 224, 2, 72, 19, 224, 0, 72, 19, 176, 11, 188, 240, 188, 2, 71, 8, 19, 112, 107, 104, + 19, 112, 107, 76, 19, 112, 96, 64, 19, 112, 1, 15, 19, 112, 96, 56, 0, 15, 66, 64, 0, 3, 13, 64, 19, 114, 197, 160, + 19, 114, 198, 232, 19, 112, 101, 128, 0, 12, 53, 0, 255, 255, 252, 20, 19, 112, 107, 84, 255, 255, 252, 15, 255, 255, + 252, 23, 255, 255, 252, 22, 255, 255, 252, 19, 255, 255, 252, 18, 181, 240, 176, 131, 76, 59, 75, 60, 104, 34, 38, 1, + 0, 146, 88, 211, 43, 0, 208, 105, 75, 57, 104, 27, 104, 155, 28, 25, 49, 68, 24, 138, 104, 18, 66, 22, 208, 96, 34, + 0, 32, 0, 96, 154, 247, 252, 253, 64, 104, 32, 247, 253, 255, 203, 30, 7, 218, 3, 104, 32, 247, 253, 255, 198, 28, 7, + 32, 60, 247, 252, 254, 212, 77, 44, 76, 42, 104, 43, 72, 44, 104, 154, 104, 35, 50, 68, 0, 155, 24, 211, 104, 27, 28, + 57, 28, 26, 147, 1, 247, 253, 251, 219, 104, 34, 72, 35, 0, 147, 33, 1, 80, 25, 38, 1, 47, 0, 219, 53, 153, 1, 72, 34, + 64, 8, 73, 34, 66, 136, 209, 47, 72, 34, 33, 0, 84, 129, 74, 27, 32, 0, 80, 152, 247, 255, 254, 191, 40, 0, 219, 15, + 104, 35, 73, 23, 0, 154, 32, 0, 80, 80, 73, 26, 72, 27, 84, 206, 247, 252, 253, 3, 104, 43, 34, 4, 104, 155, 38, 0, + 96, 154, 224, 21, 104, 35, 74, 15, 0, 155, 80, 158, 72, 21, 28, 57, 247, 253, 251, 171, 104, 35, 72, 16, 33, 0, 84, + 193, 32, 100, 247, 252, 254, 142, 72, 14, 247, 252, 252, 235, 104, 43, 34, 4, 104, 155, 96, 154, 32, 100, 247, 252, + 254, 132, 176, 3, 28, 48, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 107, 104, 19, 112, 107, 108, 19, 112, 96, 60, 19, + 112, 105, 221, 0, 0, 49, 5, 0, 0, 16, 5, 19, 112, 107, 84, 19, 112, 17, 185, 19, 112, 105, 249, 181, 240, 176, 131, + 76, 42, 75, 43, 104, 34, 0, 146, 88, 211, 34, 0, 146, 1, 43, 0, 208, 70, 247, 255, 255, 103, 104, 35, 73, 38, 0, 154, + 88, 81, 41, 0, 209, 62, 73, 37, 92, 201, 41, 0, 208, 58, 39, 164, 28, 56, 67, 88, 78, 34, 24, 211, 77, 34, 0, 155, 24, + 243, 25, 64, 121, 25, 247, 255, 249, 57, 40, 0, 219, 44, 104, 35, 0, 154, 24, 210, 0, 145, 24, 113, 0, 210, 121, 9, + 67, 95, 24, 211, 24, 203, 29, 26, 51, 20, 0, 146, 0, 155, 25, 120, 25, 82, 25, 91, 247, 255, 249, 118, 40, 0, 219, 23, + 104, 35, 74, 20, 0, 153, 88, 138, 42, 0, 208, 13, 24, 201, 0, 136, 24, 54, 121, 48, 0, 201, 24, 201, 24, 9, 49, 4, 0, + 137, 35, 128, 89, 73, 1, 27, 66, 153, 209, 3, 28, 19, 30, 90, 65, 147, 147, 1, 152, 1, 176, 3, 188, 240, 188, 2, 71, + 8, 70, 192, 19, 112, 107, 104, 19, 112, 107, 76, 19, 112, 107, 108, 19, 112, 107, 84, 19, 114, 198, 232, 19, 114, 197, + 160, 19, 112, 107, 44, 181, 240, 176, 135, 75, 81, 144, 3, 104, 27, 146, 4, 43, 0, 209, 8, 75, 79, 104, 26, 75, 79, + 0, 146, 88, 211, 43, 0, 208, 1, 75, 78, 96, 24, 75, 78, 104, 27, 43, 0, 208, 9, 75, 73, 104, 26, 75, 76, 0, 146, 88, + 208, 40, 1, 221, 2, 33, 1, 80, 209, 224, 126, 4, 9, 12, 9, 79, 70, 38, 4, 36, 0, 145, 5, 247, 255, 254, 231, 30, 67, + 65, 152, 104, 59, 66, 64, 64, 4, 43, 0, 208, 6, 75, 60, 74, 64, 104, 27, 0, 155, 88, 155, 43, 3, 208, 101, 44, 0, 219, + 5, 75, 56, 74, 60, 104, 27, 92, 211, 43, 1, 208, 7, 75, 53, 33, 1, 104, 26, 75, 55, 0, 146, 36, 1, 80, 209, 66, 100, + 75, 49, 74, 52, 104, 27, 0, 155, 88, 154, 42, 0, 209, 75, 74, 46, 88, 154, 75, 50, 42, 0, 208, 1, 74, 50, 224, 0, 74, + 50, 96, 26, 28, 99, 208, 29, 32, 0, 247, 252, 252, 12, 77, 47, 34, 0, 104, 43, 32, 164, 104, 155, 96, 154, 75, 35, 74, + 45, 104, 27, 67, 88, 24, 128, 74, 44, 92, 209, 154, 4, 155, 5, 146, 0, 154, 3, 247, 255, 250, 15, 28, 4, 72, 40, 247, + 252, 251, 245, 104, 43, 34, 4, 104, 155, 96, 154, 74, 38, 75, 30, 96, 26, 44, 0, 218, 5, 75, 22, 33, 1, 104, 26, 75, + 25, 0, 146, 80, 209, 75, 22, 104, 27, 43, 0, 208, 6, 75, 17, 104, 26, 75, 20, 0, 146, 88, 211, 43, 0, 209, 18, 75, 14, + 74, 17, 104, 27, 0, 153, 88, 138, 42, 0, 209, 5, 74, 15, 92, 211, 43, 1, 209, 1, 44, 0, 218, 7, 62, 1, 46, 0, 209, 137, + 67, 228, 15, 224, 224, 2, 32, 0, 224, 0, 32, 1, 176, 7, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 107, 12, 19, 112, + 107, 104, 19, 112, 107, 44, 19, 112, 106, 224, 19, 112, 106, 228, 19, 112, 107, 108, 19, 112, 107, 84, 19, 112, 96, + 56, 0, 152, 150, 128, 0, 12, 53, 0, 19, 112, 96, 60, 19, 114, 197, 160, 19, 112, 96, 64, 19, 112, 17, 185, 0, 7, 161, + 32, 181, 240, 176, 133, 75, 49, 28, 23, 104, 26, 75, 49, 0, 146, 88, 211, 144, 2, 32, 0, 43, 0, 209, 85, 4, 9, 12, 9, + 36, 0, 145, 3, 247, 255, 254, 56, 40, 0, 208, 2, 44, 0, 219, 7, 224, 0, 36, 0, 75, 38, 74, 40, 104, 27, 92, 211, 43, + 1, 208, 7, 75, 35, 33, 1, 104, 26, 75, 37, 0, 146, 36, 1, 80, 209, 66, 100, 77, 31, 75, 34, 104, 42, 0, 146, 88, 211, + 43, 0, 209, 226, 73, 32, 74, 32, 96, 17, 28, 98, 208, 26, 78, 31, 32, 0, 104, 50, 104, 146, 96, 147, 247, 252, 251, + 105, 104, 43, 32, 164, 67, 88, 74, 27, 24, 128, 74, 27, 92, 209, 154, 2, 155, 3, 151, 0, 247, 255, 249, 177, 28, 4, + 72, 24, 247, 252, 251, 89, 104, 51, 34, 4, 104, 155, 96, 154, 74, 22, 75, 16, 96, 26, 44, 0, 218, 5, 75, 9, 33, 1, 104, + 26, 75, 11, 0, 146, 80, 209, 75, 6, 104, 26, 75, 8, 0, 146, 88, 211, 43, 0, 209, 176, 44, 0, 219, 174, 32, 1, 176, 5, + 188, 240, 188, 2, 71, 8, 19, 112, 107, 104, 19, 112, 107, 44, 19, 112, 107, 84, 19, 112, 107, 108, 0, 15, 66, 64, 19, + 112, 96, 56, 19, 112, 96, 60, 19, 114, 197, 160, 19, 112, 96, 64, 19, 112, 17, 185, 0, 7, 161, 32, 181, 240, 176, 137, + 74, 95, 104, 19, 43, 0, 209, 6, 75, 94, 104, 27, 105, 153, 96, 17, 106, 26, 75, 93, 96, 26, 75, 92, 77, 90, 104, 28, + 38, 0, 28, 55, 104, 43, 55, 8, 0, 191, 80, 252, 28, 32, 33, 0, 34, 96, 240, 1, 249, 253, 104, 43, 33, 96, 88, 248, 240, + 0, 249, 214, 52, 127, 33, 31, 54, 1, 67, 140, 46, 8, 209, 234, 37, 8, 38, 31, 28, 32, 33, 0, 34, 96, 240, 1, 249, 235, + 61, 1, 28, 32, 33, 96, 52, 127, 240, 0, 249, 195, 67, 180, 45, 0, 209, 241, 75, 72, 34, 255, 96, 28, 75, 68, 39, 128, + 104, 29, 35, 255, 2, 18, 4, 27, 76, 69, 38, 0, 5, 255, 146, 2, 147, 3, 33, 0, 96, 37, 34, 96, 28, 40, 240, 1, 249, 206, + 28, 40, 240, 0, 249, 152, 28, 50, 100, 104, 104, 35, 30, 81, 65, 138, 5, 210, 96, 90, 104, 35, 34, 0, 96, 154, 104, + 35, 33, 31, 97, 159, 53, 127, 67, 141, 104, 34, 28, 40, 146, 5, 240, 0, 249, 132, 144, 6, 28, 40, 240, 0, 249, 128, + 144, 1, 28, 40, 240, 0, 249, 124, 144, 7, 28, 40, 240, 0, 249, 120, 35, 255, 2, 27, 153, 2, 147, 4, 34, 255, 155, 1, + 4, 18, 64, 11, 146, 1, 153, 3, 154, 7, 2, 27, 64, 10, 10, 18, 67, 19, 14, 0, 154, 6, 67, 3, 32, 224, 64, 16, 33, 2, + 67, 8, 154, 5, 6, 0, 67, 3, 96, 19, 104, 34, 35, 128, 4, 91, 97, 19, 104, 34, 33, 96, 97, 83, 204, 1, 54, 1, 240, 0, + 249, 100, 46, 6, 209, 175, 76, 22, 77, 26, 104, 32, 105, 110, 240, 0, 249, 75, 144, 2, 104, 32, 240, 0, 249, 71, 28, + 7, 104, 32, 240, 0, 249, 67, 144, 3, 104, 32, 240, 0, 249, 63, 155, 4, 153, 1, 64, 31, 155, 3, 2, 63, 64, 11, 10, 27, + 67, 31, 154, 2, 14, 3, 28, 56, 67, 24, 35, 224, 64, 19, 33, 2, 67, 11, 6, 27, 67, 24, 96, 48, 105, 104, 33, 96, 240, + 0, 249, 57, 176, 9, 188, 240, 188, 1, 71, 0, 70, 192, 19, 112, 107, 100, 19, 112, 96, 60, 19, 112, 107, 72, 19, 112, + 107, 40, 19, 114, 195, 192, 181, 248, 75, 16, 39, 128, 104, 28, 38, 0, 4, 127, 28, 32, 247, 252, 252, 153, 46, 3, 208, + 15, 28, 37, 35, 31, 53, 127, 67, 157, 107, 104, 240, 1, 248, 190, 96, 103, 96, 32, 33, 96, 28, 32, 240, 0, 249, 18, + 54, 1, 28, 44, 231, 234, 28, 32, 33, 96, 240, 0, 249, 11, 188, 248, 188, 1, 71, 0, 19, 112, 107, 40, 181, 240, 176, + 131, 247, 255, 255, 12, 247, 255, 255, 214, 76, 65, 75, 66, 104, 34, 104, 24, 77, 65, 97, 144, 104, 89, 78, 65, 97, + 209, 104, 154, 79, 64, 96, 42, 104, 218, 105, 27, 96, 50, 96, 59, 33, 96, 240, 0, 249, 1, 104, 35, 33, 0, 105, 154, + 100, 211, 105, 154, 100, 145, 105, 155, 28, 24, 147, 1, 240, 0, 248, 209, 155, 1, 104, 34, 100, 88, 104, 59, 105, 145, + 108, 91, 34, 255, 2, 18, 64, 26, 2, 16, 34, 255, 4, 18, 64, 26, 10, 18, 67, 2, 14, 24, 67, 2, 32, 224, 64, 3, 39, 2, + 67, 59, 6, 24, 28, 19, 67, 3, 96, 11, 104, 35, 34, 128, 105, 153, 4, 18, 96, 74, 105, 154, 33, 0, 96, 145, 105, 153, + 34, 128, 5, 210, 97, 138, 105, 153, 34, 128, 4, 82, 97, 10, 105, 153, 97, 74, 105, 152, 33, 96, 240, 0, 248, 179, 104, + 35, 33, 96, 105, 216, 240, 0, 248, 194, 104, 35, 33, 0, 105, 218, 100, 211, 105, 218, 100, 145, 105, 223, 28, 56, 240, + 0, 248, 147, 33, 96, 100, 120, 104, 40, 240, 0, 248, 179, 104, 47, 104, 35, 28, 56, 100, 251, 35, 0, 100, 187, 240, + 0, 248, 134, 33, 96, 100, 120, 104, 40, 240, 0, 248, 146, 104, 48, 33, 96, 240, 0, 248, 162, 104, 53, 104, 35, 33, 0, + 100, 235, 100, 169, 28, 40, 240, 0, 248, 117, 33, 96, 100, 104, 104, 48, 240, 0, 248, 129, 176, 3, 188, 240, 188, 1, + 71, 0, 70, 192, 19, 112, 96, 60, 19, 114, 195, 192, 19, 112, 107, 16, 19, 112, 107, 96, 19, 112, 107, 92, 181, 248, + 76, 35, 75, 35, 96, 35, 240, 0, 248, 74, 40, 0, 219, 58, 240, 0, 249, 121, 74, 32, 104, 131, 96, 32, 96, 26, 104, 32, + 35, 1, 104, 130, 104, 17, 66, 11, 209, 252, 33, 252, 240, 0, 248, 91, 38, 128, 39, 128, 76, 23, 37, 0, 4, 118, 1, 127, + 104, 35, 33, 4, 108, 219, 81, 94, 104, 35, 108, 219, 89, 88, 53, 4, 240, 0, 248, 75, 66, 189, 209, 243, 247, 255, 255, + 65, 104, 35, 34, 2, 51, 84, 112, 26, 247, 252, 254, 95, 104, 35, 32, 0, 104, 154, 105, 155, 108, 91, 97, 147, 104, 35, + 34, 4, 104, 155, 96, 154, 104, 35, 74, 8, 104, 155, 96, 26, 104, 35, 104, 155, 104, 27, 224, 1, 32, 1, 66, 64, 188, + 248, 188, 2, 71, 8, 19, 112, 96, 60, 19, 114, 199, 16, 0, 1, 0, 32, 0, 1, 0, 33, 181, 8, 33, 224, 72, 4, 2, 9, 240, + 1, 249, 94, 75, 3, 96, 24, 23, 192, 188, 8, 188, 2, 71, 8, 19, 112, 163, 160, 19, 112, 96, 68, 71, 112, 71, 112, 181, + 16, 28, 4, 240, 1, 249, 42, 28, 32, 188, 16, 188, 2, 71, 8, 181, 16, 28, 4, 240, 1, 249, 34, 28, 32, 188, 16, 188, 2, + 71, 8, 181, 16, 28, 4, 240, 1, 249, 26, 28, 32, 188, 16, 188, 2, 71, 8, 181, 8, 240, 1, 249, 27, 188, 8, 188, 1, 71, + 0, 181, 8, 240, 1, 249, 21, 188, 8, 188, 1, 71, 0, 181, 8, 240, 1, 249, 15, 188, 8, 188, 1, 71, 0, 181, 8, 75, 12, 28, + 1, 34, 32, 104, 24, 240, 1, 249, 45, 40, 0, 209, 13, 72, 9, 240, 1, 249, 56, 240, 0, 249, 67, 32, 200, 247, 252, 250, + 165, 240, 0, 249, 72, 32, 200, 247, 252, 250, 160, 231, 244, 188, 8, 188, 2, 71, 8, 19, 112, 96, 68, 19, 112, 106, 17, + 181, 8, 75, 4, 28, 1, 104, 24, 240, 1, 248, 170, 188, 8, 188, 1, 71, 0, 70, 192, 19, 112, 96, 68, 181, 248, 76, 13, + 28, 15, 104, 33, 28, 30, 28, 24, 28, 21, 67, 81, 240, 1, 248, 208, 28, 56, 28, 41, 28, 50, 247, 255, 252, 119, 35, 1, + 40, 0, 208, 5, 104, 33, 28, 48, 67, 105, 240, 1, 248, 203, 35, 0, 28, 24, 188, 248, 188, 2, 71, 8, 19, 114, 200, 12, + 181, 16, 76, 11, 104, 32, 40, 0, 208, 3, 240, 0, 252, 43, 35, 0, 96, 35, 76, 8, 104, 35, 43, 0, 209, 3, 72, 7, 247, + 251, 250, 220, 96, 32, 74, 6, 35, 1, 66, 91, 96, 19, 188, 16, 188, 1, 71, 0, 19, 112, 107, 124, 19, 112, 107, 116, 0, + 0, 128, 32, 19, 112, 96, 24, 181, 56, 75, 14, 104, 24, 40, 0, 208, 1, 247, 251, 250, 227, 76, 12, 75, 10, 104, 32, 37, + 0, 96, 29, 40, 0, 208, 2, 240, 0, 252, 2, 96, 37, 75, 8, 104, 24, 40, 0, 208, 1, 240, 0, 251, 95, 75, 5, 34, 0, 96, + 26, 188, 56, 188, 1, 71, 0, 70, 192, 19, 112, 107, 116, 19, 112, 107, 124, 19, 112, 107, 120, 181, 240, 176, 135, 75, + 38, 28, 7, 104, 24, 145, 5, 40, 0, 208, 1, 247, 251, 250, 188, 75, 34, 77, 35, 34, 0, 96, 26, 104, 43, 43, 0, 209, 25, + 75, 33, 36, 0, 104, 24, 247, 255, 248, 198, 78, 31, 28, 48, 247, 255, 249, 236, 75, 30, 96, 24, 40, 0, 208, 43, 154, + 5, 104, 51, 33, 0, 144, 0, 146, 1, 72, 27, 34, 0, 148, 2, 240, 0, 249, 240, 96, 40, 40, 0, 208, 30, 77, 24, 104, 44, + 44, 0, 208, 11, 72, 23, 28, 57, 34, 6, 240, 0, 254, 216, 40, 0, 208, 19, 28, 32, 240, 0, 251, 181, 35, 0, 96, 43, 75, + 11, 28, 57, 104, 24, 240, 0, 251, 56, 75, 13, 28, 4, 96, 24, 40, 0, 208, 4, 72, 12, 28, 57, 34, 6, 240, 0, 254, 240, + 176, 7, 28, 32, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 107, 116, 19, 112, 107, 120, 19, 112, 107, 104, 19, 114, + 200, 12, 19, 114, 200, 16, 19, 112, 75, 241, 19, 112, 107, 124, 19, 112, 96, 72, 181, 8, 28, 3, 28, 10, 32, 0, 28, 25, + 35, 0, 240, 0, 255, 214, 188, 8, 188, 1, 71, 0, 181, 8, 32, 1, 33, 0, 34, 0, 35, 0, 240, 0, 255, 204, 188, 8, 188, 2, + 71, 8, 181, 8, 32, 17, 33, 0, 34, 0, 35, 0, 240, 0, 255, 194, 188, 8, 188, 2, 71, 8, 181, 8, 32, 18, 33, 0, 34, 0, 35, + 0, 240, 0, 255, 184, 188, 8, 188, 2, 71, 8, 181, 56, 28, 5, 28, 12, 30, 19, 221, 4, 32, 2, 28, 41, 28, 34, 240, 0, 255, + 171, 188, 56, 188, 1, 71, 0, 181, 56, 28, 5, 28, 12, 30, 19, 221, 4, 32, 9, 28, 41, 28, 34, 240, 0, 255, 158, 188, 56, + 188, 1, 71, 0, 181, 8, 28, 3, 28, 10, 32, 5, 28, 25, 35, 0, 240, 0, 255, 147, 188, 8, 188, 1, 71, 0, 181, 8, 28, 3, + 28, 10, 32, 6, 28, 25, 35, 0, 240, 0, 255, 136, 188, 8, 188, 1, 71, 0, 181, 56, 28, 5, 28, 12, 28, 19, 28, 41, 28, 34, + 32, 16, 240, 0, 255, 124, 188, 56, 188, 2, 71, 8, 181, 8, 32, 128, 33, 0, 34, 0, 35, 0, 240, 0, 255, 114, 188, 8, 188, + 1, 71, 0, 181, 8, 32, 129, 33, 0, 34, 0, 35, 0, 240, 0, 255, 104, 188, 8, 188, 1, 71, 0, 181, 0, 35, 0, 224, 3, 51, + 1, 6, 27, 14, 27, 8, 64, 40, 0, 209, 249, 30, 88, 6, 0, 14, 0, 188, 2, 71, 8, 0, 0, 181, 240, 176, 133, 144, 1, 32, + 84, 145, 3, 146, 2, 28, 30, 159, 11, 247, 251, 249, 182, 28, 4, 30, 48, 209, 1, 32, 128, 0, 128, 247, 251, 249, 175, + 28, 5, 32, 128, 2, 0, 97, 32, 247, 255, 255, 218, 75, 125, 117, 32, 97, 227, 154, 10, 75, 124, 96, 37, 96, 30, 11, 211, + 67, 115, 97, 163, 155, 12, 98, 231, 43, 0, 208, 50, 33, 0, 28, 50, 28, 40, 240, 0, 254, 106, 35, 87, 112, 43, 35, 66, + 112, 107, 35, 70, 112, 171, 35, 83, 112, 235, 28, 48, 247, 255, 255, 188, 114, 40, 159, 10, 73, 111, 14, 59, 113, 43, + 12, 59, 113, 107, 10, 59, 113, 171, 113, 239, 105, 162, 35, 6, 66, 138, 217, 16, 73, 106, 35, 7, 66, 138, 217, 12, 73, + 105, 35, 8, 66, 138, 217, 8, 73, 104, 35, 9, 66, 138, 217, 4, 75, 103, 66, 147, 65, 155, 66, 91, 51, 10, 125, 34, 24, + 155, 114, 107, 224, 6, 28, 57, 152, 2, 34, 1, 28, 43, 159, 1, 240, 0, 248, 207, 120, 43, 120, 106, 6, 27, 4, 18, 67, + 26, 120, 171, 2, 27, 67, 26, 120, 235, 67, 26, 75, 91, 66, 154, 208, 4, 72, 90, 240, 0, 255, 97, 72, 90, 224, 40, 75, + 90, 104, 27, 66, 95, 65, 95, 46, 0, 208, 12, 47, 0, 208, 10, 28, 48, 247, 255, 255, 117, 122, 43, 66, 131, 208, 4, 72, + 81, 240, 0, 255, 78, 72, 82, 224, 21, 154, 10, 42, 0, 208, 31, 47, 0, 208, 29, 121, 42, 121, 107, 6, 18, 4, 27, 67, + 19, 121, 170, 159, 10, 2, 18, 67, 19, 121, 234, 67, 19, 66, 187, 208, 16, 72, 69, 240, 0, 255, 55, 72, 72, 240, 0, 255, + 52, 72, 71, 240, 0, 255, 49, 28, 32, 247, 251, 249, 60, 28, 40, 247, 251, 249, 57, 36, 0, 224, 100, 122, 46, 39, 1, + 28, 58, 64, 178, 96, 98, 122, 43, 28, 22, 147, 0, 114, 35, 121, 42, 121, 107, 6, 18, 4, 27, 67, 19, 121, 170, 121, 232, + 2, 18, 67, 19, 67, 24, 105, 33, 96, 224, 240, 0, 254, 148, 67, 112, 97, 160, 122, 107, 125, 34, 64, 159, 98, 99, 26, + 155, 105, 226, 64, 216, 64, 218, 4, 18, 12, 18, 4, 51, 12, 27, 133, 98, 50, 128, 4, 1, 133, 32, 0, 82, 30, 88, 24, 130, + 66, 91, 64, 26, 155, 3, 28, 37, 53, 72, 99, 99, 12, 201, 155, 0, 98, 39, 128, 42, 26, 127, 154, 1, 64, 223, 99, 34, + 100, 39, 154, 2, 159, 12, 99, 162, 47, 0, 209, 1, 100, 103, 224, 11, 30, 112, 24, 65, 66, 112, 64, 8, 247, 251, 248, + 209, 141, 34, 100, 96, 8, 210, 33, 255, 240, 0, 253, 159, 28, 35, 51, 72, 136, 25, 108, 32, 122, 35, 56, 1, 65, 25, + 240, 0, 254, 84, 4, 2, 104, 96, 12, 18, 28, 3, 59, 12, 135, 162, 66, 154, 217, 0, 135, 163, 247, 251, 248, 183, 35, + 0, 100, 224, 101, 35, 176, 5, 28, 32, 188, 240, 188, 2, 71, 8, 70, 192, 0, 4, 96, 144, 19, 112, 107, 136, 0, 63, 255, + 255, 0, 127, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 3, 255, 255, 255, 87, 66, 70, 83, 19, 112, 106, 48, 19, 112, + 106, 60, 19, 112, 107, 132, 19, 112, 106, 70, 19, 112, 106, 99, 19, 112, 105, 116, 71, 56, 70, 192, 181, 240, 176, 165, + 144, 9, 28, 24, 146, 10, 147, 11, 145, 15, 247, 251, 248, 135, 35, 1, 74, 140, 77, 141, 66, 91, 96, 19, 104, 43, 28, + 4, 43, 0, 209, 3, 152, 11, 247, 251, 248, 123, 96, 40, 75, 136, 152, 11, 33, 0, 96, 24, 34, 1, 152, 10, 28, 35, 157, + 9, 240, 0, 249, 24, 40, 0, 208, 0, 224, 246, 35, 255, 0, 91, 92, 227, 43, 85, 209, 28, 51, 171, 51, 255, 92, 227, 43, + 170, 209, 23, 28, 224, 73, 125, 34, 4, 240, 0, 253, 142, 40, 0, 208, 16, 77, 123, 28, 32, 48, 54, 28, 41, 34, 3, 240, + 0, 253, 133, 40, 0, 208, 7, 28, 32, 48, 82, 28, 41, 34, 3, 240, 0, 253, 125, 40, 0, 209, 5, 168, 20, 33, 0, 34, 64, + 240, 0, 253, 26, 224, 6, 28, 33, 49, 191, 49, 255, 168, 20, 34, 64, 240, 0, 252, 208, 175, 32, 151, 5, 32, 228, 39, + 1, 66, 127, 0, 64, 38, 0, 173, 20, 144, 14, 151, 8, 122, 235, 122, 47, 122, 105, 122, 170, 147, 7, 120, 32, 120, 99, + 6, 0, 4, 27, 67, 24, 120, 163, 2, 27, 67, 24, 120, 227, 67, 24, 75, 97, 66, 152, 208, 3, 121, 40, 40, 0, 209, 0, 224, + 162, 2, 9, 4, 18, 67, 17, 67, 57, 159, 7, 6, 59, 67, 25, 145, 7, 121, 43, 43, 15, 209, 101, 33, 227, 32, 0, 0, 73, 159, + 8, 144, 12, 35, 0, 145, 13, 149, 4, 154, 7, 152, 10, 24, 210, 146, 8, 28, 17, 28, 35, 34, 1, 157, 9, 240, 0, 248, 169, + 40, 0, 208, 0, 224, 135, 72, 78, 153, 14, 92, 34, 92, 99, 2, 18, 4, 27, 67, 26, 77, 76, 155, 13, 152, 8, 92, 225, 93, + 99, 67, 10, 6, 27, 67, 19, 24, 192, 35, 235, 144, 8, 0, 91, 92, 227, 152, 10, 147, 16, 75, 69, 153, 8, 92, 227, 34, + 1, 147, 17, 35, 236, 0, 91, 92, 227, 157, 9, 147, 18, 75, 65, 92, 227, 147, 19, 28, 35, 240, 0, 248, 128, 40, 0, 209, + 95, 120, 34, 120, 99, 6, 18, 4, 27, 67, 19, 120, 162, 73, 54, 2, 18, 67, 19, 120, 226, 67, 19, 66, 139, 209, 10, 154, + 43, 66, 150, 209, 2, 144, 0, 155, 8, 224, 48, 152, 8, 66, 184, 208, 1, 54, 1, 28, 7, 153, 17, 157, 18, 2, 11, 4, 42, + 152, 16, 153, 19, 67, 19, 67, 3, 6, 10, 67, 19, 208, 53, 154, 12, 50, 1, 146, 12, 42, 8, 209, 162, 224, 47, 152, 10, + 153, 7, 34, 1, 28, 35, 159, 9, 240, 0, 248, 79, 40, 0, 209, 45, 120, 34, 120, 99, 6, 18, 4, 27, 67, 19, 120, 162, 73, + 29, 2, 18, 67, 19, 120, 226, 67, 19, 66, 139, 209, 27, 154, 43, 66, 150, 209, 15, 155, 7, 144, 0, 157, 44, 147, 1, 152, + 9, 153, 15, 154, 10, 155, 11, 149, 2, 247, 255, 253, 201, 28, 5, 28, 32, 247, 250, 255, 163, 224, 17, 159, 7, 152, 8, + 66, 135, 208, 4, 54, 1, 151, 8, 224, 1, 157, 4, 151, 8, 153, 5, 66, 141, 208, 1, 53, 16, 231, 65, 28, 32, 247, 250, + 255, 145, 37, 0, 176, 37, 28, 40, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 96, 80, 19, 112, 107, 128, 19, 112, 107, + 136, 19, 112, 106, 127, 19, 112, 106, 132, 87, 66, 70, 83, 0, 0, 1, 199, 0, 0, 1, 201, 0, 0, 1, 215, 0, 0, 1, 217, 71, + 40, 71, 56, 181, 16, 109, 3, 28, 4, 43, 0, 208, 9, 72, 13, 240, 0, 253, 94, 72, 12, 240, 0, 253, 91, 72, 12, 240, 0, + 253, 88, 224, 13, 104, 0, 247, 250, 255, 98, 108, 224, 247, 250, 255, 95, 108, 96, 40, 0, 208, 1, 247, 250, 255, 90, + 28, 32, 247, 250, 255, 87, 188, 16, 188, 1, 71, 0, 19, 112, 106, 48, 19, 112, 106, 136, 19, 112, 105, 116, 181, 240, + 28, 3, 51, 72, 176, 131, 136, 26, 122, 3, 28, 5, 65, 26, 146, 1, 35, 1, 74, 48, 66, 91, 96, 19, 34, 0, 28, 14, 146, + 0, 39, 0, 224, 79, 104, 43, 25, 219, 123, 27, 43, 0, 208, 68, 106, 233, 155, 0, 49, 1, 24, 201, 34, 1, 107, 168, 108, + 235, 107, 44, 240, 0, 248, 83, 108, 233, 28, 48, 34, 6, 240, 0, 251, 110, 40, 0, 209, 51, 32, 12, 247, 250, 255, 5, + 30, 6, 209, 9, 72, 32, 240, 0, 253, 16, 72, 31, 240, 0, 253, 13, 72, 31, 240, 0, 253, 10, 224, 46, 28, 43, 51, 72, 96, + 53, 96, 183, 136, 24, 247, 250, 254, 242, 28, 3, 96, 112, 40, 0, 209, 12, 72, 21, 240, 0, 252, 251, 72, 21, 240, 0, + 252, 248, 72, 20, 240, 0, 252, 245, 28, 48, 247, 250, 255, 0, 224, 21, 106, 233, 154, 0, 49, 1, 24, 137, 107, 168, 107, + 44, 154, 1, 240, 0, 248, 28, 109, 43, 51, 1, 101, 43, 224, 9, 155, 0, 55, 1, 28, 26, 155, 1, 24, 210, 146, 0, 143, 171, + 66, 159, 211, 172, 38, 0, 176, 3, 28, 48, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 96, 80, 19, 112, 106, 48, 19, 112, + 106, 180, 19, 112, 105, 116, 71, 32, 70, 192, 181, 16, 104, 3, 28, 4, 109, 26, 58, 1, 101, 26, 104, 64, 247, 250, 254, + 207, 28, 32, 247, 250, 254, 204, 188, 16, 188, 1, 71, 0, 0, 0, 181, 240, 176, 137, 104, 5, 147, 0, 106, 107, 146, 1, + 28, 6, 30, 154, 28, 8, 64, 208, 4, 2, 12, 18, 104, 104, 146, 4, 70, 132, 152, 4, 104, 116, 48, 128, 0, 64, 90, 32, 122, + 47, 106, 42, 144, 2, 36, 1, 40, 0, 209, 0, 224, 194, 58, 1, 64, 250, 27, 219, 146, 6, 63, 2, 28, 10, 64, 250, 147, 5, + 155, 6, 28, 23, 70, 96, 64, 31, 8, 131, 59, 1, 28, 26, 64, 10, 146, 7, 209, 0, 224, 133, 155, 2, 152, 5, 106, 233, 64, + 131, 24, 121, 147, 3, 24, 201, 75, 87, 104, 26, 108, 235, 66, 138, 209, 5, 74, 85, 28, 24, 104, 17, 74, 85, 104, 18, + 224, 18, 107, 44, 107, 168, 34, 1, 240, 0, 248, 165, 30, 4, 208, 0, 224, 149, 106, 235, 152, 3, 73, 76, 24, 251, 24, + 27, 96, 11, 75, 75, 108, 233, 104, 24, 75, 75, 104, 26, 240, 0, 250, 231, 154, 7, 104, 108, 0, 145, 155, 0, 26, 100, + 66, 156, 217, 0, 28, 28, 108, 235, 152, 1, 24, 89, 28, 34, 240, 0, 250, 217, 152, 0, 153, 1, 27, 0, 25, 9, 144, 0, 145, + 1, 55, 1, 40, 0, 208, 71, 154, 6, 66, 186, 210, 68, 155, 4, 104, 114, 51, 1, 4, 27, 12, 27, 147, 4, 51, 128, 0, 91, + 90, 211, 36, 1, 147, 2, 39, 0, 43, 0, 209, 54, 224, 95, 122, 43, 152, 0, 64, 216, 106, 43, 25, 194, 144, 3, 66, 154, + 217, 1, 27, 219, 147, 3, 154, 5, 106, 233, 155, 2, 24, 121, 64, 147, 24, 201, 107, 168, 107, 44, 154, 3, 155, 1, 240, + 0, 248, 86, 40, 0, 209, 70, 122, 43, 152, 3, 153, 0, 64, 152, 154, 3, 26, 9, 28, 3, 145, 0, 24, 191, 41, 0, 208, 15, + 152, 6, 66, 184, 210, 12, 154, 4, 104, 113, 50, 1, 4, 18, 12, 18, 146, 4, 50, 128, 0, 82, 90, 138, 146, 2, 42, 0, 208, + 42, 39, 0, 153, 1, 24, 201, 145, 1, 104, 107, 154, 0, 66, 154, 210, 197, 36, 0, 42, 0, 208, 34, 155, 5, 158, 2, 106, + 233, 64, 158, 24, 121, 107, 44, 107, 168, 25, 137, 108, 235, 34, 1, 240, 0, 248, 35, 30, 4, 209, 20, 106, 235, 108, + 233, 24, 255, 75, 11, 25, 190, 96, 30, 75, 11, 104, 24, 75, 11, 104, 26, 240, 0, 250, 103, 108, 233, 152, 1, 154, 0, + 240, 0, 250, 98, 224, 2, 36, 1, 224, 0, 28, 4, 176, 9, 28, 32, 188, 240, 188, 2, 71, 8, 70, 192, 19, 112, 96, 80, 19, + 112, 107, 128, 19, 112, 107, 136, 71, 32, 70, 192, 0, 0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 204, 225, 47, 255, 30, 225, 160, + 0, 0, 225, 160, 0, 0, 230, 0, 0, 16, 225, 47, 255, 30, 230, 0, 0, 48, 225, 47, 255, 30, 230, 0, 0, 80, 225, 47, 255, + 30, 230, 0, 0, 112, 225, 47, 255, 30, 230, 0, 0, 144, 225, 47, 255, 30, 230, 0, 0, 176, 225, 47, 255, 30, 230, 0, 0, + 208, 225, 47, 255, 30, 230, 0, 0, 240, 225, 47, 255, 30, 230, 0, 1, 16, 225, 47, 255, 30, 230, 0, 1, 48, 225, 47, 255, + 30, 230, 0, 1, 80, 225, 47, 255, 30, 230, 0, 1, 112, 225, 47, 255, 30, 230, 0, 1, 144, 225, 47, 255, 30, 230, 0, 1, + 176, 225, 47, 255, 30, 230, 0, 1, 208, 225, 47, 255, 30, 230, 0, 1, 240, 225, 47, 255, 30, 230, 0, 2, 16, 225, 47, 255, + 30, 230, 0, 2, 48, 225, 47, 255, 30, 230, 0, 2, 80, 225, 47, 255, 30, 230, 0, 2, 112, 225, 47, 255, 30, 230, 0, 2, 144, + 225, 47, 255, 30, 230, 0, 2, 176, 225, 47, 255, 30, 230, 0, 2, 208, 225, 47, 255, 30, 230, 0, 2, 240, 225, 47, 255, + 30, 230, 0, 3, 16, 225, 47, 255, 30, 230, 0, 3, 48, 225, 47, 255, 30, 230, 0, 3, 80, 225, 47, 255, 30, 230, 0, 3, 112, + 225, 47, 255, 30, 230, 0, 3, 144, 225, 47, 255, 30, 230, 0, 3, 176, 225, 47, 255, 30, 230, 0, 3, 208, 225, 47, 255, + 30, 230, 0, 3, 240, 225, 47, 255, 30, 230, 0, 4, 16, 225, 47, 255, 30, 230, 0, 4, 48, 225, 47, 255, 30, 230, 0, 4, 80, + 225, 47, 255, 30, 230, 0, 4, 112, 225, 47, 255, 30, 230, 0, 4, 144, 225, 47, 255, 30, 230, 0, 4, 176, 225, 47, 255, + 30, 230, 0, 4, 208, 225, 47, 255, 30, 230, 0, 4, 240, 225, 47, 255, 30, 230, 0, 5, 16, 225, 47, 255, 30, 230, 0, 5, + 48, 225, 47, 255, 30, 230, 0, 5, 80, 225, 47, 255, 30, 230, 0, 6, 144, 225, 47, 255, 30, 230, 0, 7, 240, 225, 47, 255, + 30, 230, 0, 8, 16, 225, 47, 255, 30, 230, 0, 10, 16, 225, 47, 255, 30, 226, 144, 16, 0, 227, 176, 0, 4, 239, 0, 0, 171, + 225, 47, 255, 30, 225, 160, 0, 0, 225, 160, 0, 0, 180, 3, 70, 113, 8, 73, 0, 64, 0, 73, 90, 9, 0, 73, 68, 142, 188, + 3, 71, 112, 226, 81, 32, 1, 1, 47, 255, 30, 58, 0, 0, 54, 225, 80, 0, 1, 154, 0, 0, 34, 225, 17, 0, 2, 10, 0, 0, 35, + 227, 17, 2, 14, 1, 160, 17, 129, 3, 160, 48, 8, 19, 160, 48, 1, 227, 81, 2, 1, 49, 81, 0, 0, 49, 160, 18, 1, 49, 160, + 50, 3, 58, 255, 255, 250, 227, 81, 1, 2, 49, 81, 0, 0, 49, 160, 16, 129, 49, 160, 48, 131, 58, 255, 255, 250, 227, 160, + 32, 0, 225, 80, 0, 1, 32, 64, 0, 1, 33, 130, 32, 3, 225, 80, 0, 161, 32, 64, 0, 161, 33, 130, 32, 163, 225, 80, 1, 33, + 32, 64, 1, 33, 33, 130, 33, 35, 225, 80, 1, 161, 32, 64, 1, 161, 33, 130, 33, 163, 227, 80, 0, 0, 17, 176, 50, 35, 17, + 160, 18, 33, 26, 255, 255, 239, 225, 160, 0, 2, 225, 47, 255, 30, 3, 160, 0, 1, 19, 160, 0, 0, 225, 47, 255, 30, 227, + 81, 8, 1, 33, 160, 24, 33, 35, 160, 32, 16, 51, 160, 32, 0, 227, 81, 12, 1, 33, 160, 20, 33, 34, 130, 32, 8, 227, 81, + 0, 16, 33, 160, 18, 33, 34, 130, 32, 4, 227, 81, 0, 4, 130, 130, 32, 3, 144, 130, 32, 161, 225, 160, 2, 48, 225, 47, + 255, 30, 225, 47, 255, 31, 225, 160, 0, 0, 227, 80, 0, 0, 19, 224, 0, 0, 234, 0, 1, 9, 227, 81, 0, 0, 10, 255, 255, + 248, 233, 45, 64, 3, 235, 255, 255, 188, 232, 189, 64, 6, 224, 3, 0, 146, 224, 65, 16, 3, 225, 47, 255, 30, 227, 81, + 0, 0, 10, 0, 0, 67, 224, 32, 192, 1, 66, 97, 16, 0, 226, 81, 32, 1, 10, 0, 0, 39, 225, 176, 48, 0, 66, 96, 48, 0, 225, + 83, 0, 1, 154, 0, 0, 38, 225, 17, 0, 2, 10, 0, 0, 40, 227, 17, 2, 14, 1, 160, 17, 129, 3, 160, 32, 8, 19, 160, 32, 1, + 227, 81, 2, 1, 49, 81, 0, 3, 49, 160, 18, 1, 49, 160, 34, 2, 58, 255, 255, 250, 227, 81, 1, 2, 49, 81, 0, 3, 49, 160, + 16, 129, 49, 160, 32, 130, 58, 255, 255, 250, 227, 160, 0, 0, 225, 83, 0, 1, 32, 67, 48, 1, 33, 128, 0, 2, 225, 83, + 0, 161, 32, 67, 48, 161, 33, 128, 0, 162, 225, 83, 1, 33, 32, 67, 49, 33, 33, 128, 1, 34, 225, 83, 1, 161, 32, 67, 49, + 161, 33, 128, 1, 162, 227, 83, 0, 0, 17, 176, 34, 34, 17, 160, 18, 33, 26, 255, 255, 239, 227, 92, 0, 0, 66, 96, 0, + 0, 225, 47, 255, 30, 225, 60, 0, 0, 66, 96, 0, 0, 225, 47, 255, 30, 51, 160, 0, 0, 1, 160, 15, 204, 3, 128, 0, 1, 225, + 47, 255, 30, 227, 81, 8, 1, 33, 160, 24, 33, 35, 160, 32, 16, 51, 160, 32, 0, 227, 81, 12, 1, 33, 160, 20, 33, 34, 130, + 32, 8, 227, 81, 0, 16, 33, 160, 18, 33, 34, 130, 32, 4, 227, 81, 0, 4, 130, 130, 32, 3, 144, 130, 32, 161, 227, 92, + 0, 0, 225, 160, 2, 51, 66, 96, 0, 0, 225, 47, 255, 30, 225, 47, 255, 31, 225, 160, 0, 0, 227, 80, 0, 0, 195, 224, 1, + 2, 179, 160, 1, 2, 234, 0, 0, 181, 227, 81, 0, 0, 10, 255, 255, 247, 233, 45, 64, 3, 235, 255, 255, 177, 232, 189, 64, + 6, 224, 3, 0, 146, 224, 65, 16, 3, 225, 47, 255, 30, 71, 112, 70, 192, 33, 16, 6, 2, 14, 3, 65, 200, 67, 19, 6, 2, 14, + 0, 67, 16, 65, 200, 67, 24, 71, 112, 70, 192, 181, 112, 28, 4, 28, 13, 42, 3, 217, 33, 28, 11, 67, 3, 7, 158, 208, 18, + 120, 32, 120, 41, 66, 136, 209, 29, 58, 1, 35, 0, 224, 5, 52, 1, 51, 1, 120, 32, 92, 233, 66, 136, 209, 20, 66, 154, + 209, 247, 32, 0, 188, 112, 188, 2, 71, 8, 28, 13, 28, 4, 201, 8, 200, 64, 66, 158, 209, 4, 58, 4, 28, 4, 28, 13, 42, + 3, 216, 244, 32, 0, 42, 0, 209, 222, 231, 237, 26, 64, 231, 235, 70, 192, 181, 240, 28, 5, 28, 14, 28, 20, 42, 15, 217, + 3, 28, 11, 67, 3, 7, 159, 208, 10, 44, 0, 208, 5, 35, 0, 92, 242, 84, 234, 51, 1, 66, 163, 209, 250, 188, 240, 188, + 2, 71, 8, 28, 21, 28, 12, 28, 3, 104, 38, 96, 30, 104, 102, 96, 94, 104, 166, 96, 158, 104, 230, 61, 16, 96, 222, 52, + 16, 51, 16, 45, 15, 216, 242, 58, 16, 9, 23, 28, 126, 1, 63, 1, 54, 27, 215, 25, 133, 28, 60, 25, 142, 47, 3, 217, 217, + 28, 52, 28, 59, 28, 42, 204, 2, 59, 4, 194, 2, 43, 3, 216, 250, 63, 4, 8, 188, 28, 99, 0, 155, 0, 164, 24, 237, 24, + 246, 27, 60, 231, 200, 70, 192, 181, 112, 28, 3, 7, 132, 208, 13, 42, 0, 208, 64, 6, 13, 58, 1, 14, 45, 36, 3, 224, + 2, 42, 0, 208, 57, 58, 1, 112, 29, 51, 1, 66, 35, 209, 248, 42, 3, 217, 41, 37, 255, 64, 13, 2, 44, 67, 37, 4, 44, 28, + 30, 67, 37, 42, 15, 217, 18, 28, 28, 28, 22, 62, 16, 96, 37, 96, 101, 96, 165, 96, 229, 52, 16, 46, 15, 216, 247, 58, + 16, 9, 22, 54, 1, 1, 54, 25, 158, 35, 15, 64, 26, 42, 3, 217, 12, 28, 52, 28, 19, 59, 4, 196, 32, 43, 3, 216, 251, 58, + 4, 8, 147, 51, 1, 0, 155, 24, 246, 35, 3, 64, 26, 28, 51, 42, 0, 208, 6, 6, 9, 14, 12, 33, 0, 84, 92, 49, 1, 66, 138, + 209, 251, 188, 112, 188, 2, 71, 8, 120, 2, 120, 11, 48, 1, 49, 1, 42, 0, 208, 1, 66, 154, 208, 247, 26, 208, 71, 112, + 35, 0, 92, 194, 51, 1, 42, 0, 209, 251, 30, 88, 71, 112, 70, 192, 181, 240, 28, 3, 32, 0, 42, 0, 208, 72, 28, 8, 67, + 24, 36, 3, 30, 85, 64, 4, 209, 42, 28, 30, 28, 13, 42, 3, 217, 67, 104, 31, 104, 8, 66, 135, 209, 63, 58, 4, 28, 32, + 42, 0, 208, 54, 72, 34, 24, 61, 67, 189, 79, 33, 28, 32, 66, 61, 209, 47, 29, 28, 29, 8, 224, 11, 204, 8, 200, 2, 66, + 139, 209, 45, 58, 4, 42, 0, 208, 40, 77, 25, 25, 89, 67, 153, 66, 57, 209, 35, 28, 38, 28, 5, 42, 3, 216, 239, 28, 35, + 28, 1, 42, 0, 208, 33, 30, 85, 120, 28, 120, 8, 66, 132, 209, 18, 32, 0, 45, 0, 208, 16, 44, 0, 208, 14, 61, 1, 34, + 0, 224, 4, 66, 170, 208, 12, 50, 1, 44, 0, 208, 9, 24, 152, 120, 68, 24, 136, 120, 64, 66, 132, 208, 244, 26, 32, 188, + 240, 188, 2, 71, 8, 32, 0, 231, 250, 28, 41, 28, 51, 30, 85, 231, 222, 120, 36, 120, 0, 26, 32, 231, 242, 70, 192, 254, + 254, 254, 255, 128, 128, 128, 128, 0, 0, 0, 0, 71, 120, 70, 192, 234, 255, 254, 196, 71, 120, 70, 192, 234, 255, 254, + 85, 71, 120, 70, 192, 234, 255, 254, 139, 71, 120, 70, 192, 234, 255, 254, 139, 71, 120, 70, 192, 234, 255, 232, 227, + 71, 120, 70, 192, 234, 255, 232, 229, 71, 120, 70, 192, 234, 255, 254, 85, 71, 120, 70, 192, 234, 255, 232, 177, 229, + 159, 192, 0, 225, 47, 255, 28, 19, 112, 90, 177, 71, 120, 70, 192, 234, 255, 254, 240, 71, 120, 70, 192, 234, 255, 254, + 90, 71, 120, 70, 192, 234, 255, 254, 98, 71, 120, 70, 192, 234, 255, 232, 170, 71, 120, 70, 192, 234, 255, 254, 96, + 71, 120, 70, 192, 234, 255, 254, 102, 71, 120, 70, 192, 234, 255, 254, 150, 71, 120, 70, 192, 234, 255, 254, 106, 71, + 120, 70, 192, 234, 255, 254, 144, 71, 120, 70, 192, 234, 255, 254, 72, 71, 120, 70, 192, 234, 255, 255, 48, 71, 120, + 70, 192, 234, 255, 254, 136, 71, 120, 70, 192, 234, 255, 232, 187, 71, 120, 70, 192, 234, 255, 254, 130, 71, 120, 70, + 192, 234, 255, 254, 72, 71, 120, 70, 192, 234, 255, 254, 86, 71, 120, 70, 192, 234, 255, 254, 216, 71, 120, 70, 192, + 234, 255, 254, 72, 71, 120, 70, 192, 234, 255, 254, 86, 71, 120, 70, 192, 234, 255, 254, 72, 71, 120, 70, 192, 234, + 255, 254, 68, 71, 120, 70, 192, 234, 255, 232, 136, 71, 120, 70, 192, 234, 255, 254, 122, 0, 0, 0, 0, 73, 79, 83, 32, + 109, 111, 100, 117, 108, 101, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 229, 31, 240, 4, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 7, 161, + 32, 19, 114, 199, 16, 16, 16, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 87, 66, 70, 83, + 32, 110, 111, 116, 32, 101, 110, 111, 117, 103, 104, 32, 109, 101, 109, 111, 114, 121, 33, 10, 0, 47, 100, 101, 118, + 47, 117, 115, 98, 49, 50, 51, 0, 47, 100, 101, 118, 47, 117, 115, 98, 49, 50, 51, 47, 79, 70, 70, 0, 102, 105, 114, + 115, 116, 32, 114, 101, 97, 100, 32, 115, 101, 99, 116, 111, 114, 32, 40, 37, 105, 41, 32, 79, 75, 10, 0, 102, 105, + 114, 115, 116, 32, 114, 101, 97, 100, 32, 115, 101, 99, 116, 111, 114, 32, 40, 37, 105, 41, 32, 69, 82, 82, 79, 82, + 10, 0, 101, 104, 99, 105, 95, 105, 110, 116, 95, 119, 111, 114, 107, 105, 110, 103, 95, 99, 97, 108, 108, 98, 97, 99, + 107, 95, 112, 97, 114, 116, 49, 44, 32, 116, 105, 109, 101, 111, 117, 116, 58, 32, 37, 117, 10, 0, 117, 114, 98, 32, + 114, 101, 116, 118, 97, 108, 58, 32, 37, 105, 10, 0, 117, 110, 97, 98, 108, 101, 32, 116, 111, 32, 103, 101, 116, 32, + 100, 101, 118, 105, 99, 101, 32, 100, 101, 115, 99, 46, 46, 46, 10, 0, 103, 101, 116, 116, 105, 110, 103, 32, 85, 83, + 66, 95, 82, 69, 81, 95, 71, 69, 84, 68, 69, 83, 67, 82, 73, 80, 84, 79, 82, 32, 45, 32, 114, 101, 115, 101, 116, 10, + 0, 101, 114, 114, 111, 114, 32, 103, 101, 116, 116, 105, 110, 103, 32, 85, 83, 66, 95, 82, 69, 81, 95, 71, 69, 84, 68, + 69, 83, 67, 82, 73, 80, 84, 79, 82, 10, 0, 103, 101, 116, 116, 105, 110, 103, 32, 85, 83, 66, 95, 82, 69, 81, 95, 71, + 69, 84, 68, 69, 83, 67, 82, 73, 80, 84, 79, 82, 32, 45, 32, 97, 100, 113, 117, 105, 114, 101, 32, 45, 32, 114, 101, + 115, 101, 116, 10, 0, 85, 83, 66, 95, 82, 69, 81, 95, 71, 69, 84, 68, 69, 83, 67, 82, 73, 80, 84, 79, 82, 32, 111, 107, + 10, 0, 116, 114, 121, 105, 110, 103, 32, 85, 83, 66, 95, 82, 69, 81, 95, 83, 69, 84, 65, 68, 68, 82, 69, 83, 83, 58, + 32, 37, 100, 10, 0, 117, 110, 97, 98, 108, 101, 32, 116, 111, 32, 115, 101, 116, 32, 100, 101, 118, 105, 99, 101, 32, + 97, 100, 100, 114, 58, 32, 37, 100, 10, 0, 85, 83, 66, 95, 82, 69, 81, 95, 83, 69, 84, 65, 68, 68, 82, 69, 83, 83, 32, + 111, 107, 58, 32, 37, 100, 10, 0, 101, 114, 114, 111, 114, 32, 99, 104, 101, 99, 107, 105, 110, 103, 32, 85, 83, 66, + 95, 82, 69, 81, 95, 71, 69, 84, 68, 69, 83, 67, 82, 73, 80, 84, 79, 82, 10, 0, 111, 107, 32, 99, 104, 101, 99, 107, + 105, 110, 103, 32, 85, 83, 66, 95, 82, 69, 81, 95, 71, 69, 84, 68, 69, 83, 67, 82, 73, 80, 84, 79, 82, 10, 0, 105, 110, + 105, 116, 32, 111, 107, 10, 0, 98, 117, 102, 102, 101, 114, 32, 61, 61, 32, 78, 85, 76, 76, 32, 40, 110, 111, 32, 109, + 101, 109, 41, 10, 0, 95, 95, 117, 115, 98, 95, 103, 101, 116, 100, 101, 115, 99, 32, 101, 114, 114, 111, 114, 32, 85, + 83, 66, 95, 68, 84, 95, 68, 69, 86, 73, 67, 69, 58, 32, 114, 101, 116, 114, 121, 10, 0, 95, 95, 117, 115, 98, 95, 103, + 101, 116, 100, 101, 115, 99, 32, 101, 114, 114, 111, 114, 32, 85, 83, 66, 95, 68, 84, 95, 68, 69, 86, 73, 67, 69, 10, + 0, 117, 100, 100, 45, 62, 99, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 115, 32, 61, 61, 32, 78, 85, + 76, 76, 32, 40, 110, 111, 32, 109, 101, 109, 41, 10, 0, 95, 95, 117, 115, 98, 95, 103, 101, 116, 100, 101, 115, 99, + 32, 101, 114, 114, 111, 114, 32, 85, 83, 66, 95, 68, 84, 95, 67, 79, 78, 70, 73, 71, 58, 32, 114, 101, 116, 114, 121, + 10, 0, 117, 99, 100, 45, 62, 105, 110, 116, 101, 114, 102, 97, 99, 101, 115, 32, 61, 61, 32, 78, 85, 76, 76, 32, 40, + 110, 111, 32, 109, 101, 109, 41, 10, 0, 117, 105, 100, 45, 62, 101, 110, 100, 112, 111, 105, 110, 116, 115, 32, 61, + 61, 32, 78, 85, 76, 76, 32, 40, 110, 111, 32, 109, 101, 109, 41, 10, 0, 117, 105, 100, 45, 62, 101, 120, 116, 114, 97, + 32, 61, 61, 32, 78, 85, 76, 76, 32, 40, 110, 111, 32, 109, 101, 109, 41, 10, 0, 10, 113, 116, 100, 32, 101, 114, 114, + 111, 114, 33, 58, 0, 32, 66, 65, 66, 66, 76, 69, 0, 32, 32, 109, 105, 115, 115, 101, 100, 32, 109, 105, 99, 114, 111, + 32, 102, 114, 97, 109, 101, 0, 32, 32, 100, 97, 116, 97, 98, 117, 102, 102, 101, 114, 32, 101, 114, 114, 111, 114, 0, + 32, 119, 114, 111, 110, 103, 32, 97, 99, 107, 0, 32, 116, 111, 111, 32, 109, 97, 110, 121, 32, 101, 114, 114, 111, 114, + 115, 0, 105, 110, 116, 101, 114, 114, 117, 112, 116, 95, 99, 97, 108, 108, 98, 97, 99, 107, 95, 104, 97, 110, 100, 32, + 83, 84, 83, 95, 73, 78, 84, 10, 0, 105, 110, 116, 101, 114, 114, 117, 112, 116, 95, 99, 97, 108, 108, 98, 97, 99, 107, + 95, 104, 97, 110, 100, 32, 83, 84, 83, 95, 80, 67, 68, 10, 0, 117, 115, 98, 115, 116, 111, 114, 97, 103, 101, 32, 114, + 101, 115, 101, 116, 58, 32, 66, 85, 76, 75, 32, 82, 69, 83, 69, 84, 32, 37, 105, 10, 0, 117, 115, 98, 115, 116, 111, + 114, 97, 103, 101, 32, 114, 101, 115, 101, 116, 58, 32, 99, 108, 101, 97, 114, 104, 97, 108, 116, 32, 105, 110, 32, + 114, 101, 116, 32, 37, 105, 10, 0, 117, 115, 98, 115, 116, 111, 114, 97, 103, 101, 32, 114, 101, 115, 101, 116, 58, + 32, 99, 108, 101, 97, 114, 104, 97, 108, 116, 32, 111, 117, 116, 32, 114, 101, 116, 32, 37, 105, 10, 0, 117, 115, 98, + 115, 116, 111, 114, 97, 103, 101, 32, 114, 101, 115, 101, 116, 58, 32, 85, 83, 66, 95, 71, 101, 116, 67, 111, 110, 102, + 105, 103, 117, 114, 97, 116, 105, 111, 110, 32, 114, 101, 116, 32, 37, 105, 10, 0, 114, 101, 115, 101, 116, 32, 111, + 107, 10, 0, 95, 95, 115, 101, 110, 100, 95, 99, 98, 119, 32, 114, 101, 116, 32, 37, 105, 10, 0, 95, 95, 85, 83, 66, + 95, 66, 108, 107, 77, 115, 103, 84, 105, 109, 101, 111, 117, 116, 32, 37, 105, 10, 0, 95, 95, 114, 101, 97, 100, 95, + 99, 115, 119, 32, 37, 105, 10, 0, 32, 32, 32, 32, 83, 67, 83, 73, 95, 84, 69, 83, 84, 95, 85, 78, 73, 84, 95, 82, 69, + 65, 68, 89, 32, 114, 101, 116, 32, 37, 105, 10, 0, 32, 32, 32, 32, 83, 67, 83, 73, 95, 82, 69, 81, 85, 69, 83, 84, 95, + 83, 69, 78, 83, 69, 32, 114, 101, 116, 32, 37, 105, 10, 0, 32, 32, 32, 32, 83, 67, 83, 73, 95, 82, 69, 81, 85, 69, 83, + 84, 95, 83, 69, 78, 83, 69, 32, 115, 116, 97, 116, 117, 115, 32, 37, 120, 10, 0, 85, 83, 66, 83, 116, 111, 114, 97, + 103, 101, 95, 79, 112, 101, 110, 40, 41, 58, 32, 85, 83, 66, 95, 71, 101, 116, 68, 101, 115, 99, 114, 105, 112, 116, + 111, 114, 115, 32, 37, 105, 10, 0, 85, 83, 66, 83, 116, 111, 114, 97, 103, 101, 95, 79, 112, 101, 110, 40, 41, 58, 32, + 100, 101, 118, 105, 99, 101, 32, 99, 104, 97, 110, 103, 101, 100, 33, 33, 33, 10, 0, 85, 83, 66, 83, 116, 111, 114, + 97, 103, 101, 95, 79, 112, 101, 110, 40, 41, 58, 32, 117, 99, 100, 32, 37, 105, 32, 80, 111, 119, 101, 114, 32, 37, + 105, 32, 109, 65, 10, 0, 85, 83, 66, 83, 116, 111, 114, 97, 103, 101, 95, 79, 112, 101, 110, 40, 41, 58, 32, 105, 110, + 116, 101, 114, 102, 97, 99, 101, 32, 115, 117, 98, 99, 108, 97, 115, 115, 32, 37, 105, 32, 97, 116, 97, 95, 112, 114, + 111, 116, 32, 37, 105, 32, 10, 0, 73, 110, 32, 80, 111, 105, 110, 116, 58, 32, 37, 105, 10, 0, 79, 117, 116, 32, 80, + 111, 105, 110, 116, 58, 32, 37, 105, 10, 0, 101, 112, 95, 105, 110, 32, 37, 120, 32, 101, 112, 95, 111, 117, 116, 32, + 37, 120, 10, 0, 85, 83, 66, 83, 116, 111, 114, 97, 103, 101, 95, 79, 112, 101, 110, 40, 41, 58, 32, 99, 97, 110, 110, + 111, 116, 32, 102, 105, 110, 100, 32, 97, 110, 121, 32, 105, 110, 116, 101, 114, 102, 97, 99, 101, 33, 33, 33, 10, 0, + 85, 83, 66, 83, 116, 111, 114, 97, 103, 101, 95, 79, 112, 101, 110, 40, 41, 58, 32, 99, 111, 110, 102, 58, 32, 37, 120, + 32, 97, 108, 116, 73, 110, 116, 101, 114, 102, 97, 99, 101, 58, 32, 37, 120, 10, 0, 85, 83, 66, 95, 71, 101, 116, 67, + 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 40, 41, 32, 69, 114, 114, 111, 114, 46, 32, 67, 111, 110, + 116, 105, 110, 117, 101, 46, 10, 0, 65, 99, 116, 117, 97, 108, 32, 99, 111, 110, 102, 58, 32, 37, 120, 32, 32, 32, 110, + 101, 120, 116, 32, 99, 111, 110, 102, 58, 32, 37, 120, 10, 0, 85, 83, 66, 95, 83, 101, 116, 67, 111, 110, 102, 105, + 103, 117, 114, 97, 116, 105, 111, 110, 40, 41, 32, 69, 114, 114, 111, 114, 10, 0, 85, 83, 66, 95, 83, 101, 116, 65, + 108, 116, 101, 114, 110, 97, 116, 105, 118, 101, 73, 110, 116, 101, 114, 102, 97, 99, 101, 40, 41, 32, 69, 114, 114, + 111, 114, 46, 32, 67, 111, 110, 116, 105, 110, 117, 101, 10, 0, 85, 83, 66, 95, 83, 101, 116, 67, 111, 110, 102, 105, + 103, 117, 114, 97, 116, 105, 111, 110, 40, 41, 32, 38, 32, 85, 83, 66, 95, 83, 101, 116, 65, 108, 116, 101, 114, 110, + 97, 116, 105, 118, 101, 73, 110, 116, 101, 114, 102, 97, 99, 101, 40, 41, 32, 79, 75, 10, 0, 71, 101, 116, 95, 77, 97, + 120, 95, 76, 117, 110, 40, 41, 58, 32, 101, 114, 114, 44, 32, 100, 101, 102, 97, 117, 108, 116, 32, 109, 97, 120, 95, + 108, 117, 110, 61, 56, 10, 0, 71, 101, 116, 95, 77, 97, 120, 95, 76, 117, 110, 40, 41, 58, 32, 79, 75, 58, 32, 37, 105, + 10, 0, 85, 83, 66, 83, 116, 111, 114, 97, 103, 101, 95, 79, 112, 101, 110, 40, 41, 58, 32, 116, 114, 121, 95, 115, 116, + 97, 116, 117, 115, 32, 37, 105, 10, 0, 85, 83, 66, 83, 116, 111, 114, 97, 103, 101, 95, 79, 112, 101, 110, 40, 41, 58, + 32, 79, 75, 44, 32, 114, 101, 116, 117, 114, 110, 32, 48, 10, 0, 32, 32, 32, 32, 115, 116, 97, 114, 116, 95, 115, 116, + 111, 112, 32, 99, 109, 100, 32, 114, 101, 116, 32, 37, 105, 10, 0, 32, 32, 32, 32, 73, 110, 113, 117, 105, 114, 121, + 32, 114, 101, 116, 32, 37, 105, 10, 0, 32, 32, 32, 32, 68, 101, 118, 105, 99, 101, 32, 84, 121, 112, 101, 58, 32, 37, + 120, 10, 0, 32, 32, 32, 32, 82, 101, 97, 100, 67, 97, 112, 97, 99, 105, 116, 121, 32, 114, 101, 116, 32, 37, 105, 32, + 32, 115, 101, 99, 116, 111, 114, 95, 115, 105, 122, 101, 58, 32, 37, 117, 32, 32, 115, 101, 99, 116, 111, 114, 115, + 58, 32, 37, 117, 10, 0, 70, 97, 115, 116, 32, 85, 83, 66, 83, 116, 111, 114, 97, 103, 101, 95, 77, 111, 117, 110, 116, + 76, 85, 78, 32, 37, 105, 35, 10, 0, 85, 83, 66, 83, 116, 111, 114, 97, 103, 101, 95, 77, 111, 117, 110, 116, 76, 85, + 78, 58, 32, 114, 101, 116, 32, 37, 105, 10, 0, 85, 83, 66, 83, 84, 79, 82, 65, 71, 69, 95, 71, 69, 84, 95, 77, 65, 88, + 95, 76, 85, 78, 32, 114, 101, 116, 32, 37, 105, 32, 109, 97, 120, 108, 117, 110, 32, 37, 105, 10, 0, 85, 83, 66, 83, + 116, 111, 114, 97, 103, 101, 95, 77, 111, 117, 110, 116, 76, 85, 78, 32, 102, 97, 105, 108, 33, 33, 33, 10, 0, 10, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 10, 82, 111, 100, 114, 105, 101, + 115, 32, 101, 104, 99, 109, 111, 100, 117, 108, 101, 32, 49, 46, 48, 10, 85, 83, 66, 83, 116, 111, 114, 97, 103, 101, + 95, 73, 110, 105, 116, 40, 41, 10, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 10, 10, 0, 68, 101, 118, 105, 99, 101, 32, 105, 115, 32, 97, 32, 100, 118, 100, 10, 0, 68, 101, 118, 105, 99, 101, + 32, 105, 115, 32, 97, 32, 117, 115, 98, 104, 100, 10, 0, 85, 83, 66, 83, 116, 111, 114, 97, 103, 101, 95, 73, 110, 105, + 116, 40, 41, 32, 79, 107, 10, 0, 69, 114, 114, 111, 114, 32, 82, 101, 97, 100, 105, 110, 103, 32, 115, 101, 99, 116, + 111, 114, 32, 48, 10, 0, 79, 75, 32, 82, 101, 97, 100, 105, 110, 103, 32, 115, 101, 99, 116, 111, 114, 32, 48, 10, 0, + 85, 110, 112, 108, 117, 103, 58, 32, 114, 101, 115, 101, 116, 32, 37, 105, 32, 115, 116, 97, 116, 117, 115, 32, 37, + 120, 10, 0, 102, 97, 115, 116, 95, 114, 101, 109, 111, 117, 110, 116, 32, 75, 79, 32, 114, 101, 116, 32, 37, 105, 10, + 0, 85, 83, 66, 32, 65, 108, 108, 111, 99, 58, 32, 110, 111, 116, 32, 101, 110, 111, 117, 103, 104, 32, 109, 101, 109, + 111, 114, 121, 33, 10, 0, 119, 98, 102, 115, 32, 101, 114, 114, 111, 114, 32, 0, 98, 97, 100, 32, 109, 97, 103, 105, + 99, 0, 104, 100, 32, 115, 101, 99, 116, 111, 114, 32, 115, 105, 122, 101, 32, 100, 111, 101, 115, 110, 39, 116, 32, + 109, 97, 116, 99, 104, 0, 104, 100, 32, 110, 117, 109, 32, 115, 101, 99, 116, 111, 114, 32, 100, 111, 101, 115, 110, + 39, 116, 32, 109, 97, 116, 99, 104, 0, 78, 84, 70, 83, 0, 70, 65, 84, 0, 116, 114, 121, 105, 110, 103, 32, 116, 111, + 32, 99, 108, 111, 115, 101, 32, 119, 98, 102, 115, 32, 119, 104, 105, 108, 101, 32, 100, 105, 115, 99, 115, 32, 115, + 116, 105, 108, 108, 32, 111, 112, 101, 110, 0, 97, 108, 108, 111, 99, 97, 116, 105, 110, 103, 32, 109, 101, 109, 111, + 114, 121, 0 +}; diff --git a/source/mload/modules/ehcmodule_5.h b/source/mload/modules/ehcmodule_5.h new file mode 100644 index 0000000..85b0d53 --- /dev/null +++ b/source/mload/modules/ehcmodule_5.h @@ -0,0 +1,3 @@ +#define size_ehcmodule_5 27134 + +extern unsigned char ehcmodule_5[27134]; diff --git a/source/mload/modules/odip_frag.c b/source/mload/modules/odip_frag.c new file mode 100644 index 0000000..c044ec5 --- /dev/null +++ b/source/mload/modules/odip_frag.c @@ -0,0 +1,574 @@ +unsigned char odip_frag[9120] __attribute__((aligned (32)))={ + 0x13, 0x77, 0xca, 0x6d, 0x12, 0x34, 0x00, 0x01, 0x20, 0x22, 0xdd, 0xac, 0x20, 0x20, 0x10, 0x11, + 0x20, 0x20, 0x0b, 0x9d, 0x20, 0x20, 0x0b, 0x71, 0x20, 0x20, 0x5d, 0xc1, 0x20, 0x20, 0x00, 0x49, + 0x20, 0x20, 0x2b, 0x4d, 0x20, 0x20, 0x39, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x77, 0xe2, 0xa0, 0x13, 0x77, 0xd8, 0xe0, + 0x13, 0x77, 0xd5, 0x2d, 0x13, 0x77, 0xe3, 0xa0, 0x00, 0x00, 0x10, 0xa0, 0xe1, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb5, 0x00, 0x23, 0xe3, 0xb0, 0x89, 0x06, 0x1b, 0x93, 0x00, 0x46, 0x68, 0x23, 0x00, 0x21, 0x00, + 0x22, 0x00, 0x93, 0x01, 0x93, 0x02, 0xf0, 0x01, 0xfa, 0xed, 0xb0, 0x09, 0xbc, 0x02, 0x47, 0x08, + 0xb5, 0x10, 0x1c, 0x03, 0x22, 0x20, 0x1c, 0x0c, 0x48, 0x0d, 0x1c, 0x19, 0xf0, 0x01, 0xfc, 0x82, + 0x48, 0x0b, 0x21, 0x20, 0xf0, 0x01, 0xfc, 0x72, 0x4a, 0x0a, 0x23, 0x01, 0x68, 0x11, 0x42, 0x0b, + 0xd1, 0xfc, 0x22, 0x20, 0x1c, 0x20, 0x49, 0x06, 0xf0, 0x01, 0xfc, 0x74, 0x1c, 0x20, 0x21, 0x20, + 0xf0, 0x01, 0xfc, 0x64, 0x4b, 0x04, 0x68, 0x18, 0xbc, 0x10, 0xbc, 0x02, 0x47, 0x08, 0x46, 0xc0, + 0x0d, 0x00, 0x60, 0x00, 0x0d, 0x00, 0x60, 0x1c, 0x0d, 0x00, 0x60, 0x20, 0xb5, 0xf0, 0xb0, 0x8d, + 0x1c, 0x0e, 0x27, 0xd0, 0x0a, 0xc9, 0x90, 0x01, 0x92, 0x03, 0x91, 0x02, 0x25, 0x00, 0xac, 0x04, + 0x06, 0x3f, 0x99, 0x03, 0x9b, 0x02, 0x22, 0x00, 0x61, 0x21, 0x98, 0x01, 0x1c, 0x31, 0x60, 0xe3, + 0x60, 0x62, 0x60, 0xa2, 0x35, 0x01, 0x60, 0x27, 0xf0, 0x01, 0xfc, 0x48, 0x99, 0x01, 0x1c, 0x32, + 0x1c, 0x20, 0xf0, 0x01, 0xfa, 0xa7, 0x0f, 0xeb, 0x22, 0x00, 0x21, 0x1f, 0x42, 0xa9, 0x41, 0x53, + 0x06, 0x1b, 0x2b, 0x00, 0xd0, 0x01, 0x28, 0x00, 0xd1, 0xe3, 0xb0, 0x0d, 0xbc, 0xf0, 0xbc, 0x02, + 0x47, 0x08, 0xb5, 0xf0, 0xb0, 0x8b, 0x27, 0xa8, 0x90, 0x00, 0x1c, 0x0e, 0x92, 0x01, 0x25, 0x00, + 0xac, 0x02, 0x06, 0x3f, 0x99, 0x01, 0x98, 0x00, 0x60, 0xa1, 0x1c, 0x31, 0x35, 0x01, 0x60, 0x27, + 0x60, 0x66, 0xf0, 0x01, 0xfc, 0x23, 0x99, 0x00, 0x1c, 0x32, 0x1c, 0x20, 0xf0, 0x01, 0xfa, 0x82, + 0x0f, 0xeb, 0x22, 0x00, 0x21, 0x07, 0x42, 0xa9, 0x41, 0x53, 0x06, 0x1b, 0x2b, 0x00, 0xd0, 0x01, + 0x28, 0x00, 0xd1, 0xe7, 0xb0, 0x0b, 0xbc, 0xf0, 0xbc, 0x02, 0x47, 0x08, 0xb5, 0xf0, 0xb0, 0x87, + 0x90, 0x05, 0x91, 0x03, 0x92, 0x04, 0x25, 0x00, 0x29, 0x00, 0xd0, 0x75, 0x0a, 0x51, 0x91, 0x01, + 0x95, 0x00, 0xe0, 0x69, 0x9a, 0x03, 0x9b, 0x00, 0x99, 0x01, 0x1a, 0xd4, 0x9a, 0x04, 0x02, 0x4b, + 0x27, 0x00, 0x42, 0x9a, 0xd9, 0x01, 0x1a, 0xd7, 0x00, 0xbf, 0x9b, 0x05, 0x21, 0x1f, 0x1c, 0x1e, + 0x9b, 0x00, 0x18, 0xf6, 0x23, 0x00, 0x42, 0x0e, 0xd1, 0x19, 0x4b, 0x32, 0x22, 0x00, 0x42, 0x9e, + 0xd8, 0x02, 0x22, 0xc0, 0x04, 0x52, 0x1b, 0x92, 0x21, 0xf0, 0x06, 0x09, 0x18, 0x73, 0x49, 0x2e, + 0x42, 0x8b, 0xd8, 0x01, 0x4a, 0x2d, 0x1b, 0x92, 0x49, 0x2d, 0x23, 0x00, 0x42, 0x8a, 0xd9, 0x03, + 0x1c, 0x13, 0x42, 0xa2, 0xd9, 0x00, 0x1c, 0x23, 0x05, 0x5a, 0x0d, 0x52, 0x1a, 0x9b, 0x2b, 0x00, + 0xd0, 0x01, 0x2f, 0x00, 0xd0, 0x22, 0x23, 0x80, 0x19, 0x3a, 0x01, 0x1b, 0x42, 0x9a, 0xd9, 0x00, + 0x1b, 0xdc, 0x20, 0x80, 0x01, 0x00, 0x21, 0x20, 0xf0, 0x01, 0xfb, 0xbc, 0x90, 0x02, 0x28, 0x00, + 0xd0, 0x30, 0x21, 0x80, 0x01, 0x09, 0x9a, 0x01, 0xf7, 0xff, 0xff, 0x60, 0x1e, 0x05, 0xd1, 0x09, + 0x9a, 0x02, 0x1c, 0x30, 0x19, 0xd1, 0x1c, 0x22, 0xf0, 0x01, 0xfb, 0xbc, 0x1c, 0x30, 0x1c, 0x21, + 0xf0, 0x01, 0xfb, 0xac, 0x98, 0x02, 0xf0, 0x01, 0xfb, 0xa1, 0xe0, 0x0b, 0x1c, 0x1c, 0x4b, 0x15, + 0x42, 0x9c, 0xd9, 0x01, 0x24, 0xff, 0x03, 0xe4, 0x1c, 0x30, 0x1c, 0x21, 0x9a, 0x01, 0xf7, 0xff, + 0xff, 0x45, 0x1c, 0x05, 0x2d, 0x00, 0xd1, 0x0f, 0x9b, 0x00, 0x99, 0x01, 0x19, 0x1b, 0x19, 0xe4, + 0x0a, 0xe4, 0x19, 0x09, 0x93, 0x00, 0x91, 0x01, 0x9a, 0x00, 0x9b, 0x03, 0x42, 0x9a, 0xd3, 0x91, + 0x25, 0x00, 0xe0, 0x01, 0x25, 0x01, 0x42, 0x6d, 0xb0, 0x07, 0x1c, 0x28, 0xbc, 0xf0, 0xbc, 0x02, + 0x47, 0x08, 0x46, 0xc0, 0x01, 0x7f, 0xff, 0xff, 0x03, 0x61, 0x7f, 0xff, 0x13, 0x61, 0x80, 0x00, + 0x00, 0x00, 0x07, 0xff, 0x00, 0x7f, 0x7f, 0xff, 0xb5, 0xf8, 0x4e, 0x26, 0x27, 0x01, 0x1c, 0x04, + 0x60, 0x37, 0x21, 0x20, 0xf0, 0x01, 0xfb, 0x7a, 0x7b, 0x22, 0x7b, 0x63, 0x06, 0x12, 0x04, 0x1b, + 0x43, 0x13, 0x7b, 0xa2, 0x02, 0x12, 0x43, 0x13, 0x7b, 0xe2, 0x43, 0x13, 0x2b, 0x08, 0xd1, 0x30, + 0x7e, 0x22, 0x7e, 0x63, 0x06, 0x12, 0x04, 0x1b, 0x43, 0x13, 0x7e, 0xa2, 0x25, 0xc5, 0x02, 0x12, + 0x43, 0x13, 0x7e, 0xe2, 0x01, 0xad, 0x43, 0x13, 0x68, 0x18, 0x68, 0x59, 0xf0, 0x01, 0xfb, 0x5e, + 0x7e, 0x22, 0x7e, 0x63, 0x06, 0x12, 0x04, 0x1b, 0x43, 0x13, 0x7e, 0xa2, 0x1c, 0x28, 0x02, 0x12, + 0x43, 0x13, 0x7e, 0xe2, 0x21, 0x08, 0x43, 0x13, 0x68, 0x1b, 0x68, 0x5c, 0xf0, 0x01, 0xfb, 0x4e, + 0x04, 0x24, 0x43, 0x27, 0x4c, 0x0c, 0x60, 0x2f, 0x1c, 0x28, 0x21, 0x04, 0x60, 0x27, 0xf0, 0x01, + 0xfb, 0x3d, 0x1c, 0x20, 0x21, 0x04, 0xf0, 0x01, 0xfb, 0x39, 0x23, 0x00, 0x60, 0x33, 0x20, 0x00, + 0xe0, 0x04, 0x1c, 0x20, 0xf0, 0x01, 0xf9, 0x11, 0x23, 0x00, 0x60, 0x33, 0xbc, 0xf8, 0xbc, 0x02, + 0x47, 0x08, 0x46, 0xc0, 0x13, 0x77, 0xe3, 0xa0, 0x00, 0x00, 0x31, 0x88, 0x4a, 0x03, 0x23, 0x00, + 0x60, 0x13, 0x4a, 0x03, 0x60, 0x13, 0x4a, 0x03, 0x60, 0x13, 0x47, 0x70, 0x13, 0x77, 0xe5, 0xe8, + 0x13, 0x77, 0xe3, 0xc0, 0x13, 0x77, 0xe3, 0xb8, 0xb5, 0xf0, 0x4b, 0x10, 0x21, 0xa0, 0x48, 0x10, + 0x68, 0x1c, 0x22, 0x00, 0x23, 0x00, 0x00, 0x89, 0x03, 0xd6, 0xe0, 0x01, 0x04, 0x2b, 0x0c, 0x1b, + 0x00, 0x5d, 0x18, 0xed, 0x00, 0xad, 0x19, 0x65, 0x69, 0x6f, 0x68, 0xed, 0x19, 0x7d, 0x42, 0xae, + 0xd3, 0x03, 0x68, 0x67, 0x1c, 0x5d, 0x42, 0xbd, 0xd3, 0xf0, 0x32, 0x01, 0x80, 0x03, 0x30, 0x02, + 0x42, 0x8a, 0xd1, 0xe9, 0xbc, 0xf0, 0xbc, 0x01, 0x47, 0x00, 0x46, 0xc0, 0x13, 0x77, 0xe3, 0xc0, + 0x13, 0x77, 0xe6, 0x04, 0xb5, 0xf8, 0x4b, 0x22, 0x1c, 0x06, 0x68, 0x1b, 0x1c, 0x0f, 0x1c, 0x14, + 0x2b, 0x00, 0xd0, 0x01, 0xf7, 0xff, 0xff, 0xc2, 0x1e, 0x73, 0x2b, 0x01, 0xd8, 0x30, 0x2c, 0x00, + 0xd0, 0x2e, 0x4b, 0x1c, 0x42, 0x9c, 0xd8, 0x2d, 0x4d, 0x1b, 0x2e, 0x01, 0xd1, 0x02, 0xf0, 0x00, + 0xfe, 0x29, 0xe0, 0x01, 0xf0, 0x00, 0xfd, 0x72, 0x4b, 0x17, 0x60, 0x28, 0x68, 0x18, 0x28, 0x00, + 0xd1, 0x22, 0x4b, 0x16, 0x4d, 0x16, 0x60, 0x1e, 0x4b, 0x16, 0x1c, 0x38, 0x60, 0x2b, 0x1c, 0x21, + 0xf0, 0x01, 0xfa, 0xd4, 0x68, 0x2d, 0x21, 0x00, 0x4a, 0x0e, 0x1c, 0x28, 0xf0, 0x01, 0xfa, 0x2a, + 0x1c, 0x22, 0x1c, 0x39, 0x1c, 0x28, 0xf0, 0x01, 0xf9, 0xe3, 0x1c, 0x38, 0x1c, 0x21, 0xf0, 0x01, + 0xfa, 0xbd, 0xf7, 0xff, 0xff, 0xa1, 0x4b, 0x06, 0x22, 0x01, 0x60, 0x1a, 0x1c, 0x20, 0xe0, 0x03, + 0x20, 0x01, 0xe0, 0x00, 0x20, 0x02, 0x42, 0x40, 0xbc, 0xf8, 0xbc, 0x02, 0x47, 0x08, 0x46, 0xc0, + 0x13, 0x77, 0xe5, 0xe8, 0x00, 0x00, 0xa4, 0x1c, 0x13, 0x77, 0xe3, 0xb4, 0x13, 0x77, 0xe3, 0xb8, + 0x13, 0x77, 0xe3, 0xc0, 0x13, 0x73, 0x00, 0x00, 0xb5, 0xf0, 0xb0, 0x83, 0x24, 0xa0, 0x4d, 0x36, + 0x0b, 0xcf, 0x00, 0xa4, 0x9e, 0x09, 0x60, 0x2f, 0x42, 0xa7, 0xd9, 0x01, 0x4c, 0x33, 0x60, 0x2c, + 0x4c, 0x31, 0x4d, 0x33, 0x68, 0x24, 0x46, 0x9c, 0x00, 0x64, 0x5b, 0x2c, 0x4d, 0x31, 0x00, 0x67, + 0x60, 0x2c, 0x4d, 0x31, 0x19, 0x3f, 0x60, 0x2c, 0x68, 0x45, 0x00, 0xbf, 0x95, 0x00, 0x19, 0xc7, + 0x18, 0x55, 0x37, 0x0c, 0x95, 0x01, 0xe0, 0x37, 0x68, 0x3d, 0x42, 0x8d, 0xd8, 0x19, 0x68, 0xbb, + 0x18, 0xeb, 0x42, 0x8b, 0xd9, 0x2e, 0x4f, 0x28, 0x1b, 0x4d, 0x60, 0x3c, 0x4f, 0x27, 0x46, 0x63, + 0x60, 0x3d, 0x60, 0x19, 0x00, 0x63, 0x19, 0x1c, 0x00, 0xa4, 0x19, 0x00, 0x69, 0x03, 0x99, 0x08, + 0x18, 0xeb, 0x60, 0x0b, 0x69, 0x43, 0x20, 0x00, 0x1b, 0x5d, 0x60, 0x35, 0x42, 0x95, 0xd9, 0x2e, + 0xe0, 0x16, 0x9b, 0x01, 0x42, 0x9d, 0xd2, 0x15, 0x4f, 0x1b, 0x46, 0x63, 0x60, 0x3c, 0x4f, 0x1b, + 0x1a, 0x69, 0x60, 0x39, 0x60, 0x1d, 0x00, 0x63, 0x19, 0x1c, 0x00, 0xa4, 0x19, 0x00, 0x69, 0x03, + 0x9c, 0x08, 0x1a, 0x52, 0x60, 0x23, 0x69, 0x43, 0x20, 0x00, 0x60, 0x33, 0x42, 0x93, 0xd9, 0x16, + 0x60, 0x32, 0xe0, 0x14, 0x34, 0x01, 0x37, 0x0c, 0x9d, 0x00, 0x42, 0xac, 0xd3, 0xc4, 0x4d, 0x0e, + 0x18, 0x51, 0x68, 0x02, 0x46, 0x63, 0x60, 0x2c, 0x42, 0x91, 0xd8, 0x06, 0x60, 0x19, 0x99, 0x08, + 0x23, 0x00, 0x60, 0x0b, 0x20, 0x00, 0x60, 0x33, 0xe0, 0x01, 0x20, 0x02, 0x42, 0x40, 0xb0, 0x03, + 0xbc, 0xf0, 0xbc, 0x02, 0x47, 0x08, 0x46, 0xc0, 0x13, 0x77, 0xe3, 0xa4, 0x00, 0x00, 0x02, 0x7f, + 0x13, 0x77, 0xe6, 0x04, 0x13, 0x77, 0xe5, 0xfc, 0x13, 0x77, 0xeb, 0x04, 0x13, 0x77, 0xe5, 0xec, + 0xb5, 0xf0, 0xb0, 0x85, 0x1c, 0x06, 0x1c, 0x0d, 0x1c, 0x17, 0xe0, 0x46, 0x4a, 0x29, 0x4b, 0x2a, + 0x68, 0x10, 0x4a, 0x2a, 0x93, 0x00, 0x92, 0x01, 0x4b, 0x29, 0x1c, 0x31, 0x1c, 0x3a, 0xf7, 0xff, + 0xff, 0x73, 0x4b, 0x28, 0x60, 0x18, 0x28, 0x00, 0xd1, 0x3f, 0x4a, 0x25, 0x68, 0x13, 0x1b, 0x9b, + 0x93, 0x03, 0x9a, 0x03, 0x4b, 0x24, 0x60, 0x1a, 0x2a, 0x00, 0xd0, 0x09, 0x02, 0x54, 0x1c, 0x28, + 0x21, 0x00, 0x1c, 0x22, 0xf0, 0x01, 0xf9, 0x66, 0x9b, 0x03, 0x19, 0x2d, 0x18, 0xf6, 0x1a, 0xff, + 0x4b, 0x1a, 0x68, 0x19, 0x29, 0x00, 0xd0, 0x19, 0x4b, 0x1c, 0x4c, 0x1a, 0x68, 0x1a, 0x4b, 0x16, + 0x2a, 0x01, 0xd1, 0x04, 0x68, 0x18, 0x1c, 0x2a, 0xf0, 0x00, 0xfc, 0xf4, 0xe0, 0x03, 0x68, 0x18, + 0x1c, 0x2a, 0xf0, 0x00, 0xfc, 0xa9, 0x4b, 0x13, 0x60, 0x20, 0x68, 0x1b, 0x2b, 0x00, 0xd0, 0x10, + 0x4b, 0x0e, 0x68, 0x1b, 0x02, 0x5a, 0x18, 0xf6, 0x18, 0xad, 0x1a, 0xff, 0x4b, 0x0b, 0x68, 0x1a, + 0x4b, 0x0d, 0x68, 0x1b, 0x18, 0xd3, 0x2b, 0x00, 0xd0, 0x05, 0x2f, 0x00, 0xd1, 0xb6, 0x20, 0x00, + 0xe0, 0x03, 0x20, 0x03, 0xe0, 0x00, 0x20, 0x04, 0x42, 0x40, 0xb0, 0x05, 0xbc, 0xf0, 0xbc, 0x02, + 0x47, 0x08, 0x46, 0xc0, 0x13, 0x77, 0xe3, 0xc0, 0x13, 0x77, 0xe3, 0xc8, 0x13, 0x77, 0xe5, 0xf0, + 0x13, 0x77, 0xe3, 0xac, 0x13, 0x77, 0xe6, 0x00, 0x13, 0x77, 0xe3, 0xbc, 0x13, 0x77, 0xe3, 0xb8, + 0xb5, 0xf8, 0x1c, 0x1e, 0x4b, 0x1a, 0x1c, 0x0f, 0x09, 0xc1, 0x60, 0x19, 0x23, 0x7f, 0x40, 0x18, + 0x4b, 0x18, 0x00, 0x80, 0x60, 0x18, 0x23, 0x80, 0x00, 0x9b, 0x4c, 0x17, 0x1a, 0x1b, 0x60, 0x23, + 0x42, 0x93, 0xd9, 0x00, 0x60, 0x22, 0x4a, 0x14, 0x23, 0x80, 0x68, 0x10, 0x00, 0x9b, 0x42, 0x98, + 0xd1, 0x01, 0x23, 0x00, 0x60, 0x13, 0x4c, 0x10, 0x68, 0x23, 0x2b, 0x00, 0xd0, 0x10, 0x4d, 0x0f, + 0x1c, 0x08, 0x22, 0x01, 0x1c, 0x29, 0xf7, 0xff, 0xff, 0x73, 0x4b, 0x0d, 0x60, 0x18, 0x28, 0x00, + 0xd1, 0x0a, 0x4b, 0x08, 0x68, 0x22, 0x68, 0x19, 0x1c, 0x38, 0x18, 0x69, 0xf0, 0x01, 0xf8, 0xb0, + 0x4b, 0x05, 0x20, 0x00, 0x68, 0x1b, 0x60, 0x33, 0xbc, 0xf8, 0xbc, 0x02, 0x47, 0x08, 0x46, 0xc0, + 0x13, 0x77, 0xe5, 0xf4, 0x13, 0x77, 0xe5, 0xf8, 0x13, 0x77, 0xe3, 0xa8, 0x13, 0x77, 0xe3, 0xe0, + 0x13, 0x77, 0xe5, 0xe0, 0xb5, 0xf0, 0xb0, 0x85, 0x4d, 0x25, 0x90, 0x01, 0x91, 0x03, 0x1c, 0x10, + 0x1c, 0x17, 0x99, 0x01, 0x9a, 0x03, 0x1c, 0x2b, 0xf7, 0xff, 0xff, 0xb2, 0x4e, 0x21, 0x1c, 0x04, + 0x60, 0x30, 0x28, 0x00, 0xd1, 0x37, 0x68, 0x2d, 0x99, 0x01, 0x08, 0xab, 0x18, 0xfb, 0x9a, 0x03, + 0x93, 0x02, 0x4b, 0x1d, 0x19, 0x49, 0x1b, 0x55, 0x91, 0x01, 0x42, 0x9d, 0xd9, 0x15, 0x9b, 0x02, + 0x4f, 0x1a, 0x09, 0xd8, 0x4b, 0x1a, 0x0a, 0x6a, 0x60, 0x18, 0x60, 0x3a, 0xf7, 0xff, 0xff, 0x30, + 0x60, 0x30, 0x28, 0x00, 0xd1, 0x1b, 0x68, 0x3b, 0x99, 0x02, 0x01, 0xda, 0x18, 0x89, 0x9a, 0x01, + 0x02, 0x5b, 0x18, 0xd2, 0x91, 0x02, 0x92, 0x01, 0x1a, 0xed, 0x2d, 0x00, 0xd0, 0x13, 0x4e, 0x0c, + 0x98, 0x02, 0x1c, 0x33, 0x99, 0x01, 0x1c, 0x2a, 0xf7, 0xff, 0xff, 0x82, 0x4b, 0x09, 0x1c, 0x04, + 0x60, 0x18, 0x28, 0x00, 0xd1, 0x07, 0x68, 0x33, 0x42, 0x9d, 0xd1, 0x02, 0xe0, 0x03, 0x1c, 0x04, + 0xe0, 0x01, 0x24, 0x05, 0x42, 0x64, 0xb0, 0x05, 0x1c, 0x20, 0xbc, 0xf0, 0xbc, 0x02, 0x47, 0x08, + 0x13, 0x77, 0xe3, 0xb0, 0x13, 0x77, 0xe3, 0xc4, 0x00, 0x00, 0x01, 0xff, 0x13, 0x77, 0xe5, 0xe4, + 0x13, 0x77, 0xeb, 0x08, 0xb5, 0x00, 0x4b, 0x0b, 0x68, 0x1b, 0x2b, 0x01, 0xd0, 0x02, 0x2b, 0x02, + 0xd1, 0x0c, 0xe0, 0x01, 0x4a, 0x08, 0xe0, 0x00, 0x4a, 0x08, 0x23, 0x00, 0x42, 0x90, 0xd3, 0x06, + 0x4b, 0x07, 0x4a, 0x08, 0x62, 0x1a, 0x23, 0xa0, 0x02, 0x1b, 0xe0, 0x00, 0x23, 0x00, 0x1c, 0x18, + 0xbc, 0x02, 0x47, 0x08, 0x13, 0x77, 0xeb, 0x10, 0x46, 0x09, 0x00, 0x00, 0x7e, 0xd3, 0x80, 0x00, + 0x13, 0x77, 0xeb, 0x14, 0x00, 0x05, 0x21, 0x00, 0xb5, 0x10, 0x4b, 0x0c, 0x1d, 0xdc, 0x7f, 0xe4, + 0x2c, 0x00, 0xd0, 0x02, 0xf7, 0xff, 0xff, 0x7e, 0xe0, 0x0d, 0x69, 0x1c, 0x2c, 0x00, 0xd0, 0x02, + 0xf0, 0x00, 0xfc, 0xb8, 0xe0, 0x07, 0x68, 0x5b, 0x2b, 0x00, 0xd0, 0x02, 0xf7, 0xff, 0xfc, 0xe6, + 0xe0, 0x01, 0xf7, 0xff, 0xfc, 0xbe, 0xbc, 0x10, 0xbc, 0x02, 0x47, 0x08, 0x13, 0x77, 0xeb, 0x14, + 0xb5, 0xf0, 0xb0, 0x85, 0x90, 0x02, 0x1c, 0x10, 0x91, 0x03, 0x1c, 0x14, 0xf7, 0xff, 0xff, 0xba, + 0x28, 0x00, 0xd0, 0x00, 0xe0, 0xfe, 0x4b, 0x81, 0x68, 0xdd, 0x68, 0x9a, 0x18, 0xad, 0x19, 0x2d, + 0x95, 0x01, 0x69, 0x1b, 0x2b, 0x00, 0xd0, 0x12, 0x4b, 0x7d, 0x68, 0x1b, 0x2b, 0x00, 0xdd, 0x00, + 0xe0, 0xeb, 0x4b, 0x7c, 0x68, 0x19, 0x29, 0x00, 0xd0, 0x01, 0xf0, 0x01, 0xf8, 0xe7, 0x4b, 0x79, + 0x22, 0x00, 0x60, 0x1a, 0x23, 0x01, 0x4a, 0x78, 0x42, 0x5b, 0x60, 0x13, 0xe0, 0xdd, 0x4b, 0x76, + 0x49, 0x76, 0x68, 0x1b, 0x18, 0x5a, 0x2a, 0x00, 0xd1, 0x00, 0xe0, 0xa8, 0x2b, 0x00, 0xda, 0x00, + 0xe0, 0xa5, 0x4c, 0x70, 0x68, 0x23, 0x2b, 0x00, 0xd1, 0x06, 0x21, 0x80, 0x20, 0x00, 0x01, 0x89, + 0x22, 0x20, 0xf0, 0x01, 0xf8, 0xbb, 0x60, 0x20, 0x20, 0x80, 0x01, 0x00, 0x21, 0x20, 0xf0, 0x01, + 0xf8, 0xa1, 0x1e, 0x04, 0xd1, 0x03, 0x23, 0x01, 0x4a, 0x67, 0x42, 0x5b, 0x60, 0x13, 0x4e, 0x66, + 0x22, 0x00, 0x68, 0x33, 0x92, 0x00, 0x2b, 0x00, 0xdb, 0x26, 0x1c, 0x35, 0x27, 0x00, 0x68, 0x32, + 0x21, 0x80, 0x1c, 0x13, 0x33, 0x10, 0x02, 0x5b, 0x02, 0x52, 0x1c, 0x20, 0x01, 0x09, 0x93, 0x00, + 0xf7, 0xff, 0xff, 0x8a, 0x28, 0x00, 0xda, 0x03, 0x23, 0x01, 0x42, 0x5b, 0x60, 0x33, 0xe0, 0x13, + 0x78, 0x23, 0x2b, 0x43, 0xd1, 0x08, 0x78, 0x63, 0x2b, 0x49, 0xd1, 0x05, 0x78, 0xa3, 0x2b, 0x53, + 0xd1, 0x02, 0x78, 0xe3, 0x2b, 0x4f, 0xd0, 0x07, 0x68, 0x2b, 0x2b, 0x00, 0xd0, 0x01, 0x60, 0x2f, + 0xe7, 0xdd, 0x23, 0x01, 0x42, 0x5b, 0x60, 0x2b, 0x4e, 0x4f, 0x68, 0x33, 0x2b, 0x00, 0xdb, 0x59, + 0x4b, 0x4c, 0x68, 0x1b, 0x2b, 0x00, 0xd0, 0x55, 0x79, 0x62, 0x79, 0xa3, 0x02, 0x12, 0x04, 0x1b, + 0x18, 0xd2, 0x79, 0x23, 0x48, 0x4a, 0x18, 0xd2, 0x79, 0xe3, 0x21, 0x00, 0x06, 0x1b, 0x18, 0xd2, + 0x4b, 0x48, 0x08, 0x92, 0x60, 0x1a, 0x22, 0x80, 0x01, 0x12, 0xf0, 0x00, 0xfb, 0xcb, 0x27, 0x08, + 0x25, 0x00, 0x05, 0x7b, 0x2b, 0x00, 0xd1, 0x16, 0x49, 0x43, 0x23, 0x01, 0x42, 0x8d, 0xdc, 0x00, + 0x23, 0x00, 0x06, 0x1b, 0x2b, 0x00, 0xd0, 0x0e, 0x68, 0x33, 0x12, 0xfa, 0x18, 0xd2, 0x21, 0x80, + 0x02, 0x52, 0x1c, 0x20, 0x01, 0x09, 0xf7, 0xff, 0xff, 0x3f, 0x28, 0x00, 0xda, 0x03, 0x23, 0x01, + 0x42, 0x5b, 0x60, 0x33, 0xe0, 0x20, 0x20, 0x07, 0x40, 0x28, 0xd1, 0x05, 0x4b, 0x31, 0x10, 0xea, + 0x68, 0x1b, 0x99, 0x00, 0x00, 0x92, 0x50, 0xd1, 0x05, 0x7b, 0x0d, 0x5b, 0x5c, 0xe3, 0x2b, 0x00, + 0xd0, 0x0c, 0x4a, 0x2f, 0x21, 0x01, 0x10, 0xeb, 0x40, 0x81, 0x1c, 0x08, 0x5c, 0xd1, 0x43, 0x01, + 0x54, 0xd1, 0x4b, 0x2c, 0x9a, 0x00, 0x68, 0x1b, 0x18, 0xd2, 0x92, 0x00, 0x23, 0x80, 0x35, 0x01, + 0x01, 0xdb, 0x37, 0x01, 0x42, 0x9d, 0xd1, 0xc4, 0x4b, 0x23, 0x68, 0x1a, 0x2a, 0x00, 0xdb, 0x01, + 0x4a, 0x26, 0x60, 0x1a, 0x2c, 0x00, 0xd0, 0x02, 0x1c, 0x20, 0xf0, 0x01, 0xf8, 0x07, 0x4b, 0x1e, + 0x4c, 0x1c, 0x68, 0x1a, 0x4b, 0x21, 0x42, 0x9a, 0xd1, 0x1e, 0x4b, 0x1e, 0x98, 0x01, 0x68, 0x1d, + 0x1c, 0x29, 0xf0, 0x01, 0xf8, 0x1b, 0x68, 0x23, 0x08, 0xc1, 0x24, 0x07, 0x00, 0x8a, 0x58, 0xd2, + 0x40, 0x20, 0x23, 0x00, 0x4e, 0x16, 0x24, 0x01, 0xe0, 0x05, 0x5c, 0x77, 0x41, 0x1f, 0x42, 0x3c, + 0xd0, 0x00, 0x19, 0x52, 0x33, 0x01, 0x42, 0x83, 0xd3, 0xf7, 0x9b, 0x01, 0x3d, 0x01, 0x40, 0x1d, + 0x19, 0x52, 0x98, 0x02, 0x99, 0x03, 0xe0, 0x0b, 0x68, 0x21, 0x29, 0x00, 0xd0, 0x02, 0x20, 0x00, + 0xf0, 0x01, 0xf8, 0x04, 0x4b, 0x07, 0x22, 0x00, 0x60, 0x1a, 0x98, 0x02, 0x99, 0x03, 0x9a, 0x01, + 0xf7, 0xff, 0xfe, 0xda, 0xb0, 0x05, 0xbc, 0xf0, 0xbc, 0x02, 0x47, 0x08, 0x13, 0x77, 0xeb, 0x14, + 0x13, 0x77, 0xec, 0x24, 0x13, 0x77, 0xeb, 0x0c, 0x13, 0x77, 0xe2, 0x04, 0x80, 0x00, 0x00, 0x01, + 0x13, 0x77, 0xec, 0x40, 0x13, 0x77, 0xeb, 0x3c, 0x00, 0x00, 0x07, 0xf7, 0x7f, 0xff, 0xff, 0xff, + 0xb5, 0x10, 0x21, 0x80, 0x20, 0x00, 0x01, 0x09, 0x22, 0x20, 0xf0, 0x00, 0xff, 0xcf, 0x1e, 0x04, + 0xd0, 0x10, 0x21, 0x80, 0x22, 0x8e, 0x01, 0x09, 0x1c, 0x20, 0x05, 0xd2, 0xf7, 0xff, 0xfe, 0xd0, + 0x1e, 0x43, 0x41, 0x98, 0x23, 0x02, 0x1a, 0x18, 0x4b, 0x04, 0x1c, 0x21, 0x60, 0x18, 0x20, 0x00, + 0xf0, 0x00, 0xff, 0xcc, 0xbc, 0x10, 0xbc, 0x01, 0x47, 0x00, 0x46, 0xc0, 0x13, 0x77, 0xeb, 0x10, + 0xb5, 0x38, 0x22, 0x00, 0x21, 0x20, 0x1c, 0x04, 0xf7, 0xff, 0xfe, 0xba, 0x69, 0xa2, 0x4b, 0x09, + 0x1c, 0x05, 0x42, 0x9a, 0xd1, 0x09, 0x4b, 0x08, 0x21, 0x01, 0x68, 0x1a, 0x70, 0x11, 0x68, 0x1b, + 0x78, 0x5b, 0x2b, 0x00, 0xd1, 0x01, 0xf0, 0x00, 0xff, 0x85, 0x1c, 0x28, 0xbc, 0x38, 0xbc, 0x02, + 0x47, 0x08, 0x46, 0xc0, 0x5d, 0x1c, 0x9e, 0xa3, 0x13, 0x77, 0xc0, 0x08, 0xb5, 0xf0, 0xb0, 0x83, + 0x92, 0x01, 0x78, 0x02, 0x1c, 0x07, 0x92, 0x00, 0x4a, 0xba, 0x1c, 0x0d, 0x68, 0x13, 0x2b, 0x00, + 0xd0, 0x0d, 0x4c, 0xb9, 0x4e, 0xb9, 0x68, 0x20, 0x68, 0x32, 0x21, 0x00, 0xf0, 0x00, 0xfa, 0xea, + 0x68, 0x20, 0x68, 0x31, 0xf0, 0x00, 0xff, 0x72, 0x4a, 0xb2, 0x23, 0x00, 0x60, 0x13, 0x9b, 0x00, + 0x2b, 0xe0, 0xd0, 0x61, 0x4c, 0xb2, 0x26, 0x00, 0x62, 0x26, 0x2b, 0xda, 0xd1, 0x00, 0xe1, 0x51, + 0x2b, 0xda, 0xd8, 0x2f, 0x2b, 0x8a, 0xd1, 0x00, 0xe1, 0xb6, 0x2b, 0x8a, 0xd8, 0x12, 0x2b, 0x15, + 0xd1, 0x00, 0xe1, 0x1c, 0x2b, 0x15, 0xd8, 0x03, 0x2b, 0x13, 0xd2, 0x00, 0xe1, 0xd8, 0xe0, 0xf0, + 0x9a, 0x00, 0x2a, 0x71, 0xd1, 0x00, 0xe1, 0x69, 0x2a, 0x79, 0xd0, 0x60, 0x2a, 0x70, 0xd0, 0x00, + 0xe1, 0xce, 0xe1, 0x7a, 0x9b, 0x00, 0x2b, 0xa8, 0xd1, 0x00, 0xe1, 0xbe, 0x2b, 0xa8, 0xd8, 0x06, + 0x2b, 0x8d, 0xd1, 0x00, 0xe1, 0xb9, 0x2b, 0xa4, 0xd0, 0x00, 0xe1, 0xc1, 0xe1, 0x1c, 0x9a, 0x00, + 0x2a, 0xd0, 0xd1, 0x00, 0xe1, 0xb1, 0x2a, 0xd9, 0xd1, 0x00, 0xe1, 0x04, 0x2a, 0xab, 0xd0, 0x00, + 0xe1, 0xb6, 0xe0, 0x39, 0x9b, 0x00, 0x2b, 0xf4, 0xd0, 0x5e, 0x2b, 0xf4, 0xd8, 0x0f, 0x2b, 0xf0, + 0xd0, 0x50, 0x2b, 0xf0, 0xd8, 0x05, 0x2b, 0xe0, 0xd0, 0x1e, 0x2b, 0xe4, 0xd0, 0x00, 0xe1, 0xa7, + 0xe0, 0x3a, 0x9a, 0x00, 0x2a, 0xf2, 0xd0, 0x4a, 0x2a, 0xf2, 0xd8, 0x4b, 0xe0, 0x45, 0x9b, 0x00, + 0x2b, 0xf9, 0xd0, 0x61, 0x2b, 0xf9, 0xd8, 0x05, 0x2b, 0xf5, 0xd0, 0x56, 0x2b, 0xf6, 0xd0, 0x00, + 0xe1, 0x96, 0xe0, 0xaa, 0x9a, 0x00, 0x2a, 0xfb, 0xd1, 0x00, 0xe0, 0x9b, 0x2a, 0xfb, 0xd3, 0x7d, + 0x2a, 0xff, 0xd0, 0x00, 0xe1, 0x8c, 0xe0, 0xcf, 0x4b, 0x81, 0x6a, 0x1a, 0x2a, 0x00, 0xd1, 0x03, + 0x69, 0x1b, 0x2b, 0x00, 0xd1, 0x00, 0xe1, 0x83, 0x1c, 0x28, 0x21, 0x00, 0x9a, 0x01, 0xf0, 0x00, + 0xfa, 0x71, 0x4b, 0x7b, 0x6a, 0x1b, 0xe0, 0x39, 0x4b, 0x79, 0x26, 0x00, 0x68, 0x5a, 0x2a, 0x00, + 0xd0, 0x00, 0xe1, 0x7d, 0x69, 0x1b, 0x2b, 0x00, 0xd0, 0x00, 0xe1, 0x79, 0xe1, 0x70, 0x69, 0x23, + 0x2b, 0x00, 0xd1, 0x00, 0xe1, 0x6c, 0xe1, 0x72, 0x68, 0x63, 0x2b, 0x00, 0xd1, 0x04, 0x4b, 0x70, + 0x69, 0x1b, 0x2b, 0x00, 0xd1, 0x00, 0xe1, 0x63, 0x1c, 0x28, 0x21, 0x00, 0x9a, 0x01, 0xf0, 0x00, + 0xfa, 0x51, 0xe0, 0x1c, 0x68, 0x7b, 0x60, 0xa3, 0xe1, 0x61, 0x68, 0xa3, 0xe0, 0x16, 0x68, 0x7b, + 0x60, 0x23, 0xe1, 0x5c, 0x68, 0x23, 0xe0, 0x11, 0x68, 0x7b, 0x1d, 0xe2, 0x61, 0x23, 0x77, 0xd6, + 0x2b, 0x00, 0xd0, 0x06, 0x1c, 0x20, 0x1c, 0x39, 0x30, 0x18, 0x31, 0x08, 0x22, 0x06, 0xf0, 0x00, + 0xfe, 0xd1, 0x69, 0x7a, 0x4b, 0x5e, 0x61, 0x5a, 0xe1, 0x49, 0x69, 0x23, 0x60, 0x2b, 0x99, 0x01, + 0x1c, 0x28, 0xf0, 0x00, 0xfe, 0xbb, 0xe1, 0x42, 0x68, 0x7b, 0x93, 0x00, 0x68, 0xba, 0x92, 0x01, + 0x68, 0xff, 0xf7, 0xff, 0xfb, 0x8b, 0x1d, 0xe3, 0x77, 0xde, 0x9b, 0x01, 0x61, 0x26, 0x60, 0x2e, + 0x2b, 0x00, 0xd1, 0x00, 0xe1, 0x33, 0x9a, 0x00, 0x2a, 0x00, 0xd1, 0x00, 0xe1, 0x2f, 0x26, 0x00, + 0x2f, 0x00, 0xd1, 0x00, 0xe1, 0x2c, 0x1c, 0x18, 0xf0, 0x00, 0xfe, 0xa4, 0x1c, 0x3a, 0x1c, 0x01, + 0x98, 0x00, 0xf7, 0xff, 0xfb, 0xa7, 0x60, 0x28, 0x28, 0x00, 0xdc, 0x00, 0xe1, 0x20, 0x4b, 0x48, + 0x21, 0x01, 0x1d, 0xda, 0x77, 0xd1, 0x9a, 0x00, 0x61, 0x1a, 0xe1, 0x19, 0x60, 0x2e, 0x34, 0x07, + 0x7f, 0xe3, 0x2b, 0x00, 0xd0, 0x01, 0x23, 0x10, 0xe0, 0x0a, 0x4b, 0x42, 0x68, 0x1b, 0x2b, 0x00, + 0xd0, 0x01, 0x23, 0x08, 0xe0, 0x04, 0x4b, 0x3e, 0x69, 0x1a, 0x2a, 0x00, 0xd0, 0x02, 0x23, 0x04, + 0x60, 0x2b, 0xe1, 0x04, 0x68, 0x5b, 0x26, 0x00, 0x2b, 0x00, 0xd1, 0x00, 0xe1, 0x00, 0x23, 0x01, + 0x60, 0x2b, 0xe0, 0xfd, 0x1c, 0x28, 0x49, 0x38, 0x22, 0x04, 0xf0, 0x00, 0xfe, 0x7b, 0x69, 0x23, + 0x34, 0x07, 0x60, 0x6b, 0x7f, 0xe3, 0x60, 0xab, 0xe0, 0xf1, 0x79, 0x3b, 0x34, 0x05, 0x77, 0xe3, + 0xe0, 0xed, 0x26, 0x00, 0x2d, 0x00, 0xd1, 0x00, 0xe0, 0xea, 0x9b, 0x00, 0x2b, 0x13, 0xd1, 0x0d, + 0x69, 0x23, 0x2b, 0x00, 0xd0, 0x11, 0x4b, 0x2d, 0x68, 0x1b, 0x2b, 0x00, 0xd0, 0x09, 0xf0, 0x00, + 0xf9, 0xf9, 0x1e, 0x43, 0x41, 0x98, 0x00, 0x40, 0x60, 0x28, 0xe7, 0x90, 0x69, 0x23, 0x2b, 0x00, + 0xd0, 0x03, 0x4b, 0x27, 0x68, 0x1b, 0x2b, 0x00, 0xda, 0x07, 0x4b, 0x26, 0x22, 0x01, 0x68, 0x1b, + 0x40, 0x13, 0x42, 0x5a, 0x41, 0x53, 0x00, 0x5b, 0xe7, 0x80, 0x23, 0x02, 0xe7, 0x7e, 0x4b, 0x21, + 0x22, 0x01, 0x68, 0x1b, 0x43, 0x93, 0xe7, 0x79, 0x68, 0x78, 0x1c, 0x29, 0x00, 0x40, 0x08, 0x40, + 0xf7, 0xff, 0xf9, 0xb6, 0xe0, 0xb9, 0x68, 0x63, 0x2b, 0x00, 0xd1, 0x04, 0x4b, 0x14, 0x69, 0x1b, + 0x2b, 0x00, 0xd1, 0x00, 0xe0, 0xac, 0x68, 0x7a, 0x68, 0xbb, 0x07, 0x92, 0x43, 0x1a, 0x0b, 0xd2, + 0x4b, 0x0f, 0x03, 0xd2, 0x60, 0xda, 0xe0, 0xaa, 0x68, 0x63, 0x2b, 0x00, 0xd1, 0x04, 0x4b, 0x0c, + 0x69, 0x1b, 0x2b, 0x00, 0xd1, 0x00, 0xe0, 0x9b, 0x4a, 0x0f, 0x4b, 0x09, 0x26, 0xa0, 0x62, 0x1a, + 0x02, 0x36, 0xe0, 0x9d, 0x4c, 0x0d, 0x21, 0x40, 0x1c, 0x20, 0xf0, 0x00, 0xfe, 0x17, 0x1c, 0x23, + 0x33, 0x40, 0xe0, 0x18, 0x13, 0x77, 0xe2, 0x00, 0x13, 0x77, 0xc0, 0x44, 0x13, 0x77, 0xc0, 0x48, + 0x13, 0x77, 0xeb, 0x14, 0x13, 0x77, 0xec, 0x24, 0x13, 0x77, 0xd8, 0xd8, 0x13, 0x77, 0xec, 0x28, + 0x13, 0x77, 0xe2, 0x84, 0x0d, 0x00, 0x60, 0x04, 0x00, 0x05, 0x31, 0x00, 0x13, 0x77, 0xd8, 0xe0, + 0x34, 0x01, 0x42, 0x9c, 0xd0, 0x74, 0x78, 0x22, 0x2a, 0x00, 0xd0, 0xf9, 0x49, 0x3f, 0x1c, 0x28, + 0x22, 0x40, 0xf0, 0x00, 0xfd, 0xf7, 0x1c, 0x28, 0x21, 0x40, 0xe7, 0x2a, 0x1d, 0xa3, 0x22, 0x01, + 0x77, 0xda, 0x68, 0x23, 0x2b, 0x00, 0xd1, 0x05, 0x1c, 0x38, 0x1c, 0x29, 0x9a, 0x01, 0xf0, 0x00, + 0xfc, 0x49, 0xe0, 0x04, 0x68, 0x79, 0x68, 0xba, 0x1c, 0x28, 0xf7, 0xff, 0xfc, 0xf1, 0x4b, 0x34, + 0x22, 0x00, 0x33, 0x06, 0x1c, 0x06, 0x77, 0xda, 0xe0, 0x5a, 0x4b, 0x31, 0x69, 0x1b, 0x2b, 0x00, + 0xd1, 0x06, 0x1c, 0x38, 0x1c, 0x29, 0x9a, 0x01, 0xf0, 0x00, 0xfc, 0x34, 0x28, 0x00, 0xd1, 0x0c, + 0x4b, 0x2b, 0x20, 0x00, 0x68, 0xd9, 0x68, 0x9a, 0x43, 0x11, 0xd1, 0x06, 0x69, 0x1a, 0x2a, 0x00, + 0xd1, 0x03, 0x69, 0xac, 0x49, 0x27, 0x42, 0x8c, 0xd0, 0x0a, 0x1e, 0x43, 0x41, 0x98, 0x4b, 0x24, + 0x99, 0x01, 0x60, 0x58, 0x1c, 0x28, 0xf7, 0xff, 0xfe, 0x0b, 0x1e, 0x06, 0xd1, 0x38, 0xe0, 0x00, + 0x60, 0x5a, 0xf7, 0xff, 0xfd, 0xe5, 0xe0, 0x32, 0x1d, 0x63, 0x7f, 0xdb, 0x26, 0x00, 0x2b, 0x00, + 0xd1, 0x2e, 0x1d, 0xa2, 0x77, 0xd3, 0x60, 0x23, 0x60, 0x63, 0x60, 0xa3, 0x60, 0xe3, 0x69, 0x23, + 0x2b, 0x00, 0xd1, 0x04, 0x69, 0x62, 0x4b, 0x18, 0x3a, 0x01, 0x60, 0x1a, 0xe0, 0x18, 0xf7, 0xff, + 0xf9, 0x07, 0x1d, 0xe3, 0x7f, 0xdb, 0x2b, 0x00, 0xd1, 0x1a, 0x69, 0x20, 0x1c, 0x21, 0x31, 0x18, + 0x69, 0x62, 0x38, 0x01, 0xf0, 0x00, 0xfa, 0x9c, 0xe0, 0x0f, 0x9b, 0x00, 0x68, 0x79, 0x68, 0xba, + 0x2b, 0xd0, 0xd1, 0x01, 0x02, 0xc9, 0x02, 0x52, 0x1c, 0x28, 0xf7, 0xff, 0xfc, 0x99, 0xe0, 0x04, + 0x1c, 0x38, 0x1c, 0x29, 0x9a, 0x01, 0xf0, 0x00, 0xfb, 0xe5, 0x1c, 0x06, 0xe0, 0x00, 0x26, 0x00, + 0xb0, 0x03, 0x1c, 0x30, 0xbc, 0xf0, 0xbc, 0x02, 0x47, 0x08, 0x46, 0xc0, 0x13, 0x77, 0xd8, 0xe0, + 0x13, 0x77, 0xeb, 0x14, 0x5d, 0x1c, 0x9e, 0xa3, 0x13, 0x77, 0xe2, 0x04, 0xb5, 0x30, 0xb0, 0x83, + 0x4c, 0x0e, 0x25, 0x00, 0x68, 0x23, 0x2b, 0x00, 0xda, 0x13, 0x48, 0x0d, 0x21, 0x01, 0xf0, 0x00, + 0xfd, 0x43, 0x60, 0x20, 0x28, 0x00, 0xdb, 0x0a, 0x22, 0x00, 0x23, 0x00, 0x21, 0x01, 0x95, 0x00, + 0xf0, 0x00, 0xfd, 0x44, 0x23, 0x80, 0x4a, 0x07, 0x00, 0x9b, 0x60, 0x13, 0xe0, 0x01, 0x25, 0x0b, + 0x42, 0x6d, 0xb0, 0x03, 0x1c, 0x28, 0xbc, 0x30, 0xbc, 0x02, 0x47, 0x08, 0x13, 0x77, 0xe2, 0x44, + 0x13, 0x77, 0xe2, 0x20, 0x13, 0x77, 0xe2, 0x40, 0xb5, 0x70, 0xb0, 0x82, 0x1c, 0x03, 0x48, 0x1d, + 0x68, 0x04, 0x20, 0x00, 0x2c, 0x00, 0xdb, 0x31, 0x48, 0x1b, 0x4c, 0x1c, 0x60, 0x03, 0x23, 0x04, + 0x60, 0x63, 0x60, 0xe3, 0x4b, 0x1a, 0x60, 0x41, 0x68, 0x1b, 0x60, 0x20, 0x43, 0x59, 0x30, 0x04, + 0x1c, 0x26, 0x60, 0xa0, 0x61, 0x22, 0x61, 0x61, 0x36, 0x18, 0x1c, 0x25, 0x68, 0x28, 0x68, 0x69, + 0x35, 0x08, 0xf0, 0x00, 0xfd, 0x23, 0x42, 0xb5, 0xd1, 0xf8, 0x4d, 0x10, 0x21, 0x18, 0x1c, 0x28, + 0xf0, 0x00, 0xfd, 0x1c, 0x4b, 0x0b, 0x21, 0x02, 0x68, 0x18, 0x22, 0x02, 0x23, 0x01, 0x95, 0x00, + 0xf0, 0x00, 0xfd, 0x04, 0x1c, 0x03, 0x20, 0x00, 0x2b, 0x00, 0xdb, 0x07, 0x68, 0x20, 0x68, 0x61, + 0x34, 0x08, 0xf0, 0x00, 0xfd, 0x13, 0x42, 0xb4, 0xd1, 0xf8, 0x20, 0x01, 0xb0, 0x02, 0xbc, 0x70, + 0xbc, 0x02, 0x47, 0x08, 0x13, 0x77, 0xe2, 0x44, 0x13, 0x77, 0xeb, 0x60, 0x13, 0x77, 0xeb, 0x40, + 0x13, 0x77, 0xe2, 0x40, 0xb5, 0x70, 0xb0, 0x82, 0x1c, 0x03, 0x48, 0x1d, 0x68, 0x04, 0x20, 0x00, + 0x2c, 0x00, 0xdb, 0x31, 0x48, 0x1b, 0x4c, 0x1c, 0x60, 0x03, 0x23, 0x04, 0x60, 0x63, 0x60, 0xe3, + 0x4b, 0x1a, 0x60, 0x41, 0x68, 0x1b, 0x60, 0x20, 0x43, 0x59, 0x30, 0x04, 0x1c, 0x26, 0x60, 0xa0, + 0x61, 0x22, 0x61, 0x61, 0x36, 0x18, 0x1c, 0x25, 0x68, 0x28, 0x68, 0x69, 0x35, 0x08, 0xf0, 0x00, + 0xfc, 0xdd, 0x42, 0xb5, 0xd1, 0xf8, 0x4d, 0x10, 0x21, 0x18, 0x1c, 0x28, 0xf0, 0x00, 0xfc, 0xd6, + 0x4b, 0x0b, 0x49, 0x0f, 0x68, 0x18, 0x22, 0x02, 0x23, 0x01, 0x95, 0x00, 0xf0, 0x00, 0xfc, 0xbe, + 0x1c, 0x03, 0x20, 0x00, 0x2b, 0x00, 0xdb, 0x07, 0x68, 0x20, 0x68, 0x61, 0x34, 0x08, 0xf0, 0x00, + 0xfc, 0xcd, 0x42, 0xb4, 0xd1, 0xf8, 0x20, 0x01, 0xb0, 0x02, 0xbc, 0x70, 0xbc, 0x02, 0x47, 0x08, + 0x13, 0x77, 0xe2, 0x80, 0x13, 0x77, 0xeb, 0xa0, 0x13, 0x77, 0xeb, 0x80, 0x13, 0x77, 0xeb, 0xc0, + 0x55, 0x4d, 0x53, 0x03, 0xb5, 0x30, 0xb0, 0x83, 0x4c, 0x0e, 0x25, 0x00, 0x68, 0x23, 0x2b, 0x00, + 0xda, 0x13, 0x48, 0x0d, 0x21, 0x01, 0xf0, 0x00, 0xfc, 0x8f, 0x60, 0x20, 0x28, 0x00, 0xdb, 0x0a, + 0x22, 0x00, 0x23, 0x00, 0x49, 0x09, 0x95, 0x00, 0xf0, 0x00, 0xfc, 0x90, 0x23, 0x80, 0x4a, 0x08, + 0x00, 0x9b, 0x60, 0x13, 0xe0, 0x01, 0x25, 0x0b, 0x42, 0x6d, 0xb0, 0x03, 0x1c, 0x28, 0xbc, 0x30, + 0xbc, 0x02, 0x47, 0x08, 0x13, 0x77, 0xe2, 0x80, 0x13, 0x77, 0xe2, 0x60, 0x55, 0x4d, 0x53, 0x01, + 0x13, 0x77, 0xeb, 0xc0, 0xb5, 0xf0, 0x2a, 0x00, 0xd0, 0x29, 0x23, 0x03, 0x1c, 0x1c, 0x40, 0x04, + 0x27, 0x04, 0x1b, 0x3c, 0x06, 0x0e, 0x40, 0x1c, 0x0e, 0x36, 0x1c, 0x05, 0x42, 0x94, 0xd8, 0x03, + 0x23, 0x00, 0x2c, 0x00, 0xd0, 0x08, 0xe0, 0x00, 0x1c, 0x14, 0x1c, 0x23, 0xe0, 0x01, 0x70, 0x2e, + 0x35, 0x01, 0x3b, 0x01, 0xd2, 0xfb, 0x1c, 0x23, 0x04, 0x0c, 0x06, 0x0d, 0x43, 0x25, 0x43, 0x0d, + 0x02, 0x0c, 0x1c, 0x29, 0x43, 0x21, 0x18, 0xc4, 0xe0, 0x01, 0xc4, 0x02, 0x1c, 0x2b, 0x1d, 0x1d, + 0x42, 0x95, 0xd9, 0xfa, 0xe0, 0x01, 0x33, 0x01, 0x54, 0xc6, 0x42, 0x93, 0xd3, 0xfb, 0xbc, 0xf0, + 0xbc, 0x01, 0x47, 0x00, 0xb5, 0x00, 0xb0, 0x83, 0x4b, 0x0a, 0x20, 0x01, 0x68, 0x1b, 0x2b, 0x00, + 0xd0, 0x0c, 0x4b, 0x09, 0x68, 0x1b, 0x2b, 0x00, 0xdb, 0x08, 0x4a, 0x08, 0x1c, 0x18, 0x68, 0x12, + 0x49, 0x07, 0x92, 0x00, 0x23, 0x00, 0x22, 0x00, 0xf0, 0x00, 0xfc, 0x38, 0xb0, 0x03, 0xbc, 0x02, + 0x47, 0x08, 0x46, 0xc0, 0x13, 0x77, 0xec, 0x28, 0x13, 0x77, 0xe2, 0x84, 0x13, 0x77, 0xeb, 0xc4, + 0x57, 0x46, 0x53, 0x04, 0xb5, 0xf0, 0xb0, 0x87, 0x4b, 0x9a, 0x90, 0x03, 0x68, 0x1b, 0x91, 0x02, + 0x92, 0x04, 0x2b, 0x00, 0xd0, 0x04, 0x21, 0xff, 0x9a, 0x02, 0xf7, 0xff, 0xff, 0xa3, 0xe0, 0xee, + 0x4d, 0x95, 0x68, 0x2b, 0x2b, 0x00, 0xda, 0x00, 0xe1, 0x1c, 0x4b, 0x94, 0x68, 0x1b, 0x2b, 0x00, + 0xd1, 0x00, 0xe0, 0xf0, 0x3b, 0x01, 0x2b, 0x01, 0xd9, 0x00, 0xe0, 0xad, 0x4c, 0x90, 0x68, 0x23, + 0x2b, 0x00, 0xd1, 0x06, 0x21, 0x80, 0x20, 0x00, 0x01, 0x89, 0x22, 0x20, 0xf0, 0x00, 0xfc, 0x26, + 0x60, 0x20, 0x20, 0x80, 0x01, 0x00, 0x21, 0x20, 0xf0, 0x00, 0xfc, 0x0c, 0x1e, 0x04, 0xd1, 0x03, + 0x23, 0x01, 0x4a, 0x86, 0x42, 0x5b, 0x60, 0x13, 0x4b, 0x84, 0x25, 0x00, 0x68, 0x1b, 0x2b, 0x00, + 0xdb, 0x21, 0x4d, 0x81, 0x21, 0x00, 0x68, 0x28, 0x22, 0x00, 0xf0, 0x00, 0xfc, 0x13, 0x28, 0x00, + 0xdb, 0x13, 0x22, 0x80, 0x68, 0x28, 0x1c, 0x21, 0x01, 0x12, 0xf0, 0x00, 0xfc, 0x13, 0x28, 0x00, + 0xdb, 0x0b, 0x78, 0x23, 0x2b, 0x43, 0xd1, 0x08, 0x78, 0x63, 0x2b, 0x49, 0xd1, 0x05, 0x78, 0xa3, + 0x2b, 0x53, 0xd1, 0x02, 0x78, 0xe3, 0x2b, 0x4f, 0xd0, 0x03, 0x23, 0x01, 0x4a, 0x73, 0x42, 0x5b, + 0x60, 0x13, 0x25, 0x80, 0x01, 0xad, 0x4a, 0x71, 0x68, 0x13, 0x2b, 0x00, 0xdb, 0x67, 0x4b, 0x70, + 0x68, 0x1b, 0x2b, 0x00, 0xd0, 0x63, 0x79, 0x62, 0x79, 0xa3, 0x02, 0x12, 0x04, 0x1b, 0x18, 0xd2, + 0x79, 0x23, 0x48, 0x6c, 0x18, 0xd2, 0x79, 0xe3, 0x21, 0x00, 0x06, 0x1b, 0x18, 0xd2, 0x4b, 0x6a, + 0x08, 0x92, 0x60, 0x1a, 0x22, 0x80, 0x01, 0x12, 0xf7, 0xff, 0xff, 0x3c, 0x27, 0x08, 0x26, 0x00, + 0x05, 0x7b, 0x2b, 0x00, 0xd1, 0x26, 0x4a, 0x65, 0x23, 0x01, 0x42, 0x96, 0xdc, 0x00, 0x23, 0x00, + 0x06, 0x1b, 0x2b, 0x00, 0xd0, 0x1e, 0x4b, 0x5d, 0x68, 0x1a, 0x4b, 0x5b, 0x2a, 0x02, 0xd1, 0x03, + 0x12, 0xf9, 0x68, 0x18, 0x02, 0x49, 0xe0, 0x02, 0x0a, 0xf9, 0x68, 0x18, 0x02, 0xc9, 0x22, 0x00, + 0xf0, 0x00, 0xfb, 0xc0, 0x28, 0x00, 0xdb, 0x08, 0x4b, 0x53, 0x22, 0x80, 0x68, 0x18, 0x1c, 0x21, + 0x01, 0x12, 0xf0, 0x00, 0xfb, 0xbf, 0x28, 0x00, 0xda, 0x04, 0x23, 0x01, 0x4a, 0x4f, 0x42, 0x5b, + 0x60, 0x13, 0xe0, 0x1d, 0x20, 0x07, 0x40, 0x30, 0xd1, 0x04, 0x4b, 0x4d, 0x10, 0xf2, 0x68, 0x1b, + 0x00, 0x92, 0x50, 0xd5, 0x05, 0x7b, 0x0d, 0x5b, 0x5c, 0xe3, 0x2b, 0x00, 0xd0, 0x0a, 0x4a, 0x49, + 0x21, 0x01, 0x10, 0xf3, 0x40, 0x81, 0x1c, 0x08, 0x5c, 0xd1, 0x43, 0x01, 0x54, 0xd1, 0x4b, 0x46, + 0x68, 0x1b, 0x18, 0xed, 0x23, 0x80, 0x36, 0x01, 0x01, 0xdb, 0x37, 0x01, 0x42, 0x9e, 0xd1, 0xb7, + 0x4b, 0x3e, 0x68, 0x1a, 0x2a, 0x00, 0xdb, 0x02, 0x21, 0x04, 0x43, 0x0a, 0x60, 0x1a, 0x2c, 0x00, + 0xd0, 0x02, 0x1c, 0x20, 0xf0, 0x00, 0xfb, 0x6a, 0x4b, 0x38, 0x4c, 0x39, 0x68, 0x1b, 0x93, 0x05, + 0x2b, 0x03, 0xdd, 0x2e, 0x4b, 0x38, 0x98, 0x04, 0x68, 0x1d, 0x1c, 0x29, 0xf0, 0x00, 0xfb, 0x7e, + 0x68, 0x23, 0x08, 0xc2, 0x24, 0x07, 0x00, 0x91, 0x58, 0xc9, 0x40, 0x20, 0x23, 0x00, 0x4e, 0x31, + 0x24, 0x01, 0xe0, 0x05, 0x5c, 0xb7, 0x41, 0x1f, 0x42, 0x3c, 0xd0, 0x00, 0x19, 0x49, 0x33, 0x01, + 0x42, 0x83, 0xd3, 0xf7, 0x9a, 0x04, 0x3d, 0x01, 0x40, 0x15, 0x9a, 0x05, 0x19, 0x49, 0x4b, 0x26, + 0x07, 0x92, 0xd5, 0x01, 0x68, 0x18, 0xe0, 0x01, 0x68, 0x18, 0x00, 0x89, 0x22, 0x00, 0xf0, 0x00, + 0xfb, 0x59, 0x4b, 0x21, 0x99, 0x03, 0x68, 0x18, 0x9a, 0x02, 0xf0, 0x00, 0xfb, 0x5b, 0x24, 0x00, + 0xe0, 0x32, 0x68, 0x21, 0x29, 0x00, 0xd0, 0x02, 0x20, 0x00, 0xf0, 0x00, 0xfb, 0x57, 0x4b, 0x1c, + 0x22, 0x00, 0x60, 0x1a, 0xe0, 0x26, 0x4c, 0x1e, 0x9b, 0x04, 0x68, 0x20, 0x9a, 0x02, 0x62, 0x03, + 0x9b, 0x03, 0x63, 0xc2, 0x61, 0x03, 0x61, 0x82, 0x21, 0x40, 0xf0, 0x00, 0xfb, 0x27, 0x98, 0x03, + 0x99, 0x02, 0xf0, 0x00, 0xfb, 0x23, 0x4b, 0x17, 0x68, 0x1b, 0x2b, 0x00, 0xd0, 0x04, 0x68, 0x23, + 0x68, 0x28, 0x49, 0x15, 0x93, 0x00, 0xe0, 0x03, 0x68, 0x23, 0x49, 0x14, 0x68, 0x28, 0x93, 0x00, + 0x22, 0x02, 0x23, 0x01, 0xf0, 0x00, 0xfb, 0x02, 0x99, 0x02, 0x1c, 0x04, 0x98, 0x03, 0xf0, 0x00, + 0xfb, 0x15, 0xe0, 0x01, 0x24, 0x01, 0x42, 0x64, 0xb0, 0x07, 0x1c, 0x20, 0xbc, 0xf0, 0xbc, 0x02, + 0x47, 0x08, 0x46, 0xc0, 0x13, 0x77, 0xec, 0x20, 0x13, 0x77, 0xe2, 0x84, 0x13, 0x77, 0xec, 0x24, + 0x13, 0x77, 0xeb, 0x0c, 0x13, 0x77, 0xec, 0x40, 0x13, 0x77, 0xeb, 0x3c, 0x00, 0x00, 0x07, 0xf7, + 0x13, 0x77, 0xeb, 0xc4, 0x13, 0x77, 0xec, 0x28, 0x57, 0x46, 0x53, 0x03, 0x57, 0x46, 0x53, 0x02, + 0xb5, 0xf0, 0xb0, 0x85, 0x1c, 0x05, 0x1c, 0x0e, 0x92, 0x03, 0x28, 0x01, 0xd9, 0x00, 0xe0, 0x9e, + 0x4a, 0x53, 0x4b, 0x54, 0x68, 0x11, 0x42, 0x99, 0xd1, 0x02, 0x23, 0x01, 0x42, 0x5b, 0x60, 0x13, + 0x4b, 0x51, 0x68, 0x1a, 0x2a, 0x00, 0xd1, 0x02, 0x4a, 0x50, 0x60, 0x1a, 0xe0, 0x05, 0x4b, 0x4c, + 0x68, 0x18, 0x28, 0x00, 0xdb, 0x01, 0xf0, 0x00, 0xfa, 0xf5, 0x48, 0x49, 0x23, 0x01, 0x42, 0x5b, + 0x60, 0x03, 0x4a, 0x4b, 0x4b, 0x4b, 0x21, 0x00, 0x60, 0x11, 0x60, 0x19, 0x78, 0x31, 0x29, 0x5f, + 0xd1, 0x38, 0x78, 0x71, 0x29, 0x4e, 0xd1, 0x0c, 0x78, 0xb2, 0x2a, 0x55, 0xd1, 0x32, 0x78, 0xf2, + 0x2a, 0x4c, 0xd1, 0x2f, 0x22, 0x01, 0x60, 0x1a, 0x4b, 0x43, 0x60, 0x1a, 0x4b, 0x3d, 0x60, 0x03, + 0xe0, 0x70, 0x29, 0x44, 0xd1, 0x26, 0x78, 0xb1, 0x29, 0x45, 0xd1, 0x1c, 0x78, 0xf2, 0x2a, 0x56, + 0xd1, 0x20, 0x22, 0x01, 0x60, 0x1a, 0x79, 0x32, 0x2a, 0x57, 0xd1, 0x01, 0x22, 0x02, 0x60, 0x1a, + 0x4c, 0x3a, 0x21, 0x80, 0x1c, 0x20, 0x00, 0x49, 0xf0, 0x00, 0xfa, 0xa8, 0x1c, 0x20, 0x21, 0x00, + 0xf0, 0x00, 0xfa, 0x82, 0x4b, 0x2e, 0x1c, 0x05, 0x60, 0x18, 0x28, 0x00, 0xda, 0x52, 0x4b, 0x31, + 0x22, 0x00, 0x60, 0x1a, 0xe0, 0x4f, 0x29, 0x56, 0xd1, 0x04, 0x78, 0xf3, 0x2b, 0x44, 0xd1, 0x01, + 0x23, 0x01, 0x60, 0x13, 0x4b, 0x2e, 0x00, 0xaa, 0x58, 0xd0, 0x21, 0x01, 0xf0, 0x00, 0xfa, 0x6c, + 0x4c, 0x23, 0x60, 0x20, 0x28, 0x00, 0xda, 0x06, 0x2d, 0x00, 0xd1, 0x04, 0x48, 0x29, 0x21, 0x01, + 0xf0, 0x00, 0xfa, 0x62, 0x60, 0x20, 0x4f, 0x1e, 0x68, 0x3d, 0x2d, 0x00, 0xdb, 0x33, 0x4c, 0x1e, + 0x1c, 0x31, 0x68, 0x20, 0x22, 0x06, 0x30, 0x20, 0xf0, 0x00, 0xfa, 0x7c, 0x68, 0x20, 0xa9, 0x03, + 0x22, 0x04, 0x30, 0x3c, 0xf0, 0x00, 0xfa, 0x76, 0x68, 0x20, 0x26, 0x04, 0x1c, 0x03, 0x33, 0x20, + 0x60, 0x03, 0x23, 0x06, 0x60, 0x43, 0x1c, 0x03, 0x33, 0x3c, 0x60, 0x83, 0x60, 0xc6, 0x21, 0x40, + 0xf0, 0x00, 0xfa, 0x5c, 0x68, 0x23, 0x68, 0x38, 0x49, 0x17, 0x93, 0x00, 0x22, 0x02, 0x23, 0x00, + 0xf0, 0x00, 0xfa, 0x44, 0x1c, 0x05, 0x68, 0x20, 0x21, 0x40, 0x1c, 0x03, 0x33, 0x20, 0x60, 0x03, + 0x33, 0x1c, 0x60, 0x46, 0x60, 0x83, 0x60, 0xc6, 0xf0, 0x00, 0xfa, 0x48, 0xe0, 0x03, 0x25, 0x01, + 0x42, 0x6d, 0xe0, 0x00, 0x25, 0x00, 0xb0, 0x05, 0x1c, 0x28, 0xbc, 0xf0, 0xbc, 0x02, 0x47, 0x08, + 0x13, 0x77, 0xe2, 0x84, 0x00, 0x66, 0x69, 0x99, 0x13, 0x77, 0xeb, 0xc4, 0x13, 0x77, 0xeb, 0xe0, + 0x13, 0x77, 0xec, 0x28, 0x13, 0x77, 0xec, 0x24, 0x13, 0x77, 0xec, 0x20, 0x13, 0x77, 0xe2, 0xa0, + 0x13, 0x77, 0xd9, 0x3c, 0x13, 0x77, 0xd9, 0x20, 0x57, 0x46, 0x53, 0x01, 0xb4, 0x7c, 0xb5, 0x00, + 0xf7, 0xfe, 0xfe, 0xaa, 0xbc, 0x02, 0xbc, 0x7c, 0x47, 0x08, 0xb5, 0x70, 0xb0, 0x88, 0x68, 0x85, + 0x1c, 0x01, 0x4b, 0x01, 0x47, 0x18, 0x00, 0x00, 0x20, 0x10, 0x00, 0xd5, 0x00, 0x00, 0x00, 0x00, + 0xe6, 0x00, 0x08, 0x10, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x07, 0xf0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x03, 0x30, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x03, 0x50, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x03, 0x90, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x03, 0xb0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x03, 0xd0, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x03, 0xf0, 0xe1, 0x2f, 0xff, 0x1e, + 0xe6, 0x00, 0x04, 0x10, 0xe1, 0x2f, 0xff, 0x1e, 0xe6, 0x00, 0x04, 0x50, 0xe1, 0x2f, 0xff, 0x1e, + 0xef, 0x00, 0x00, 0xcc, 0xe1, 0x2f, 0xff, 0x1e, 0x46, 0x72, 0x1c, 0x01, 0x20, 0x04, 0xdf, 0xab, + 0x47, 0x10, 0x46, 0xc0, 0x46, 0xc0, 0x46, 0xc0, 0x46, 0xc0, 0x46, 0xc0, 0x46, 0xc0, 0x46, 0xc0, + 0xe9, 0x2d, 0x40, 0x80, 0xe5, 0x9f, 0x70, 0xac, 0xe5, 0x97, 0x70, 0x00, 0xeb, 0x00, 0x00, 0x1f, + 0xe8, 0xbd, 0x40, 0x80, 0xe1, 0x2f, 0xff, 0x1e, 0xe9, 0x2d, 0x40, 0x80, 0xe5, 0x9f, 0x70, 0x98, + 0xe5, 0x97, 0x70, 0x00, 0xeb, 0x00, 0x00, 0x19, 0xe8, 0xbd, 0x40, 0x80, 0xe1, 0x2f, 0xff, 0x1e, + 0xe9, 0x2d, 0x40, 0x80, 0xe5, 0x9f, 0x70, 0x84, 0xe5, 0x97, 0x70, 0x00, 0xeb, 0x00, 0x00, 0x13, + 0xe8, 0xbd, 0x40, 0x80, 0xe1, 0x2f, 0xff, 0x1e, 0xe9, 0x2d, 0x40, 0x80, 0xe5, 0x9f, 0x70, 0x70, + 0xe5, 0x97, 0x70, 0x00, 0xeb, 0x00, 0x00, 0x0d, 0xe8, 0xbd, 0x40, 0x80, 0xe1, 0x2f, 0xff, 0x1e, + 0xe9, 0x2d, 0x40, 0x80, 0xe5, 0x9f, 0x70, 0x5c, 0xe5, 0x97, 0x70, 0x00, 0xeb, 0x00, 0x00, 0x07, + 0xe8, 0xbd, 0x40, 0x80, 0xe1, 0x2f, 0xff, 0x1e, 0xe9, 0x2d, 0x40, 0x80, 0xe5, 0x9f, 0x70, 0x48, + 0xe5, 0x97, 0x70, 0x00, 0xeb, 0x00, 0x00, 0x01, 0xe8, 0xbd, 0x40, 0x80, 0xe1, 0x2f, 0xff, 0x1e, + 0xe1, 0x2f, 0xff, 0x17, 0xb5, 0xf0, 0x46, 0x5f, 0x46, 0x56, 0x46, 0x4d, 0x46, 0x44, 0xb4, 0xf0, + 0x4b, 0x0b, 0x68, 0x1b, 0x47, 0x18, 0x00, 0x00, 0xe3, 0xc0, 0x01, 0x02, 0xe1, 0x2f, 0xff, 0x1e, + 0xe3, 0x80, 0x01, 0x02, 0xe1, 0x2f, 0xff, 0x1e, 0x13, 0x77, 0xc0, 0x10, 0x13, 0x77, 0xc0, 0x14, + 0x13, 0x77, 0xc0, 0x18, 0x13, 0x77, 0xc0, 0x1c, 0x13, 0x77, 0xc0, 0x20, 0x13, 0x77, 0xc0, 0x24, + 0x13, 0x77, 0xc0, 0x0c, 0xe1, 0xa0, 0x00, 0x00, 0xe1, 0xa0, 0x00, 0x00, 0xe1, 0xa0, 0x00, 0x00, + 0xe2, 0x51, 0x20, 0x01, 0x01, 0x2f, 0xff, 0x1e, 0x3a, 0x00, 0x00, 0x36, 0xe1, 0x50, 0x00, 0x01, + 0x9a, 0x00, 0x00, 0x22, 0xe1, 0x11, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x23, 0xe3, 0x11, 0x02, 0x0e, + 0x01, 0xa0, 0x11, 0x81, 0x03, 0xa0, 0x30, 0x08, 0x13, 0xa0, 0x30, 0x01, 0xe3, 0x51, 0x02, 0x01, + 0x31, 0x51, 0x00, 0x00, 0x31, 0xa0, 0x12, 0x01, 0x31, 0xa0, 0x32, 0x03, 0x3a, 0xff, 0xff, 0xfa, + 0xe3, 0x51, 0x01, 0x02, 0x31, 0x51, 0x00, 0x00, 0x31, 0xa0, 0x10, 0x81, 0x31, 0xa0, 0x30, 0x83, + 0x3a, 0xff, 0xff, 0xfa, 0xe3, 0xa0, 0x20, 0x00, 0xe1, 0x50, 0x00, 0x01, 0x20, 0x40, 0x00, 0x01, + 0x21, 0x82, 0x20, 0x03, 0xe1, 0x50, 0x00, 0xa1, 0x20, 0x40, 0x00, 0xa1, 0x21, 0x82, 0x20, 0xa3, + 0xe1, 0x50, 0x01, 0x21, 0x20, 0x40, 0x01, 0x21, 0x21, 0x82, 0x21, 0x23, 0xe1, 0x50, 0x01, 0xa1, + 0x20, 0x40, 0x01, 0xa1, 0x21, 0x82, 0x21, 0xa3, 0xe3, 0x50, 0x00, 0x00, 0x11, 0xb0, 0x32, 0x23, + 0x11, 0xa0, 0x12, 0x21, 0x1a, 0xff, 0xff, 0xef, 0xe1, 0xa0, 0x00, 0x02, 0xe1, 0x2f, 0xff, 0x1e, + 0x03, 0xa0, 0x00, 0x01, 0x13, 0xa0, 0x00, 0x00, 0xe1, 0x2f, 0xff, 0x1e, 0xe3, 0x51, 0x08, 0x01, + 0x21, 0xa0, 0x18, 0x21, 0x23, 0xa0, 0x20, 0x10, 0x33, 0xa0, 0x20, 0x00, 0xe3, 0x51, 0x0c, 0x01, + 0x21, 0xa0, 0x14, 0x21, 0x22, 0x82, 0x20, 0x08, 0xe3, 0x51, 0x00, 0x10, 0x21, 0xa0, 0x12, 0x21, + 0x22, 0x82, 0x20, 0x04, 0xe3, 0x51, 0x00, 0x04, 0x82, 0x82, 0x20, 0x03, 0x90, 0x82, 0x20, 0xa1, + 0xe1, 0xa0, 0x02, 0x30, 0xe1, 0x2f, 0xff, 0x1e, 0xe1, 0x2f, 0xff, 0x1f, 0xe1, 0xa0, 0x00, 0x00, + 0xe3, 0x50, 0x00, 0x00, 0x13, 0xe0, 0x00, 0x00, 0xea, 0x00, 0x00, 0x6c, 0xe3, 0x51, 0x00, 0x00, + 0x0a, 0xff, 0xff, 0xf8, 0xe9, 0x2d, 0x40, 0x03, 0xeb, 0xff, 0xff, 0xbc, 0xe8, 0xbd, 0x40, 0x06, + 0xe0, 0x03, 0x00, 0x92, 0xe0, 0x41, 0x10, 0x03, 0xe1, 0x2f, 0xff, 0x1e, 0x47, 0x70, 0x46, 0xc0, + 0xb5, 0xf0, 0x1c, 0x05, 0x1c, 0x0e, 0x1c, 0x14, 0x2a, 0x0f, 0xd9, 0x03, 0x1c, 0x0b, 0x43, 0x03, + 0x07, 0x9f, 0xd0, 0x0a, 0x2c, 0x00, 0xd0, 0x05, 0x23, 0x00, 0x5c, 0xf2, 0x54, 0xea, 0x33, 0x01, + 0x42, 0xa3, 0xd1, 0xfa, 0xbc, 0xf0, 0xbc, 0x02, 0x47, 0x08, 0x1c, 0x15, 0x1c, 0x0c, 0x1c, 0x03, + 0x68, 0x26, 0x60, 0x1e, 0x68, 0x66, 0x60, 0x5e, 0x68, 0xa6, 0x60, 0x9e, 0x68, 0xe6, 0x3d, 0x10, + 0x60, 0xde, 0x34, 0x10, 0x33, 0x10, 0x2d, 0x0f, 0xd8, 0xf2, 0x3a, 0x10, 0x09, 0x17, 0x1c, 0x7e, + 0x01, 0x3f, 0x01, 0x36, 0x1b, 0xd7, 0x19, 0x85, 0x1c, 0x3c, 0x19, 0x8e, 0x2f, 0x03, 0xd9, 0xd9, + 0x1c, 0x34, 0x1c, 0x3b, 0x1c, 0x2a, 0xcc, 0x02, 0x3b, 0x04, 0xc2, 0x02, 0x2b, 0x03, 0xd8, 0xfa, + 0x3f, 0x04, 0x08, 0xbc, 0x1c, 0x63, 0x00, 0x9b, 0x00, 0xa4, 0x18, 0xed, 0x18, 0xf6, 0x1b, 0x3c, + 0xe7, 0xc8, 0x46, 0xc0, 0xb5, 0x70, 0x1c, 0x03, 0x07, 0x84, 0xd0, 0x0d, 0x2a, 0x00, 0xd0, 0x40, + 0x06, 0x0d, 0x3a, 0x01, 0x0e, 0x2d, 0x24, 0x03, 0xe0, 0x02, 0x2a, 0x00, 0xd0, 0x39, 0x3a, 0x01, + 0x70, 0x1d, 0x33, 0x01, 0x42, 0x23, 0xd1, 0xf8, 0x2a, 0x03, 0xd9, 0x29, 0x25, 0xff, 0x40, 0x0d, + 0x02, 0x2c, 0x43, 0x25, 0x04, 0x2c, 0x1c, 0x1e, 0x43, 0x25, 0x2a, 0x0f, 0xd9, 0x12, 0x1c, 0x1c, + 0x1c, 0x16, 0x3e, 0x10, 0x60, 0x25, 0x60, 0x65, 0x60, 0xa5, 0x60, 0xe5, 0x34, 0x10, 0x2e, 0x0f, + 0xd8, 0xf7, 0x3a, 0x10, 0x09, 0x16, 0x36, 0x01, 0x01, 0x36, 0x19, 0x9e, 0x23, 0x0f, 0x40, 0x1a, + 0x2a, 0x03, 0xd9, 0x0c, 0x1c, 0x34, 0x1c, 0x13, 0x3b, 0x04, 0xc4, 0x20, 0x2b, 0x03, 0xd8, 0xfb, + 0x3a, 0x04, 0x08, 0x93, 0x33, 0x01, 0x00, 0x9b, 0x18, 0xf6, 0x23, 0x03, 0x40, 0x1a, 0x1c, 0x33, + 0x2a, 0x00, 0xd0, 0x06, 0x06, 0x09, 0x0e, 0x0c, 0x21, 0x00, 0x54, 0x5c, 0x31, 0x01, 0x42, 0x8a, + 0xd1, 0xfb, 0xbc, 0x70, 0xbc, 0x02, 0x47, 0x08, 0x48, 0x45, 0x4c, 0x4f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x75, 0x73, 0x62, 0x31, 0x32, 0x33, 0x00, 0x2f, 0x64, 0x65, 0x76, + 0x2f, 0x73, 0x64, 0x69, 0x6f, 0x2f, 0x73, 0x64, 0x68, 0x63, 0x00, 0x00, 0x13, 0x77, 0xd9, 0x20, + 0x13, 0x77, 0xd9, 0x2c, 0x13, 0x77, 0xd9, 0x20, 0x47, 0x78, 0x46, 0xc0, 0xea, 0xff, 0xff, 0x07, + 0xe5, 0x9f, 0xc0, 0x00, 0xe1, 0x2f, 0xff, 0x1c, 0x13, 0x77, 0xd7, 0xbd, 0x47, 0x78, 0x46, 0xc0, + 0xea, 0xff, 0xff, 0x0c, 0x47, 0x78, 0x46, 0xc0, 0xea, 0xff, 0xff, 0x2c, 0x47, 0x78, 0x46, 0xc0, + 0xea, 0xff, 0xff, 0x18, 0x47, 0x78, 0x46, 0xc0, 0xea, 0xff, 0xff, 0x10, 0x47, 0x78, 0x46, 0xc0, + 0xea, 0xff, 0xfe, 0xf2, 0x47, 0x78, 0x46, 0xc0, 0xea, 0xff, 0xff, 0x36, 0x47, 0x78, 0x46, 0xc0, + 0xea, 0xff, 0xfe, 0xf0, 0x47, 0x78, 0x46, 0xc0, 0xea, 0xff, 0xff, 0x14, 0x47, 0x78, 0x46, 0xc0, + 0xea, 0xff, 0xfe, 0xee, 0x47, 0x78, 0x46, 0xc0, 0xea, 0xff, 0xfe, 0xf8, 0x47, 0x78, 0x46, 0xc0, + 0xea, 0xff, 0xff, 0x3a, 0x47, 0x78, 0x46, 0xc0, 0xea, 0xff, 0xfe, 0xf0, 0x47, 0x78, 0x46, 0xc0, + 0xea, 0xff, 0xfe, 0xe8, 0x47, 0x78, 0x46, 0xc0, 0xea, 0xff, 0xfe, 0xea, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x73, 0x64, 0x69, 0x6f, 0x2f, 0x73, 0x64, 0x68, 0x63, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x75, 0x73, 0x62, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +}; +#define size_odip_frag 9120 diff --git a/source/mload/modules/odip_frag.h b/source/mload/modules/odip_frag.h new file mode 100644 index 0000000..43abdc3 --- /dev/null +++ b/source/mload/modules/odip_frag.h @@ -0,0 +1,16 @@ +#ifndef ODIP_FRAG_H_ +#define ODIP_FRAG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned char odip_frag[9120]; + +#define odip_frag_size sizeof(odip_frag) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/network/FileDownloader.cpp b/source/network/FileDownloader.cpp new file mode 100644 index 0000000..4c679ab --- /dev/null +++ b/source/network/FileDownloader.cpp @@ -0,0 +1,311 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include "language/gettext.h" +#include "networkops.h" +#include "http.h" +#include "FileOperations/fileops.h" +#include "prompts/PromptWindows.h" +#include "prompts/ProgressWindow.h" +#include "utils/ShowError.h" + +/**************************************************************************** + * Download a file from a given url with a Progressbar + ****************************************************************************/ +int DownloadFileToMem(const char *url, u8 **inbuffer, u32 *size) +{ + if(strncasecmp(url, "http://", strlen("http://")) != 0) + { + ShowError(tr("Not a valid URL")); + return -1; + } + char *path = strchr(url + strlen("http://"), '/'); + + if(!path) + { + ShowError(tr("Not a valid URL path")); + return -2; + } + + int domainlength = path - url - strlen("http://"); + + if(domainlength == 0) + { + ShowError(tr("Not a valid domain")); + return -3; + } + + char domain[domainlength + 1]; + strncpy(domain, url + strlen("http://"), domainlength); + domain[domainlength] = '\0'; + + int connection = GetConnection(domain); + + if(connection < 0) + { + ShowError(tr("Could not connect to the server.")); + return -4; + } + + char header[1024]; + char * ptr = header; + ptr += sprintf(ptr, "GET %s HTTP/1.1\r\n", path); + ptr += sprintf(ptr, "Host: %s\r\n", domain); + ptr += sprintf(ptr, "Referer: %s\r\n", domain); + ptr += sprintf(ptr, "User-Agent: USB Loader GX\r\n"); + ptr += sprintf(ptr, "Pragma: no-cache\r\n"); + ptr += sprintf(ptr, "Cache-Control: no-cache\r\n"); + ptr += sprintf(ptr, "Connection: close\r\n\r\n"); + + char filename[255]; + memset(filename, 0, sizeof(filename)); + + int filesize = network_request(connection, header, filename); + + if(filesize <= 0) + { + net_close(connection); + ShowError(tr("Filesize is 0 Byte.")); + return -5; + } + + int blocksize = 4*1024; + + u8 * buffer = (u8 *) malloc(filesize); + if(!buffer) + { + net_close(connection); + ShowError(tr("Not enough memory.")); + return -6; + } + + ProgressCancelEnable(true); + StartProgress(tr("Downloading file..."), 0, filename, true, true); + + int done = 0; + + while(done < filesize) + { + if(ProgressCanceled()) + { + done = PROGRESS_CANCELED; + break; + } + + ShowProgress(done, filesize); + + if(blocksize > filesize - done) + blocksize = filesize - done; + + + s32 read = network_read(connection, buffer+done, blocksize); + + if(read < 0) + { + done = -8; + ShowError(tr("Transfer failed")); + break; + } + else if(!read) + break; + + done += read; + } + + ProgressStop(); + ProgressCancelEnable(false); + net_close(connection); + + if(done < 0) + { + free(buffer); + return done; + } + + *inbuffer = buffer; + *size = filesize; + + return done; +} + +/**************************************************************************** + * Download a file from a given url to a given path with a Progressbar + ****************************************************************************/ +int DownloadFileToPath(const char *orig_url, const char *dest, bool UseFilename) +{ + if(!orig_url || !dest) + { + ShowError(tr("No URL or Path specified.")); + return -2; + } + + bool addhttp = false; + + if(strncasecmp(orig_url, "http://", strlen("http://")) != 0) + { + addhttp = true; + } + + char url[strlen(orig_url) + (addhttp ? strlen("http://") : 0) + 1]; + + if(addhttp) + snprintf(url, sizeof(url), "http://%s", orig_url); + else + strcpy(url, orig_url); + + char *path = strchr(url + strlen("http://"), '/'); + + if(!path) + { + ShowError(tr("Not a valid URL path")); + return -2; + } + + int domainlength = path - url - strlen("http://"); + + if(domainlength == 0) + { + ShowError(tr("Not a valid domain")); + return -3; + } + + char domain[domainlength + 1]; + strncpy(domain, url + strlen("http://"), domainlength); + domain[domainlength] = '\0'; + + int connection = GetConnection(domain); + + if(connection < 0) + { + ShowError(tr("Could not connect to the server.")); + return -4; + } + + char header[1024]; + char * ptr = header; + ptr += sprintf(ptr, "GET %s HTTP/1.1\r\n", path); + ptr += sprintf(ptr, "Host: %s\r\n", domain); + ptr += sprintf(ptr, "Referer: %s\r\n", domain); + ptr += sprintf(ptr, "User-Agent: WiiXplorer\r\n"); + ptr += sprintf(ptr, "Pragma: no-cache\r\n"); + ptr += sprintf(ptr, "Cache-Control: no-cache\r\n"); + ptr += sprintf(ptr, "Connection: close\r\n\r\n"); + + char filename[255]; + memset(filename, 0, sizeof(filename)); + + int filesize = network_request(connection, header, filename); + + if(filesize <= 0) + { + net_close(connection); + ShowError(tr("Filesize is %i Byte."), filesize); + return -5; + } + + int blocksize = 4*1024; + + u8 *buffer = (u8 *) malloc(blocksize); + if(!buffer) + { + net_close(connection); + ShowError(tr("Not enough memory.")); + return -6; + } + + if(UseFilename) + { + if(dest[strlen(dest)-1] != '/') + strcat((char *) dest, "/"); + + CreateSubfolder(dest); + + strcat((char *) dest, filename); + } + + if(!UseFilename && strcmp(filename, "") == 0) + { + const char * ptr = strrchr(dest, '/'); + if(ptr) ptr++; + else ptr = dest; + + snprintf(filename, sizeof(filename), "%s", ptr); + } + + FILE *file = fopen(dest, "wb"); + if(!file) + { + net_close(connection); + free(buffer); + ShowError(tr("Cannot write to destination.")); + return -7; + } + + ProgressCancelEnable(true); + StartProgress(tr("Downloading file..."), 0, filename, true, true); + + int done = 0; + + while(done < filesize) + { + if(ProgressCanceled()) + { + done = PROGRESS_CANCELED; + break; + } + + ShowProgress(done, filesize); + + if(blocksize > filesize - done) + blocksize = filesize - done; + + s32 read = network_read(connection, buffer, blocksize); + + if(read < 0) + { + done = -8; + ShowError(tr("Transfer failed")); + break; + } + else if(!read) + break; + + fwrite(buffer, 1, read, file); + + done += read; + } + + free(buffer); + ProgressStop(); + net_close(connection); + fclose(file); + ProgressStop(); + ProgressCancelEnable(false); + + return done; +} diff --git a/source/network/FileDownloader.h b/source/network/FileDownloader.h new file mode 100644 index 0000000..3fd2f24 --- /dev/null +++ b/source/network/FileDownloader.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef FILE_DOWNLOADER_H_ +#define FILE_DOWNLOADER_H_ + +int DownloadFileToMem(const char *url, u8 **inbuffer, u32 *size); +int DownloadFileToPath(const char *url, const char *dest, bool UseFilename = true); + +#endif diff --git a/source/network/HTML_Stream.cpp b/source/network/HTML_Stream.cpp new file mode 100644 index 0000000..acc14cc --- /dev/null +++ b/source/network/HTML_Stream.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * HTML_Stream Class + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include + +#include "HTML_Stream.h" +#include "networkops.h" +#include "http.h" + +#define htmlstringcompare(text, cmp, pos) strncasecmp((const char*) &text[pos], (const char*) cmp, strlen((const char*) cmp)) + +HTML_Stream::HTML_Stream() +{ + HTML_File = NULL; + position = 0; + filesize = 0; +} + +HTML_Stream::HTML_Stream(const char * url) +{ + HTML_File = NULL; + position = 0; + filesize = 0; + + LoadLink(url); +} + +HTML_Stream::~HTML_Stream() +{ + if (HTML_File) free(HTML_File); +} + +bool HTML_Stream::LoadLink(const char * url) +{ + if (!IsNetworkInit()) return false; + + struct block file = downloadfile(url); + + if (!file.data || !file.size) return false; + + if (HTML_File) free(HTML_File); + + HTML_File = (char *) file.data; + filesize = file.size; + position = 0; + + return true; +} + +const char * HTML_Stream::FindStringStart(const char * string) +{ + if (!HTML_File) return NULL; + + while ((u32) position < filesize) + { + if (htmlstringcompare( HTML_File, string, position ) == 0) break; + + position++; + } + + return &HTML_File[position]; +} + +const char * HTML_Stream::FindStringEnd(const char * string) +{ + if (!HTML_File) return NULL; + + while ((u32) position < filesize) + { + if (htmlstringcompare( HTML_File, string, position ) == 0) break; + + position++; + } + + if ((u32) position >= filesize) + { + return NULL; + } + + position += strlen(string); + + return &HTML_File[position]; +} + +char * HTML_Stream::CopyString(const char * stopat) +{ + if (!stopat || !HTML_File) return NULL; + + u32 blocksize = 1024; + u32 counter = 0; + + char * outtext = (char*) malloc(blocksize); + if (!outtext) return NULL; + + memset(outtext, 0, blocksize); + + while ((htmlstringcompare( HTML_File, stopat, position ) != 0) && (position + strlen(stopat) < filesize)) + { + if (counter > blocksize) + { + blocksize += 1024; + char * tmpblock = (char*) realloc(outtext, blocksize); + if (!tmpblock) + { + free(outtext); + outtext = NULL; + free(tmpblock); + return NULL; + } + + outtext = tmpblock; + } + + outtext[counter] = HTML_File[position]; + position++; + counter++; + } + + outtext[counter] = '\0'; + outtext = (char*) realloc(outtext, counter + 1); + + return outtext; +} + +int HTML_Stream::Seek(u32 pos, int origin) +{ + if (!HTML_File) return -1; + + switch (origin) + { + case SEEK_SET: + position = pos; + break; + case SEEK_CUR: + position += pos; + break; + case SEEK_END: + position = filesize + pos; + break; + } + + return 0; +} + +void HTML_Stream::Rewind() +{ + if (!HTML_File) return; + + position = 0; +} + +int HTML_Stream::GetPosition() +{ + return position; +} diff --git a/source/network/HTML_Stream.h b/source/network/HTML_Stream.h new file mode 100644 index 0000000..c68b251 --- /dev/null +++ b/source/network/HTML_Stream.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * HTML_Stream Class + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef ___HTML_STREAM_H_ +#define ___HTML_STREAM_H_ + +#include + +class HTML_Stream +{ + public: + //!Constructor + HTML_Stream(); + //!\param url from where to the HTML file + HTML_Stream(const char * url); + //!Destructor + ~HTML_Stream(); + //!Load url + bool LoadLink(const char * url); + //! Find start of a string from current position in the html + //!\param string to find + const char * FindStringStart(const char * string); + //! Find end of a string from current position in the html + //!\param string to find + const char * FindStringEnd(const char * string); + //!CopyString from current position in html till stopat string + //!\param stopat string before which to stop copying (e.g. ) + //!\param outtext variable is allocated with malloc and must be set 0 before + char * CopyString(const char * stopat); + //!Seek position in file + //!\param position seeked + //!\param seek origin (SEEK_SET, SEEK_CUR, SEEK_END) + int Seek(u32 pos, int origin); + //!Rewind to the start of the html + void Rewind(); + //!Get current position + int GetPosition(); + protected: + int position; + u32 filesize; + char * HTML_File; +}; + +#endif diff --git a/source/network/ImageDownloader.cpp b/source/network/ImageDownloader.cpp new file mode 100644 index 0000000..1478877 --- /dev/null +++ b/source/network/ImageDownloader.cpp @@ -0,0 +1,440 @@ +/**************************************************************************** + * Copyright (C) 2011 Dimok + * Copyright (C) 2012 Cyan + * + * 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 "ImageDownloader.h" +#include "network/networkops.h" +#include "prompts/PromptWindows.h" +#include "prompts/ProgressWindow.h" +#include "prompts/CheckboxPrompt.hpp" +#include "FileOperations/fileops.h" +#include "settings/CSettings.h" +#include "settings/GameTitles.h" +#include "language/gettext.h" +#include "usbloader/GetMissingGameFiles.hpp" +#include "utils/StringTools.h" +#include "gecko.h" + +#define VALID_IMAGE(x) (!(x.size == 36864 || x.size <= 1024 || x.size == 7386 || x.size <= 1174 || x.size == 4446 || x.data == NULL)) + +static const char *serverURL3D = "http://art.gametdb.com/wii/cover3D/"; +static const char *serverURL2D = "http://art.gametdb.com/wii/cover/"; +static const char *serverURLFullHQ = "http://art.gametdb.com/wii/coverfullHQ/"; +static const char *serverURLFull = "http://art.gametdb.com/wii/coverfull/"; +static const char *serverURLOrigDiscs = "http://art.gametdb.com/wii/disc/"; +static const char *serverURLCustomDiscs = "http://art.gametdb.com/wii/disccustom/"; +static const char *serverURLCustomBannersGC = Settings.CustomBannersURL; + +void ImageDownloader::DownloadImages() +{ + bool ValidBannerURL = false; + if(strncasecmp(serverURLCustomBannersGC, "http://", strlen("http://")) == 0) + { + char *path = strchr(serverURLCustomBannersGC + strlen("http://"), '/'); + if(path) + ValidBannerURL = true; + } + bool showBanner = (ValidBannerURL && Settings.LoaderMode & MODE_GCGAMES); + + int choice = CheckboxWindow(tr( "Cover Download" ), 0, tr( "3D Covers" ), tr( "Flat Covers" ), tr("Full Covers"), tr( "Discarts" ), showBanner ? tr( "Custom Banners" ) : 0, 0, showBanner ? 0x1F : 0xF); // ask for download choice + if (choice == 0 || choice == CheckedNone) + return; + + ImageDownloader Downloader; + Downloader.SetChoices(choice); + Downloader.Start(); +} + +void ImageDownloader::Start() +{ + gprintf("CoverDownload start - choices: %04X\n", choices); + + MissingImagesCount = 0; + FindMissingImages(); + + if(MissingImagesCount == 0) + { + WindowPrompt(tr( "No file missing!" ), 0, tr("OK")); + return; + } + + u32 TotalDownloadCount = MissingImagesCount; + + if (WindowPrompt(tr("Found missing images."), fmt(tr("%i missing files"), TotalDownloadCount), tr( "Yes" ), tr( "No" )) == 0) + return; + + if (!IsNetworkInit() && !NetworkInitPrompt()) + { + gprintf("No network\n"); + return; + } + + ProgressCancelEnable(true); + + DownloadProcess(TotalDownloadCount); + + ProgressCancelEnable(false); + + ProgressStop(); + + if(MissingImagesCount == 0) + WindowPrompt(tr("Download finished"), tr("All images downloaded successfully."), tr( "OK" )); + else + { + int res = WindowPrompt(tr( "Download finished" ), fmt(tr("%i files not found on the server!"), MissingImagesCount), tr("Save List"), tr( "OK" )); + if(res) + CreateCSVLog(); + } +} + +void ImageDownloader::FindMissingImages() +{ + if(choices & CheckedBox1) + FindMissing(Settings.covers_path, serverURL3D, NULL, tr("Downloading 3D Covers"), NULL, ".png"); + + if(choices & CheckedBox2) + FindMissing(Settings.covers2d_path, serverURL2D, NULL, tr("Downloading Flat Covers"), NULL, ".png"); + + if(choices & CheckedBox3) + { + const char * downloadURL = (Settings.coversfull == COVERSFULL_HQ || Settings.coversfull == COVERSFULL_HQ_LQ ) ? serverURLFullHQ : serverURLFull; + const char * progressTitle = (Settings.coversfull == COVERSFULL_HQ || Settings.coversfull == COVERSFULL_HQ_LQ ) ? tr("Downloading Full HQ Covers") : tr("Downloading Full LQ Covers"); + const char * backupURL = (Settings.coversfull == COVERSFULL_HQ_LQ || Settings.coversfull == COVERSFULL_LQ_HQ) ? ((Settings.coversfull == COVERSFULL_HQ_LQ) ? serverURLFull : serverURLFullHQ) : NULL; + const char * backupProgressTitle = (Settings.coversfull == COVERSFULL_HQ_LQ || Settings.coversfull == COVERSFULL_LQ_HQ) ? ((Settings.coversfull == COVERSFULL_HQ_LQ) ? tr("Downloading Full LQ Covers") : tr("Downloading Full HQ Covers")) : NULL; + FindMissing(Settings.coversFull_path, downloadURL, backupURL, progressTitle, backupProgressTitle, ".png"); + } + + if(choices & CheckedBox4) + { + const char * downloadURL = (Settings.discart == DISCARTS_ORIGINALS || Settings.discart == DISCARTS_ORIGINALS_CUSTOMS ) ? serverURLOrigDiscs : serverURLCustomDiscs; + const char * progressTitle = (Settings.discart == DISCARTS_ORIGINALS || Settings.discart == DISCARTS_ORIGINALS_CUSTOMS ) ? tr("Downloading original Discarts") : tr("Downloading custom Discarts"); + const char * backupURL = (Settings.discart == DISCARTS_ORIGINALS_CUSTOMS || Settings.discart == DISCARTS_CUSTOMS_ORIGINALS) ? ((Settings.discart == DISCARTS_ORIGINALS_CUSTOMS) ? serverURLCustomDiscs : serverURLOrigDiscs) : NULL; + const char * backupProgressTitle = (Settings.discart == DISCARTS_ORIGINALS_CUSTOMS || Settings.discart == DISCARTS_CUSTOMS_ORIGINALS) ? ((Settings.discart == DISCARTS_ORIGINALS_CUSTOMS) ? tr("Downloading custom Discarts") : tr("Downloading original Discarts")) : NULL; + FindMissing(Settings.disc_path, downloadURL, backupURL, progressTitle, backupProgressTitle, ".png"); + } + + if(choices & CheckedBox5) + { + FindMissing(Settings.BNRCachePath, serverURLCustomBannersGC, NULL, tr("Downloading Custom Banners"), NULL, ".bnr"); + } +} + +void ImageDownloader::FindMissing(const char *writepath, const char *downloadURL, const char *backupURL, const char *progressTitle, const char *backupProgressTitle, const char *fileExt) +{ + if (!CreateSubfolder(writepath)) + { + WindowPrompt(tr( "Error !" ), fmt("%s %s", tr("Can't create directory"), writepath), tr( "OK" )); + return; + } + + std::vector MissingFilesList; + + if((Settings.LoaderMode & MODE_GCGAMES) && strcmp(fileExt, ".bnr") == 0) + { + short LoaderModeBackup = Settings.LoaderMode; + Settings.LoaderMode = MODE_GCGAMES; // Limit banner download for GameCube Only. + GetMissingGameFiles(writepath, fileExt, MissingFilesList); + Settings.LoaderMode = LoaderModeBackup; + } + else + { + GetMissingGameFiles(writepath, fileExt, MissingFilesList); + } + int size = MissingImages.size(); + MissingImages.resize(size+MissingFilesList.size()); + + for(u32 i = 0, n = size; i < MissingFilesList.size(); ++i, ++n) + { + MissingImages[n].gameID = MissingFilesList[i]; + MissingImages[n].downloadURL = downloadURL; + MissingImages[n].backupURL = backupURL; + MissingImages[n].writepath = writepath; + MissingImages[n].progressTitle = progressTitle; + MissingImages[n].backupProgressTitle = backupProgressTitle; + MissingImages[n].fileExt = fileExt; + } + + MissingImagesCount += MissingFilesList.size(); +} + +int ImageDownloader::DownloadProcess(int TotalDownloadCount) +{ + char progressMsg[255]; + + char *path = strchr(serverURLCustomBannersGC + strlen("http://"), '/'); + int domainlength = path - serverURLCustomBannersGC; + char domain[domainlength + 1]; + strncpy(domain, serverURLCustomBannersGC, domainlength); + domain[domainlength] = '\0'; + + for(u32 i = 0, pos = 0; i < MissingImages.size(); ++i, ++pos) + { + if(ProgressCanceled()) + break; + + if(strcmp(MissingImages[i].fileExt, ".bnr") == 0) + snprintf(progressMsg, sizeof(progressMsg), "%s : %s.bnr", domain, MissingImages[i].gameID.c_str()); + else + snprintf(progressMsg, sizeof(progressMsg), "http://gametdb.com : %s.png", MissingImages[i].gameID.c_str()); + + ShowProgress(MissingImages[i].progressTitle, fmt("%i %s", TotalDownloadCount - pos, tr( "files left" )), progressMsg, pos, TotalDownloadCount); + + if(MissingImages[i].gameID.size() < 3) + continue; + + struct block file = DownloadImage(MissingImages[i].downloadURL, MissingImages[i].gameID.c_str(), MissingImages[i].fileExt); + if(!file.data) + { + if(MissingImages[i].backupURL) + { + gprintf("Trying backup URL.\n"); + MissingImages[i].downloadURL = MissingImages[i].backupURL; + MissingImages[i].backupURL = NULL; + MissingImages[i].progressTitle = MissingImages[i].backupProgressTitle; + --i; + --pos; + } + continue; + } + + gprintf(" - OK\n"); + char imgPath[200]; + snprintf(imgPath, sizeof(imgPath), "%s/%s%s", MissingImages[i].writepath, MissingImages[i].gameID.c_str(), MissingImages[i].fileExt); + + FILE *pfile = fopen(imgPath, "wb"); + if (pfile != NULL) + { + fwrite(file.data, 1, file.size, pfile); + fclose(pfile); + MissingImagesCount--; + } + free(file.data); + + //! Remove the image from the vector since it's done + MissingImages.erase(MissingImages.begin()+i); + --i; + } + + return MissingImages.size(); +} + +struct block ImageDownloader::DownloadImage(const char * url, const char * gameID, const char * fileExt) +{ + char CheckedRegion[10]; + char downloadURL[512]; + bool PAL = false; + + if(strcmp(fileExt, ".bnr") == 0) + { + snprintf(downloadURL, sizeof(downloadURL), "%s%s.bnr", url, gameID); + gprintf("%s", downloadURL); + struct block file = downloadfile(downloadURL); + if(file.size > 132 && IsValidBanner(file.data)) // 132 = IMET magic location in the banner with u8 header + return file; + + free(file.data); + + snprintf(downloadURL, sizeof(downloadURL), "%s%.3s.bnr", url, gameID); + gprintf(" - Not found. trying ID3:\n%s", downloadURL); + file = downloadfile(downloadURL); + if(file.size > 132 && IsValidBanner(file.data)) + return file; + + gprintf(" - Not found.\n"); + free(file.data); + memset(&file, 0, sizeof(struct block)); + return file; + } + + //Creates URL depending from which Country the game is + switch (gameID[3]) + { + case 'J': + sprintf(downloadURL, "%sJA/%s.png", url, gameID); + sprintf(CheckedRegion, "JA"); + break; + case 'W': + sprintf(downloadURL, "%sZH/%s.png", url, gameID); + sprintf(CheckedRegion, "ZH"); + break; + case 'K': + sprintf(downloadURL, "%sKO/%s.png", url, gameID); + sprintf(CheckedRegion, "KO"); + break; + case 'P': + case 'D': + case 'F': + case 'I': + case 'S': + case 'H': + case 'U': + case 'X': + case 'Y': + case 'Z': + sprintf(downloadURL, "%s%s/%s.png", url, Settings.db_language, gameID); + sprintf(CheckedRegion, "%s", Settings.db_language); + PAL = true; + break; + case 'E': + sprintf(downloadURL, "%sUS/%s.png", url, gameID); + sprintf(CheckedRegion, "US"); + break; + default: + strcpy(downloadURL, ""); + strcpy(CheckedRegion, ""); + break; + } + + gprintf("%s", downloadURL); + struct block file = downloadfile(downloadURL); + if(VALID_IMAGE(file)) + return file; + + free(file.data); + file.data = NULL; + + if(PAL && strcmp(CheckedRegion, "EN") != 0) + { + snprintf(downloadURL, sizeof(downloadURL), "%sEN/%s.png", url, gameID); + gprintf(" - Not found.\n%s", downloadURL); + file = downloadfile(downloadURL); + if(VALID_IMAGE(file)) + return file; + } + else if(strcmp(CheckedRegion, "") == 0) + { + const char * lang = Settings.db_language; + + if(strcmp(lang, "EN") == 0 && CONF_GetRegion() == CONF_REGION_US) + lang = "US"; + + snprintf(downloadURL, sizeof(downloadURL), "%s%s/%s.png", url, lang, gameID); + gprintf(" - Not found.\n%s", downloadURL); + file = downloadfile(downloadURL); + if(VALID_IMAGE(file)) + return file; + + free(file.data); + + snprintf(downloadURL, sizeof(downloadURL), "%sOTHER/%s.png", url, gameID); + gprintf(" - Not found.\n%s", downloadURL); + file = downloadfile(downloadURL); + if(VALID_IMAGE(file)) + return file; + + if(gameID[3] == 'R') // no english cover found, try russian + { + lang = "RU"; + free(file.data); + + snprintf(downloadURL, sizeof(downloadURL), "%s%s/%s.png", url, lang, gameID); + gprintf(" - Not found.\n%s", downloadURL); + file = downloadfile(downloadURL); + if(VALID_IMAGE(file)) + return file; + } + + if(gameID[3] == 'V') // no English cover found, try Finnish and Swedish + { + lang = "FI"; + free(file.data); + + snprintf(downloadURL, sizeof(downloadURL), "%s%s/%s.png", url, lang, gameID); + gprintf(" - Not found.\n%s", downloadURL); + file = downloadfile(downloadURL); + if(VALID_IMAGE(file)) + return file; + + lang = "SE"; + free(file.data); + + snprintf(downloadURL, sizeof(downloadURL), "%s%s/%s.png", url, lang, gameID); + gprintf(" - Not found.\n%s", downloadURL); + file = downloadfile(downloadURL); + if(VALID_IMAGE(file)) + return file; + } + } + + gprintf(" - Not found.\n"); + free(file.data); + + memset(&file, 0, sizeof(struct block)); + + return file; +} + +void ImageDownloader::CreateCSVLog() +{ + char path[200]; + snprintf(path, sizeof(path), "%s/MissingImages.csv", Settings.update_path); + + FILE *f = fopen(path, "wb"); + if(!f) return; + + const char *ImageType = "3D Cover"; + + fprintf(f, "\"ID\",\"Name\",\"ImageType\"\n"); + + for (u32 i = 0; i < MissingImages.size(); ++i) + { + if(MissingImages[i].downloadURL == serverURL3D) + { + ImageType = "3D Cover"; + } + else if(MissingImages[i].downloadURL == serverURL2D) + { + ImageType = "2D Cover"; + } + else if(MissingImages[i].downloadURL == serverURLFullHQ) + { + ImageType = "Full HQ Cover"; + } + else if(MissingImages[i].downloadURL == serverURLFull) + { + ImageType = "Full LQ Cover"; + } + else if(MissingImages[i].downloadURL == serverURLOrigDiscs) + { + ImageType = "Original Discart"; + } + else if(MissingImages[i].downloadURL == serverURLCustomDiscs) + { + ImageType = "Custom Discart"; + } + else if(MissingImages[i].downloadURL == serverURLCustomBannersGC) + { + ImageType = "Custom Banner"; + } + + fprintf(f, "\"%s\",\"%s\",\"%s\"\n", MissingImages[i].gameID.c_str(), GameTitles.GetTitle(MissingImages[i].gameID.c_str()), ImageType); + gprintf("\"%s\",\"%s\",\"%s\"\n", MissingImages[i].gameID.c_str(), GameTitles.GetTitle(MissingImages[i].gameID.c_str()), ImageType); + } + + fclose(f); +} + +bool ImageDownloader::IsValidBanner(unsigned char *banner) +{ + if(!((*(u32*)(banner+64)) == 'IMET')) + { + if(!((*(u32*)(banner+128)) == 'IMET')) // with U8Archive header + return false; + } + return true; +} diff --git a/source/network/ImageDownloader.h b/source/network/ImageDownloader.h new file mode 100644 index 0000000..7289dd9 --- /dev/null +++ b/source/network/ImageDownloader.h @@ -0,0 +1,37 @@ +#ifndef IMAGE_DOWNLOADER_H_ +#define IMAGE_DOWNLOADER_H_ + +#include +#include +#include "network/http.h" + +class ImageDownloader +{ + public: + static void DownloadImages(); + private: + void Start(); + void SetChoices(int c) { choices = c; } + void FindMissingImages(); + void FindMissing(const char *writepath, const char *downloadURL, const char *backupURL, const char *progressTitle, const char *backupProgressTitle, const char *fileExt); + int DownloadProcess(int TotalDownloadCount); + struct block DownloadImage(const char * url, const char * gameID, const char *fileExt); + void CreateCSVLog(); + bool IsValidBanner(unsigned char *banner); + + struct ImageLink + { + std::string gameID; + const char *downloadURL; + const char *backupURL; + const char *writepath; + const char *progressTitle; + const char *backupProgressTitle; + const char *fileExt; + }; + int choices; + u32 MissingImagesCount; + std::vector MissingImages; +}; + +#endif diff --git a/source/network/URL_List.cpp b/source/network/URL_List.cpp new file mode 100644 index 0000000..4cbb6a7 --- /dev/null +++ b/source/network/URL_List.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** + * URL List Class + * for USB Loader GX + * by dimok + ***************************************************************************/ +#include +#include +#include +#include + +#include "URL_List.h" + +URL_List::URL_List(const char * url) +{ + Links = NULL; + urlcount = 0; + + if (!IsNetworkInit()) + { + urlcount = -1; + return; + } + + struct block file = downloadfile(url); + + if (!file.data || !file.size) + { + urlcount = -2; + return; + } + + u32 cnt = 0; + char temp[1024]; + + Links = (Link_Info *) malloc(sizeof(Link_Info)); + if (!Links) + { + free(file.data); + urlcount = -3; + return; + } + + memset(&Links[urlcount], 0, sizeof(Link_Info)); + + while (cnt < file.size) + { + + if (file.data[cnt] == '"' && file.data[cnt - 1] == '=' && file.data[cnt - 2] == 'f' && file.data[cnt - 3] + == 'e' && file.data[cnt - 4] == 'r' && file.data[cnt - 5] == 'h') + { + + u32 cnt2 = 0; + cnt++; + while (file.data[cnt] != '"' && cnt2 < 1024) + { + temp[cnt2] = file.data[cnt]; + cnt2++; + cnt++; + } + temp[cnt2] = '\0'; + + Links = (Link_Info *) realloc(Links, (urlcount + 1) * sizeof(Link_Info)); + + if (!Links) + { + for (int i = 0; i == urlcount; i++) + { + delete Links[i].URL; + Links[i].URL = NULL; + } + free(Links); + Links = NULL; + free(file.data); + urlcount = -4; + break; + } + + memset(&(Links[urlcount]), 0, sizeof(Link_Info)); + + Links[urlcount].URL = new char[cnt2 + 1]; + + if (!Links[urlcount].URL) + { + for (int i = 0; i == urlcount; i++) + { + delete Links[i].URL; + Links[i].URL = NULL; + } + free(Links); + Links = NULL; + free(file.data); + urlcount = -5; + break; + } + + snprintf(Links[urlcount].URL, cnt2 + 1, "%s", temp); + + if (strncmp(Links[urlcount].URL, "http://", strlen("http://")) != 0) + Links[urlcount].direct = false; + else Links[urlcount].direct = true; + + urlcount++; + } + cnt++; + } + + free(file.data); +} + +URL_List::~URL_List() +{ + for (int i = 0; i == urlcount; i++) + { + delete Links[i].URL; + Links[i].URL = NULL; + } + + if (Links != NULL) + { + free(Links); + Links = NULL; + } +} + +char * URL_List::GetURL(int ind) +{ + if (ind > urlcount || ind < 0 || !Links || urlcount <= 0) + return NULL; + else return Links[ind].URL; +} + +int URL_List::GetURLCount() +{ + return urlcount; +} + +static int ListCompare(const void *a, const void *b) +{ + Link_Info *ab = (Link_Info*) a; + Link_Info *bb = (Link_Info*) b; + + return strcasecmp((char *) ab->URL, (char *) bb->URL); +} +void URL_List::SortList() +{ + qsort(Links, urlcount, sizeof(Link_Info), ListCompare); +} diff --git a/source/network/URL_List.h b/source/network/URL_List.h new file mode 100644 index 0000000..3c6a255 --- /dev/null +++ b/source/network/URL_List.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * URL List Class + * for USB Loader GX + * by dimok + ***************************************************************************/ +#ifndef ___URLLIST_H_ +#define ___URLLIST_H_ + +#include "network/networkops.h" +#include "network/http.h" + +typedef struct +{ + char *URL; + bool direct; +} Link_Info; + +class URL_List +{ + public: + //!Constructor + //!\param url from where to get the list of links + URL_List(const char *url); + //!Destructor + ~URL_List(); + //! Get the a filepath of the list + //!\param list index + char * GetURL(int index); + //! Is it a direct URL or just a file or path under the main url + bool IsDirectURL(int index); + //! Get the number of links counted + int GetURLCount(); + //! Sort list + void SortList(); + protected: + int urlcount; + Link_Info *Links; +}; + +#endif diff --git a/source/network/Wiinnertag.cpp b/source/network/Wiinnertag.cpp new file mode 100644 index 0000000..c60837f --- /dev/null +++ b/source/network/Wiinnertag.cpp @@ -0,0 +1,126 @@ +/*************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "Wiinnertag.h" +#include "FileOperations/fileops.h" +#include "settings/CSettings.h" +#include "network/networkops.h" +#include "utils/StringTools.h" +#include "xml/tinyxml2.h" +#include "gecko.h" + +using namespace tinyxml2; + +Wiinnertag::Wiinnertag(const string &filepath) +{ + ReadXML(filepath); +} + +bool Wiinnertag::ReadXML(const string &filepath) +{ + XMLDocument xmlDoc; + if(xmlDoc.LoadFile(filepath.c_str()) != 0) + return false; + + XMLElement * node = xmlDoc.FirstChildElement("Tag"); + + while(node != NULL) + { + const char * URL = node->Attribute("URL"); + const char * Key = node->Attribute("Key"); + + if(URL && Key) + { + int size = tagList.size(); + tagList.resize(size+1); + tagList[size].first = URL; + tagList[size].second = Key; + } + + node = node->NextSiblingElement(); + } + + return true; +} + +bool Wiinnertag::Send(const char *gameID) +{ + if(!IsNetworkInit()) + return false; + + char sendURL[1024]; + + for(u32 i = 0; i < tagList.size(); ++i) + { + strcpy(sendURL, tagList[i].first.c_str()); + + replaceString(sendURL, "{ID6}", gameID); + replaceString(sendURL, "{KEY}", tagList[i].second.c_str()); + + download_request(sendURL); + CloseConnection(); + } + + return true; +} + +bool Wiinnertag::TagGame(const char *gameID) +{ + string fullpath = Settings.WiinnertagPath; + if(fullpath.size() == 0) + return false; + + if(fullpath[fullpath.size()-1] != '/') + fullpath += '/'; + fullpath += "Wiinnertag.xml"; + + Wiinnertag Tag(fullpath); + return Tag.Send(gameID); +} + +bool Wiinnertag::CreateExample(const string &filepath) +{ + if(filepath.size() == 0) + return false; + + CreateSubfolder(filepath.c_str()); + + string fullpath = filepath; + if(fullpath[fullpath.size()-1] != '/') + fullpath += '/'; + fullpath += "Wiinnertag.xml"; + + XMLDocument xmlDoc; + + XMLDeclaration * declaration = xmlDoc.NewDeclaration(); + xmlDoc.InsertEndChild(declaration); + + XMLElement *Tag = xmlDoc.NewElement("Tag"); + Tag->SetAttribute("URL", "http://www.wiinnertag.com/wiinnertag_scripts/update_sign.php?key={KEY}&game_id={ID6}"); + Tag->SetAttribute("Key", "1234567890"); + xmlDoc.InsertEndChild(Tag); + + xmlDoc.SaveFile(fullpath.c_str()); + + return true; +} diff --git a/source/network/Wiinnertag.h b/source/network/Wiinnertag.h new file mode 100644 index 0000000..0cf0cdb --- /dev/null +++ b/source/network/Wiinnertag.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef WIINNERTAG_H_ +#define WIINNERTAG_H_ + +#include +#include +#include + +using namespace std; + +class Wiinnertag +{ + public: + static bool CreateExample(const string &filepath); + static bool TagGame(const char *gameID); + private: + Wiinnertag(const string &filepath); + bool Send(const char *gameID); + bool ReadXML(const string &filepath); + vector > tagList; +}; + +#endif diff --git a/source/network/dns.c b/source/network/dns.c new file mode 100644 index 0000000..b13c1a7 --- /dev/null +++ b/source/network/dns.c @@ -0,0 +1,124 @@ +#include "dns.h" + +/** + * Resolves a domainname to an ip address + * It makes use of net_gethostbyname from libogc, which in turn makes use of a Wii BIOS function + * Just like the net_gethostbyname function this function is NOT threadsafe! + * + * @param char* The domain name to resolve + * @return u32 The ipaddress represented by four bytes inside an u32 (in network order) + */ +u32 getipbyname(char *domain) +{ + //Care should be taken when using net_gethostbyname, + //it returns a static buffer which makes it not threadsafe + //TODO: implement some locking mechanism to make below code atomic + struct hostent *host = net_gethostbyname(domain); + + if (host == NULL) + { + return 0; + } + + u32 *ip = (u32*) host->h_addr_list[0]; + return *ip; +} + +//Defines how many DNS entries should be cached by getipbynamecached() +#define MAX_DNS_CACHE_ENTRIES 20 + +//The cache is defined as a linked list, +//The last resolved domain name will always be at the front +//This will allow heavily used domainnames to always stay cached +struct dnsentry +{ + char *domain; + u32 ip; + struct dnsentry *nextnode; +}; + +static struct dnsentry *firstdnsentry = NULL; +static int dnsentrycount = 0; + +/** + * Performs the same function as getipbyname(), + * except that it will prevent extremely expensive net_gethostbyname() calls by caching the result + */ +u32 getipbynamecached(char *domain) +{ + //Search if this domainname is already cached + struct dnsentry *node = firstdnsentry; + struct dnsentry *previousnode = NULL; + + while (node != NULL) + { + if (strcmp(node->domain, domain) == 0) + { + //DNS node found in the cache, move it to the front of the list + if (previousnode != NULL) previousnode->nextnode = node->nextnode; + + if (node != firstdnsentry) node->nextnode = firstdnsentry; + firstdnsentry = node; + + return node->ip; + } + //Go to the next element in the list + previousnode = node; + node = node->nextnode; + } + u32 ip = getipbyname(domain); + + //No cache of this domain could be found, create a cache node and add it to the front of the cache + struct dnsentry *newnode = malloc(sizeof(struct dnsentry)); + if (newnode == NULL) + { + return ip; + } + + newnode->ip = ip; + newnode->domain = malloc(strlen(domain) + 1); + if (newnode->domain == NULL) + { + free(newnode); + return ip; + } + strcpy(newnode->domain, domain); + + newnode->nextnode = firstdnsentry; + firstdnsentry = newnode; + dnsentrycount++; + + //If the cache grows too big delete the last (and probably least important) node of the list + if (dnsentrycount > MAX_DNS_CACHE_ENTRIES) + { + struct dnsentry *node = firstdnsentry; + struct dnsentry *previousnode = NULL; + + //Fetch the last two elements of the list + while (node->nextnode != NULL) + { + previousnode = node; + node = node->nextnode; + } + + if (node == NULL) + { + printf("Configuration error, MAX_DNS_ENTRIES reached while the list is empty\n"); + exit(1); + } + else if (previousnode == NULL) + { + firstdnsentry = NULL; + } + else + { + previousnode->nextnode = NULL; + } + + free(node->domain); + free(node); + dnsentrycount--; + } + + return newnode->ip; +} diff --git a/source/network/dns.h b/source/network/dns.h new file mode 100644 index 0000000..e6d587c --- /dev/null +++ b/source/network/dns.h @@ -0,0 +1,22 @@ +#ifndef _DNS_H_ +#define _DNS_H_ + +#include +#include +#include +#include + +#include //usleep +#ifdef __cplusplus +extern "C" +{ +#endif + + u32 getipbyname(char *domain); + u32 getipbynamecached(char *domain); + +#ifdef __cplusplus +} +#endif + +#endif /* _DNS_H_ */ diff --git a/source/network/http.c b/source/network/http.c new file mode 100644 index 0000000..665abdc --- /dev/null +++ b/source/network/http.c @@ -0,0 +1,392 @@ +/* http -- http convenience functions + + Copyright (C) 2008 bushing + 2008-2014 Dimok, Cyan + + 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, version 2. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "http.h" +#include "../svnrev.h" +#include "gecko.h" + +extern char incommingIP[50]; +static u8 retryloop = 0; + +/** + * Emptyblock is a statically defined variable for functions to return if they are unable + * to complete a request + */ +const struct block emptyblock = { 0, NULL }; + +//The maximum amount of bytes to send per net_write() call +//#define NET_BUFFER_SIZE 1024 +#define NET_BUFFER_SIZE 3600 +//#define VERBOSE + +// Write our message to the server +static s32 send_message(s32 server, char *msg) +{ + s32 bytes_transferred = 0; + s32 remaining = strlen(msg); + while (remaining) + { + if ((bytes_transferred = net_write(server, msg, remaining > NET_BUFFER_SIZE ? NET_BUFFER_SIZE : remaining)) > 0) + { + remaining -= bytes_transferred; + msg += bytes_transferred; + usleep(20 * 1000); + } + else if (bytes_transferred < 0) + { + return bytes_transferred; + } + else + { + return -ENODATA; + } + } + return 0; +} + +/** + * Connect to a remote server via TCP on a specified port + * + * @param u32 ip address of the server to connect to + * @param u32 the port to connect to on the server + * @return s32 The connection to the server (negative number if connection could not be established) + */ +static s32 server_connect(u32 ipaddress, u16 socket_port) +{ + //Initialize socket + s32 connection = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (connection < 0) return connection; + + struct sockaddr_in connect_addr; + memset(&connect_addr, 0, sizeof(connect_addr)); + connect_addr.sin_family = AF_INET; + connect_addr.sin_port = htons(socket_port); + connect_addr.sin_addr.s_addr = ipaddress; + + sprintf(incommingIP, "%s", inet_ntoa(connect_addr.sin_addr)); + + //Attemt to open the socket + if (net_connect(connection, (struct sockaddr*) &connect_addr, sizeof(connect_addr)) == -1) + { + net_close(connection); + return -1; + } + return connection; +} + +//The amount of memory in bytes reserved initially to store the HTTP response in +//Be careful in increasing this number, reading from a socket on the Wii +//will fail if you request more than 20k or so +#define HTTP_BUFFER_SIZE 1024 * 5 + +//The amount of memory the buffer should expanded with if the buffer is full +#define HTTP_BUFFER_GROWTH 1024 * 5 + +/** + * This function reads all the data from a connection into a buffer which it returns. + * It will return an empty buffer if something doesn't go as planned + * + * @param s32 connection The connection identifier to suck the response out of + * @return block A 'block' struct (see http.h) in which the buffer is located + */ +struct block read_message(s32 connection) +{ + //Create a block of memory to put in the response + struct block buffer; + buffer.data = malloc(HTTP_BUFFER_SIZE); + buffer.size = HTTP_BUFFER_SIZE; + + if (buffer.data == NULL) + { + return emptyblock; + } + + //The offset variable always points to the first byte of memory that is free in the buffer + u32 offset = 0; + + while (1) + { + //Fill the buffer with a new batch of bytes from the connection, + //starting from where we left of in the buffer till the end of the buffer + s32 bytes_read = net_read(connection, buffer.data + offset, buffer.size - offset); + + //Anything below 0 is an error in the connection + if (bytes_read < 0) + { + //printf("Connection error from net_read() Errorcode: %i\n", bytes_read); + return emptyblock; + } + + //No more bytes were read into the buffer, + //we assume this means the HTTP response is done + if (bytes_read == 0) + { + break; + } + + offset += bytes_read; + + //Check if we have enough buffer left over, + //if not expand it with an additional HTTP_BUFFER_GROWTH worth of bytes + if (offset >= buffer.size) + { + buffer.size += HTTP_BUFFER_GROWTH; + u8 * tmp = realloc(buffer.data, buffer.size); + + if (tmp == NULL) + { + free(buffer.data); + return emptyblock; + } + else + buffer.data = tmp; + } + } + + //At the end of above loop offset should be precisely the amount of bytes that were read from the connection + buffer.size = offset; + + //Shrink the size of the buffer so the data fits exactly in it + buffer.data = realloc(buffer.data, buffer.size); + + return buffer; +} + +/** + * Downloads the contents of a URL to memory + * This method is not threadsafe (because networking is not threadsafe on the Wii) + */ +struct block downloadfile(const char *url) +{ + //Check if the url starts with "http://", if not it is not considered a valid url + if (strncmp(url, "http://", strlen("http://")) != 0) + { + //printf("URL '%s' doesn't start with 'http://'\n", url); + return emptyblock; + } + + //Locate the path part of the url by searching for '/' past "http://" + char *path = strchr(url + strlen("http://"), '/'); + + //At the very least the url has to end with '/', ending with just a domain is invalid + if (path == NULL) + { + //printf("URL '%s' has no PATH part\n", url); + return emptyblock; + } + + //Extract the domain part out of the url + int domainlength = path - url - strlen("http://"); + + if (domainlength == 0) + { + //printf("No domain part in URL '%s'\n", url); + return emptyblock; + } + + char domain[domainlength + 1]; + strlcpy(domain, url + strlen("http://"), domainlength + 1); + + //Parsing of the URL is done, start making an actual connection + u32 ipaddress = getipbynamecached(domain); + + if (ipaddress == 0) + { + //printf("\ndomain %s could not be resolved", domain); + return emptyblock; + } + + s32 connection = server_connect(ipaddress, 80); + + if (connection < 0) + { + //printf("Error establishing connection"); + return emptyblock; + } + + // Remove Referer from the request header for incompatible websites (ex. Cloudflare proxy) + char referer[domainlength + 12]; + snprintf(referer, sizeof(referer), "Referer: %s\r\n", domain); + if(strstr(url, "geckocodes")) + { + strcpy(referer, ""); + } + + //Form a nice request header to send to the webserver + char* headerformat = "GET %s HTTP/1.0\r\nHost: %s\r\n%sUser-Agent: USBLoaderGX r%s\r\n\r\n"; + char header[strlen(headerformat) + strlen(path) + strlen(domain) + strlen(referer) + 100]; + sprintf(header, headerformat, path, domain, referer, GetRev()); + +#ifdef VERBOSE + gprintf("\nHTTP Request:\n"); + gprintf("%s\n",header); +#endif + + //Do the request and get the response + send_message(connection, header); + struct block response = read_message(connection); + net_close(connection); + +#ifdef VERBOSE + // dump response + hexdump(response.data, response.size); +#endif + + //Search for the 4-character sequence \r\n\r\n in the response which signals the start of the http payload (file) + unsigned char *filestart = NULL; + u32 filesize = 0; + u32 i; + char newURL[512]; + bool redirect = false; + + for (i = 3; i < response.size; i++) + { + if (response.data[i] == '\n' && response.data[i - 1] == '\r' && response.data[i - 2] == '\n' && response.data[i - 3] == '\r') + { + filestart = response.data + i + 1; + filesize = response.size - i - 1; + + // Check the HTTP response code + if (response.size > 10 && strncmp((char*)response.data, "HTTP/", 5)==0) + { + char htstat[i]; + strncpy(htstat, (char*)response.data, i); + htstat[i] = 0; + char *codep; + codep = strchr(htstat, ' '); + if (codep) + { + int code; + if (sscanf(codep+1, "%d", &code) == 1) + { +#ifdef VERBOSE + gprintf("HTTP response code: %d\n", code); +#endif + if (code == 302) // 302 FOUND (redirected link) + { + char *ptr = strcasestr((char*)response.data, "Location: "); + if(ptr) + { + ptr += strlen("Location: "); + strncpy(newURL, ptr, sizeof(newURL)); + *(strchr(newURL, '\r'))=0; + + redirect = true; +#ifdef VERBOSE + gprintf("New URL to download = %s \n", newURL); +#endif + } + else + { +#ifdef VERBOSE + gprintf("HTTP ERROR: %s\n", htstat); +#endif + free(response.data); + return emptyblock; + } + } + if (code >=400) // Not found + { +#ifdef VERBOSE + gprintf("HTTP ERROR: %s\n", htstat); +#endif + free(response.data); + return emptyblock; + } + } + } + } + break; + } + } + + if(redirect) + { + // Prevent endless loop + retryloop++; + if(retryloop > 3) + { + retryloop = 0; + free(response.data); + return emptyblock; + } + + struct block redirected = downloadfile(newURL); + + // copy the newURL data into the original data + u8 * tmp = realloc(response.data, redirected.size); + if (tmp == NULL) + { +#ifdef VERBOSE + gprintf("Could not allocate enough memory for new URL. Download canceled.\n"); +#endif + free(response.data); + free(redirected.data); + return emptyblock; + } + response.data = tmp; + memcpy(response.data, redirected.data, redirected.size); + + // Set filestart's new size based on redirected file + filestart = response.data; + filesize = redirected.size; + free(redirected.data); + + } + retryloop = 0; + + if (filestart == NULL) + { + //printf("HTTP Response was without a file\n"); + free(response.data); + return emptyblock; + } + + //Copy the file part of the response into a new memoryblock to return + struct block file; + file.data = malloc(filesize); + file.size = filesize; + + if (file.data == NULL) + { + //printf("No more memory to copy file from HTTP response\n"); + free(response.data); + return emptyblock; + } + + memcpy(file.data, filestart, filesize); + + //Dispose of the original response + free(response.data); + + return file; +} + +s32 GetConnection(char * domain) +{ + + u32 ipaddress = getipbynamecached(domain); + if (ipaddress == 0) + { + return -1; + } + s32 connection = server_connect(ipaddress, 80); + return connection; + +} diff --git a/source/network/http.h b/source/network/http.h new file mode 100644 index 0000000..f1008c5 --- /dev/null +++ b/source/network/http.h @@ -0,0 +1,34 @@ +#ifndef _HTTP_H_ +#define _HTTP_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "dns.h" + + /** + * A simple structure to keep track of the size of a malloc()ated block of memory + */ + struct block + { + u32 size; + unsigned char *data; + }; + + extern const struct block emptyblock; + + struct block downloadfile(const char *url); + s32 GetConnection(char * domain); + +#ifdef __cplusplus +} +#endif + +#endif /* _HTTP_H_ */ diff --git a/source/network/networkops.cpp b/source/network/networkops.cpp new file mode 100644 index 0000000..b399814 --- /dev/null +++ b/source/network/networkops.cpp @@ -0,0 +1,606 @@ +/**************************************************************************** + * Network Operations + * for USB Loader GX + * + * HTTP operations + * Written by dhewg/bushing modified by dimok + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "prompts/PromptWindows.h" +#include "language/gettext.h" +#include "settings/CSettings.h" +#include "utils/timer.h" +#include "networkops.h" +#include "main.h" +#include "http.h" +#include "svnrev.h" +#include "gecko.h" +#include "update.h" + +#define PORT 4299 + +/*** Incomming filesize ***/ +u32 infilesize = 0; +u32 uncfilesize = 0; + +bool updateavailable = false; +s32 connection; +static s32 socket; +static bool updatechecked = false; +static bool networkinitialized = false; +static bool checkincomming = false; +static bool waitforanswer = false; +static char IP[16]; +char incommingIP[50]; +char wiiloadVersion[2]; + +static lwp_t networkthread = LWP_THREAD_NULL; +static bool networkHalt = true; + +/**************************************************************************** + * Initialize_Network + ***************************************************************************/ +void Initialize_Network(int retries) +{ + + if (networkinitialized) return; + + s32 result; + + result = if_config(IP, NULL, NULL, true, retries); + + if (result < 0) + { + networkinitialized = false; + return; + } + else + { + networkinitialized = true; + return; + } +} + +/**************************************************************************** + * DeinitNetwork + ***************************************************************************/ +void DeinitNetwork(void) +{ + net_wc24cleanup(); + net_deinit(); + networkinitialized = false; +} + +/**************************************************************************** + * Check if network was initialised + ***************************************************************************/ +bool IsNetworkInit(void) +{ + return networkinitialized; +} + +/**************************************************************************** + * Get network IP + ***************************************************************************/ +char * GetNetworkIP(void) +{ + return IP; +} + +/**************************************************************************** + * Get incomming IP + ***************************************************************************/ +char * GetIncommingIP(void) +{ + return incommingIP; +} + +s32 network_request(s32 connect, const char * request, char * filename) +{ + if(connect == NET_DEFAULT_SOCK) + connect = connection; + + char buf[1024]; + char *ptr = NULL; + + u32 cnt, size; + s32 ret; + + /* Send request */ + ret = net_send(connect, request, strlen(request), 0); + if (ret < 0) return ret; + + /* Clear buffer */ + memset(buf, 0, sizeof(buf)); + + /* Read HTTP header */ + for (cnt = 0; !strstr(buf, "\r\n\r\n"); cnt++) + if (net_recv(connect, buf + cnt, 1, 0) <= 0) return -1; + + /* HTTP request OK? */ + if (!strstr(buf, "HTTP/1.1 200 OK")) return -1; + + if (filename) + { + /* Get filename */ + ptr = strstr(buf, "filename=\""); + + if (ptr) + { + ptr += sizeof("filename=\"") - 1; + + for (cnt = 0; ptr[cnt] != '\r' && ptr[cnt] != '\n' && ptr[cnt] != '"'; cnt++) + { + filename[cnt] = ptr[cnt]; + filename[cnt + 1] = '\0'; + } + } + } + + /* Retrieve content size */ + ptr = strstr(buf, "Content-Length:"); + if (!ptr) return NET_SIZE_UNKNOWN; + + sscanf(ptr, "Content-Length: %lu", &size); + return size; +} + +s32 network_read(s32 connect, u8 *buf, u32 len) +{ + if(connect == NET_DEFAULT_SOCK) + connect = connection; + + u32 read = 0; + s32 ret = -1; + + /* Data to be read */ + while (read < len) + { + /* Read network data */ + ret = net_read(connect, buf + read, len - read); + if (ret < 0) return ret; + + /* Read finished */ + if (!ret) break; + + /* Increment read variable */ + read += ret; + } + + return read; +} + +/**************************************************************************** + * Download request + ***************************************************************************/ +s32 download_request(const char * url, char * filename) +{ + //Check if the url starts with "http://", if not it is not considered a valid url + if (strncmp(url, "http://", strlen("http://")) != 0) + { + return -1; + } + + //Locate the path part of the url by searching for '/' past "http://" + char *path = strchr(url + strlen("http://"), '/'); + + //At the very least the url has to end with '/', ending with just a domain is invalid + if (path == NULL) + { + return -1; + } + + //Extract the domain part out of the url + int domainlength = path - url - strlen("http://"); + + if (domainlength == 0) + { + return -1; + } + + char domain[domainlength + 1]; + strlcpy(domain, url + strlen("http://"), domainlength + 1); + + connection = GetConnection(domain); + if (connection < 0) + { + return -1; + } + + //Form a nice request header to send to the webserver + char header[strlen(path) + strlen(domain) + strlen(url) + 100]; + sprintf(header, "GET %s HTTP/1.1\r\nHost: %s\r\nReferer: %s\r\nUser-Agent: USBLoaderGX\r\nConnection: close\r\n\r\n", path, domain, url); + + s32 filesize = network_request(connection, header, filename); + + return filesize; +} + +/**************************************************************************** + * HTML HEAD request + ***************************************************************************/ +char * HEAD_Request(const char * url) +{ + if(strncmp(url, "http://", strlen("http://")) != 0) + { + gprintf("Not a valid URL"); + return NULL; + } + char *path = strchr(url + strlen("http://"), '/'); + + if(!path) + { + gprintf("Not a valid URL path"); + return NULL; + } + + int domainlength = path - url - strlen("http://"); + + if(domainlength == 0) + { + gprintf("Not a valid domain"); + return NULL; + } + + char domain[domainlength + 1]; + strncpy(domain, url + strlen("http://"), domainlength); + domain[domainlength] = '\0'; + + connection = GetConnection(domain); + if(connection < 0) + { + gprintf("Could not connect to the server."); + return NULL; + } + + char header[strlen(path)+strlen(domain)*2+150]; + sprintf(header, "HEAD %s HTTP/1.1\r\nHost: %s\r\nReferer: %s\r\nUser-Agent: USB Loader GX\r\nConnection: close\r\n\r\n", path, domain, domain); + + /* Send request */ + s32 ret = net_send(connection, header, strlen(header), 0); + if (ret < 0) + { + CloseConnection(); + return NULL; + } + + u32 cnt = 0; + char * buf = (char *) malloc(1024); + memset(buf, 0, 1024); + + for (cnt = 0; !strstr(buf, "\r\n\r\n") && cnt < 1024; cnt++) + { + if(net_recv(connection, buf + cnt, 1, 0) <= 0) + { + CloseConnection(); + free(buf); + return NULL; + } + } + + CloseConnection(); + + return buf; +} + +void CloseConnection() +{ + + net_close(connection); + + if (waitforanswer) + { + net_close(socket); + waitforanswer = false; + } +} + +/**************************************************************************** + * Test if connection to the address is available (PING) + ***************************************************************************/ +bool CheckConnection(const char *url, float timeout) +{ + //Check if the url starts with "http://", if not it is not considered a valid url + if (strncmp(url, "http://", strlen("http://")) != 0) + return false; + + //Locate the path part of the url by searching for '/' past "http://" + char *path = strchr(url + strlen("http://"), '/'); + + //At the very least the url has to end with '/', ending with just a domain is invalid + if (path == NULL) + return false; + + //Extract the domain part out of the url + int domainlength = path - url - strlen("http://"); + if (domainlength == 0) + return false; + + char domain[domainlength + 1]; + strlcpy(domain, url + strlen("http://"), domainlength + 1); + + //Parsing of the URL is done, start making an actual connection + u32 ipaddress = getipbynamecached(domain); + if (ipaddress == 0) + return false; + + //Initialize socket + s32 connection = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (connection < 0) return connection; + + s32 flags = net_fcntl(connection, F_GETFL, 0); + if (flags >= 0) flags = net_fcntl(connection, F_SETFL, flags | 4); + + struct sockaddr_in connect_addr; + memset(&connect_addr, 0, sizeof(connect_addr)); + connect_addr.sin_family = AF_INET; + connect_addr.sin_port = 80; + connect_addr.sin_addr.s_addr = getipbynamecached(domain); + + Timer netTime; + + int res = -1; + while(res < 0 && res != -127 && netTime.elapsed() < timeout) + { + res = net_connect(connection, (struct sockaddr*) &connect_addr, sizeof(connect_addr)); + usleep(1000); + } + + net_close(connection); + + return !(res < 0 && res != -127); +} + + +/**************************************************************************** + * Download request + ***************************************************************************/ +s32 DownloadWithResponse(const char * url, u8 **outbuffer, u32 *outsize) +{ + //Check if the url starts with "http://", if not it is not considered a valid url + if (strncmp(url, "http://", strlen("http://")) != 0) + return -1; + + //Locate the path part of the url by searching for '/' past "http://" + char *path = strchr(url + strlen("http://"), '/'); + + //At the very least the url has to end with '/', ending with just a domain is invalid + if (path == NULL) + return -1; + + //Extract the domain part out of the url + int domainlength = path - url - strlen("http://"); + + if (domainlength == 0) + return -1; + + char domain[domainlength + 1]; + strlcpy(domain, url + strlen("http://"), domainlength + 1); + + int connect = GetConnection(domain); + if (connect < 0) + return -1; + + //Form a nice request header to send to the webserver + char header[strlen(path) + strlen(domain) + strlen(url) + 100]; + sprintf(header, "GET %s HTTP/1.1\r\nHost: %s\r\nReferer: %s\r\nUser-Agent: USBLoaderGX\r\nConnection: close\r\n\r\n", path, domain, url); + + int ret = net_send(connect, header, strlen(header), 0); + if(ret < 0) + { + net_close(connect); + return ret; + } + + int blocksize = 4096; + + u8 *buffer = (u8 *) malloc(blocksize); + if(!buffer) + { + net_close(connect); + return -1; + } + + int done = 0; + + while(1) + { + int ret = network_read(connect, buffer+done, blocksize); + + if(ret < 0) + { + free(buffer); + net_close(connect); + return -1; + } + else if(ret == 0) + break; + + done += ret; + u8 *tmp = (u8 *) realloc(buffer, done+blocksize); + if(!tmp) + { + free(buffer); + net_close(connect); + return -1; + } + + buffer = tmp; + } + + net_close(connect); + + u8 *tmp = (u8 *) realloc(buffer, done+1); + if(!tmp) + { + free(buffer); + return -1; + } + + buffer = tmp; + buffer[done] = 0; + + *outbuffer = buffer; + *outsize = done; + + return done; +} + + +/**************************************************************************** + * NetworkWait + ***************************************************************************/ +int NetworkWait() +{ + if (!checkincomming) return -3; + + struct sockaddr_in sin; + struct sockaddr_in client_address; + socklen_t addrlen = sizeof(client_address); + + //Open socket + socket = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + + if (socket == INVALID_SOCKET) + { + return socket; + } + + sin.sin_family = AF_INET; + sin.sin_port = htons( PORT ); + sin.sin_addr.s_addr = htonl( INADDR_ANY ); + + if (net_bind(socket, (struct sockaddr*) &sin, sizeof(sin)) < 0) + { + net_close(socket); + return -1; + } + + if (net_listen(socket, 3) < 0) + { + net_close(socket); + return -1; + } + + connection = net_accept(socket, (struct sockaddr*) &client_address, &addrlen); + + sprintf(incommingIP, "%s", inet_ntoa(client_address.sin_addr)); + + if (connection < 0) + { + net_close(connection); + net_close(socket); + return -4; + + } + else + { + + unsigned char haxx[9]; + //skip haxx + net_read(connection, &haxx, 8); + wiiloadVersion[0] = haxx[4]; + wiiloadVersion[1] = haxx[5]; + + net_read(connection, &infilesize, 4); + + if (haxx[4] > 0 || haxx[5] > 4) + { + net_read(connection, &uncfilesize, 4); // Compressed protocol, read another 4 bytes + } + waitforanswer = true; + checkincomming = false; + networkHalt = true; + } + + return 1; +} + +/**************************************************************************** + * HaltNetwork + ***************************************************************************/ +void HaltNetworkThread() +{ + networkHalt = true; + checkincomming = false; + + if (waitforanswer) CloseConnection(); + + // wait for thread to finish + while (!LWP_ThreadIsSuspended(networkthread)) + usleep(100); +} + +/**************************************************************************** + * ResumeNetworkThread + ***************************************************************************/ +void ResumeNetworkThread() +{ + networkHalt = false; + LWP_ResumeThread(networkthread); +} + +/**************************************************************************** + * Resume NetworkWait + ***************************************************************************/ +void ResumeNetworkWait() +{ + networkHalt = true; + checkincomming = true; + waitforanswer = true; + infilesize = 0; + connection = -1; + LWP_ResumeThread(networkthread); +} + +/********************************************************************************* + * Networkthread for background network initialize and update check with idle prio + *********************************************************************************/ +static void * networkinitcallback(void *arg) +{ + while (1) + { + if (!checkincomming && networkHalt) + LWP_SuspendThread(networkthread); + + Initialize_Network(); + + if (networkinitialized == true && updatechecked == false) + { + + if (CheckUpdate() > 0) updateavailable = true; + + //suspend thread + updatechecked = true; + networkHalt = true; + } + + if (checkincomming) NetworkWait(); + + usleep(100000); + } + return NULL; +} + +/**************************************************************************** + * InitNetworkThread with priority 0 (idle) + ***************************************************************************/ +void InitNetworkThread() +{ + LWP_CreateThread(&networkthread, networkinitcallback, NULL, NULL, 16384, 0); +} + +/**************************************************************************** + * ShutdownThread + ***************************************************************************/ +void ShutdownNetworkThread() +{ + LWP_JoinThread(networkthread, NULL); + networkthread = LWP_THREAD_NULL; +} diff --git a/source/network/networkops.h b/source/network/networkops.h new file mode 100644 index 0000000..a6ac649 --- /dev/null +++ b/source/network/networkops.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * Network Operations + * for USB Loader GX + * + * HTTP operations + * Written by dhewg/bushing modified by dimok + ****************************************************************************/ +#ifndef _NETWORKOPS_H_ +#define _NETWORKOPS_H_ + +#define NETWORKBLOCKSIZE 5*1024 //5KB +#define NET_SIZE_UNKNOWN -0xFFFFFFF +#define NET_DEFAULT_SOCK -0xFFFFFFE + +void Initialize_Network(int retries = 0); +void DeinitNetwork(void); +bool IsNetworkInit(void); +char * GetNetworkIP(void); +char * GetIncommingIP(void); +bool ShutdownWC24(); +bool CheckConnection(const char *url, float timeout = 5.0f); +s32 network_request(s32 connection, const char * request, char * filename); +s32 network_read(s32 connection, u8 *buf, u32 len); +s32 download_request(const char * url, char * filename = NULL); +s32 DownloadWithResponse(const char * url, u8 **outbuffer, u32 *outsize); +void CloseConnection(); +char * HEAD_Request(const char * url); +void HaltNetworkThread(); +void ResumeNetworkWait(); +void ResumeNetworkThread(); +void InitNetworkThread(); +void ShutdownNetworkThread(); + +#endif diff --git a/source/network/ssl.c b/source/network/ssl.c new file mode 100644 index 0000000..94efba3 --- /dev/null +++ b/source/network/ssl.c @@ -0,0 +1,284 @@ +/* Code taken from http://wiibrew.org/wiki//dev/net/ssl/code */ + +#include +#include +#include "ssl.h" +#include "libs/libruntimeiospatch/runtimeiospatch.h" + +#define ISALIGNED(x) ((((u32)x)&0x1F)==0) + +static char __ssl_fs[] ATTRIBUTE_ALIGN(32) = "/dev/net/ssl"; + +static s32 __ssl_fd = -1; +static s32 __ssl_hid = -1; + +s32 ssl_init(void){ + + if(__ssl_hid < 0 ) { + __ssl_hid = iosCreateHeap(SSL_HEAP_SIZE); + if(__ssl_hid < 0){ + return __ssl_hid; + } + if(IosPatch_SSL(false) < 4) + return -1; + } + + return 0; +} + +u32 ssl_open(void){ + + s32 ret; + + if (__ssl_fd < 0) { + ret = IOS_Open(__ssl_fs,0); + if(ret<0){ + return ret; + } + __ssl_fd = ret; + } + + return 0; +} + +u32 ssl_close(void){ + s32 ret; + + if(__ssl_fd < 0){ + return 0; + } + + ret = IOS_Close(__ssl_fd); + + __ssl_fd = -1; + + if(ret<0){ + return ret; + } + + return 0; +} + +s32 ssl_new(u8 * CN, u32 ssl_verify_options){ + + s32 ret; + s32 aContext[8] ATTRIBUTE_ALIGN(32); + u32 aVerify_options[8] ATTRIBUTE_ALIGN(32); + + ret = ssl_open(); + if(ret){ + return ret; + } + + aVerify_options[0] = ssl_verify_options; + + if(ISALIGNED(CN)){ //Avoid alignment if the input is aligned + ret = IOS_IoctlvFormat(__ssl_hid, __ssl_fd, IOCTLV_SSL_NEW, "d:dd", aContext, 0x20, aVerify_options, 0x20, CN, 0x100); + }else{ + u8 *aCN = NULL; + + aCN = iosAlloc(__ssl_hid, 0x100); + if (!aCN) { + return IPC_ENOMEM; + } + + memcpy(aCN, CN, 0x100); + ret = IOS_IoctlvFormat(__ssl_hid, __ssl_fd, IOCTLV_SSL_NEW, "d:dd", aContext, 0x20, aVerify_options, 0x20, aCN, 0x100); + + if(aCN){ + iosFree(__ssl_hid, aCN); + } + } + + ssl_close(); + +return (ret ? ret : aContext[0]); +} + + +s32 ssl_setbuiltinclientcert(s32 ssl_context, s32 index){ + + s32 aSsl_context[8] ATTRIBUTE_ALIGN(32); + s32 aIndex[8] ATTRIBUTE_ALIGN(32); + s32 aResponse[8] ATTRIBUTE_ALIGN(32); + s32 ret; + + ret = ssl_open(); + if(ret){ + return ret; + } + + aSsl_context[0] = ssl_context; + aIndex[0] = index; + ret = IOS_IoctlvFormat(__ssl_hid, __ssl_fd, IOCTLV_SSL_SETBUILTINCLIENTCERT, "d:dd", aResponse, 32, aSsl_context, 32, aIndex, 32); + ssl_close(); + +return (ret ? ret : aResponse[0]); +} + + +s32 ssl_setrootca(s32 ssl_context, const void *root, u32 length){ + + s32 aSsl_context[8] ATTRIBUTE_ALIGN(32); + s32 aResponse[8] ATTRIBUTE_ALIGN(32); + s32 ret; + + ret = ssl_open(); + if(ret){ + return ret; + } + + aSsl_context[0] = ssl_context; + + if(ISALIGNED(root)){ //Avoid alignment if the input is aligned + ret = IOS_IoctlvFormat(__ssl_hid, __ssl_fd, IOCTLV_SSL_SETROOTCA, "d:dd", aResponse, 0x20, aSsl_context, 0x20, root, length); + }else{ + u8 *aRoot = NULL; + + aRoot = iosAlloc(__ssl_hid, length); + if (!aRoot) { + return IPC_ENOMEM; + } + + memcpy(aRoot, root, length); + ret = IOS_IoctlvFormat(__ssl_hid, __ssl_fd, IOCTLV_SSL_SETROOTCA, "d:dd", aResponse, 0x20, aSsl_context, 0x20, aRoot, length); + + if(aRoot){ + iosFree(__ssl_hid, aRoot); + } + } + + ssl_close(); + +return (ret ? ret : aResponse[0]); +} + + +s32 ssl_connect(s32 ssl_context, s32 socket){ + + s32 aSsl_context[8] ATTRIBUTE_ALIGN(32); + s32 aSocket[8] ATTRIBUTE_ALIGN(32); + s32 aResponse[8] ATTRIBUTE_ALIGN(32); + s32 ret; + + ret = ssl_open(); + if(ret){ + return ret; + } + + aSsl_context[0] = ssl_context; + aSocket[0] = socket; + ret = IOS_IoctlvFormat(__ssl_hid, __ssl_fd, IOCTLV_SSL_CONNECT, "d:dd", aResponse, 0x20, aSsl_context, 0x20, aSocket, 0x20); + ssl_close(); + +return (ret ? ret : aResponse[0]); +} + + +s32 ssl_handshake( s32 ssl_context ){ + + s32 aSsl_context[8] ATTRIBUTE_ALIGN(32); + s32 aResponse[8] ATTRIBUTE_ALIGN(32); + s32 ret; + + ret = ssl_open(); + if(ret){ + return ret; + } + + aSsl_context[0] = ssl_context; + ret = IOS_IoctlvFormat(__ssl_hid, __ssl_fd, IOCTLV_SSL_HANDSHAKE, "d:d", aResponse, 0x20, aSsl_context, 0x20); + ssl_close(); + +return (ret ? ret : aResponse[0]); +} + + +s32 ssl_read(s32 ssl_context, void* buffer, u32 length){ + s32 aSsl_context[8] ATTRIBUTE_ALIGN(32); + s32 aResponse[8] ATTRIBUTE_ALIGN(32); + s32 ret; + + ret = ssl_open(); + if(ret){ + return ret; + } + + if(!buffer){ + return IPC_EINVAL; + } + + u8 *aBuffer = NULL; + aBuffer = iosAlloc(__ssl_hid, length); + if (!aBuffer) { + return IPC_ENOMEM; + } + + aSsl_context[0] = ssl_context; + ret = IOS_IoctlvFormat(__ssl_hid, __ssl_fd, IOCTLV_SSL_READ, "dd:d", aResponse, 0x20, aBuffer, length, aSsl_context, 0x20); + ssl_close(); + + if(ret == IPC_OK){ + memcpy(buffer, aBuffer, aResponse[0]); + } + + if(aBuffer){ + iosFree(__ssl_hid, aBuffer); + } + +return (ret ? ret : aResponse[0]); +} + +s32 ssl_write(s32 ssl_context, const void *buffer, u32 length){ + + s32 aSsl_context[8] ATTRIBUTE_ALIGN(32); + s32 aResponse[8] ATTRIBUTE_ALIGN(32); + s32 ret; + + ret = ssl_open(); + if(ret){ + return ret; + } + + if(!buffer){ + return IPC_EINVAL; + } + + aSsl_context[0] = ssl_context; + + if(ISALIGNED(buffer)){ //Avoid alignment if the input is aligned + ret = IOS_IoctlvFormat(__ssl_hid, __ssl_fd, IOCTLV_SSL_WRITE, "d:dd", aResponse, 0x20, aSsl_context, 0x20, buffer, length); + }else{ + u8 *aBuffer = NULL; + aBuffer = iosAlloc(__ssl_hid, length); + if (!aBuffer) { + return IPC_ENOMEM; + } + + memcpy(aBuffer, buffer, length); + ret = IOS_IoctlvFormat(__ssl_hid, __ssl_fd, IOCTLV_SSL_WRITE, "d:dd", aResponse, 0x20, aSsl_context, 0x20, aBuffer, length); + } + + ssl_close(); + +return (ret ? ret : aResponse[0]); +} + +s32 ssl_shutdown( s32 ssl_context){ + s32 aSsl_context[8] ATTRIBUTE_ALIGN(32); + s32 aResponse[8] ATTRIBUTE_ALIGN(32); + s32 ret; + + ret = ssl_open(); + if(ret){ + return ret; + } + + aSsl_context[0] = ssl_context; + + ret = IOS_IoctlvFormat(__ssl_hid, __ssl_fd, IOCTLV_SSL_SHUTDOWN, "d:d", aResponse, 0x20, aSsl_context, 0x20); + + ssl_close(); + +return (ret ? ret : aResponse[0]); +} \ No newline at end of file diff --git a/source/network/ssl.h b/source/network/ssl.h new file mode 100644 index 0000000..3226f01 --- /dev/null +++ b/source/network/ssl.h @@ -0,0 +1,36 @@ +/* Code taken from http://wiibrew.org/wiki//dev/net/ssl/code */ +#ifndef _SSL_H_ +#define _SSL_H_ + +#define IOCTLV_SSL_NEW 1 +#define IOCTLV_SSL_CONNECT 2 +#define IOCTLV_SSL_HANDSHAKE 3 +#define IOCTLV_SSL_READ 4 +#define IOCTLV_SSL_WRITE 5 +#define IOCTLV_SSL_SHUTDOWN 6 +#define IOCTLV_SSL_SETROOTCA 10 +#define IOCTLV_SSL_SETBUILTINCLIENTCERT 14 + +#define SSL_HEAP_SIZE 0xB000 + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +s32 ssl_init(void); +u32 ssl_open(void); +u32 ssl_close(void); +s32 ssl_new(u8 * CN, u32 verify_options); +s32 ssl_setbuiltinclientcert(s32 ssl_context, s32 index); +s32 ssl_setrootca(s32 ssl_context, const void *root, u32 length); +s32 ssl_connect(s32 ssl_context, s32 socket); +s32 ssl_handshake( s32 ssl_context ); +s32 ssl_read(s32 ssl_context, void* buffer, u32 length); +s32 ssl_write(s32 ssl_context, const void * buffer, u32 length); +s32 ssl_shutdown( s32 ssl_context); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/source/network/update.cpp b/source/network/update.cpp new file mode 100644 index 0000000..5fabdd3 --- /dev/null +++ b/source/network/update.cpp @@ -0,0 +1,385 @@ +/*************************************************************************** + * Copyright (C) 2009 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * update.cpp + * + * Update operations + * for Wii-Xplorer 2009 + ***************************************************************************/ +#include +#include +#include +#include + +#include "gecko.h" +#include "ZipFile.h" +#include "http.h" +#include "networkops.h" +#include "HTML_Stream.h" +#include "FileDownloader.h" +#include "settings/CSettings.h" +#include "settings/GameTitles.h" +#include "language/gettext.h" +#include "language/UpdateLanguage.h" +#include "homebrewboot/BootHomebrew.h" +#include "utils/StringTools.h" +#include "utils/ShowError.h" +#include "prompts/PromptWindows.h" +#include "FileOperations/fileops.h" +#include "xml/GameTDB.hpp" +#include "wad/nandtitle.h" +#include "wad/wad.h" +#include "sys.h" +#include "svnrev.h" + +static const char * GameTDB_URL = "http://www.gametdb.com/wiitdb.zip"; + +/**************************************************************************** + * Checking if an Update is available + ***************************************************************************/ +int CheckForBetaUpdate() +{ + int revnumber = 0; + + HTML_Stream HTML("http://code.google.com/p/usbloader-gui/downloads/list"); + + const char * HTML_Pos = NULL; + + do + { + HTML_Pos = HTML.FindStringEnd("href='"); + char * tmpLink = HTML.CopyString("'\""); + if (tmpLink) + { + char *fileext = strrchr(tmpLink, '.'); + if (fileext) + { + if (strcasecmp(fileext, ".dol") == 0) + { + char revtxt[80]; + char *filename = strrchr(tmpLink, '/') + 2; + u8 n = 0; + for (n = 0; n < strlen(filename) - 2; n++) + revtxt[n] = filename[n]; + revtxt[n] = 0; + int fileRev = atoi(revtxt); + + if (fileRev > revnumber) + { + revnumber = fileRev; + } + } + } + free(tmpLink); + } + } while (HTML_Pos != NULL); + + return revnumber; +} + +static bool CheckNewGameTDBVersion(const char *url) +{ + u64 Version = 0; + + char * HEAD_Responde = HEAD_Request(url); + if(!HEAD_Responde) + return false; + + char * version_ptr = strstr(HEAD_Responde, "X-GameTDB-Timestamp: "); + if(version_ptr) + { + version_ptr += strlen("X-GameTDB-Timestamp: "); + Version = strtoull(version_ptr, NULL, 10); + } + + free(HEAD_Responde); + + std::string Title; + std::string Filepath = Settings.titlestxt_path; + if(Settings.titlestxt_path[Filepath.size()-1] != '/') + Filepath += '/'; + Filepath += "wiitdb.xml"; + + GameTDB XML_DB; + + if(!XML_DB.OpenFile((Filepath.c_str()))) + return true; //! If no file exists we need the file + + u64 ExistingVersion = XML_DB.GetGameTDBVersion(); + + gprintf("Existing GameTDB Version: %llu Online GameTDB Version: %llu\n", ExistingVersion, Version); + + return (ExistingVersion != Version); +} + +int UpdateGameTDB() +{ + if(CheckNewGameTDBVersion(GameTDB_URL) == false) + { + gprintf("Not updating GameTDB: Version is the same\n"); + return -1; + } + + gprintf("Updating GameTDB...\n"); + + string ZipPath = Settings.titlestxt_path; + if(Settings.titlestxt_path[ZipPath.size()-1] != '/') + ZipPath += '/'; + + ZipPath += "wiitdb.zip"; + + int filesize = DownloadFileToPath(GameTDB_URL, ZipPath.c_str(), false); + + if(filesize <= 0) + return -1; + + ZipFile zFile(ZipPath.c_str()); + + bool result = zFile.ExtractAll(Settings.titlestxt_path); + + //! The zip file is not needed anymore so we can remove it + remove(ZipPath.c_str()); + + //! Reload all titles and reload cached titles because the file changed now. + GameTitles.SetDefault(); + GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path); + + return (result ? filesize : -1); +} + +static void UpdateIconPng() +{ + char iconpath[200]; + struct block file = downloadfile("http://svn.code.sf.net/p/usbloadergx/code/branches/updates/icon.png"); + if (file.data != NULL) + { + snprintf(iconpath, sizeof(iconpath), "%sicon.png", Settings.update_path); + FILE * pfile = fopen(iconpath, "wb"); + if(pfile) + { + fwrite(file.data, 1, file.size, pfile); + fclose(pfile); + } + free(file.data); + } +} + +static void UpdateMetaXml() +{ + char xmlpath[200]; + struct block file = downloadfile("http://svn.code.sf.net/p/usbloadergx/code/branches/updates/meta.xml"); + // if not working, use this url form: http://sourceforge.net/p/usbloadergx/code/1254/tree//branches/updates/meta.xml?format=raw + if (file.data != NULL) + { + snprintf(xmlpath, sizeof(xmlpath), "%smeta.xml", Settings.update_path); + FILE *pfile = fopen(xmlpath, "wb"); + if(pfile) + { + fwrite(file.data, 1, file.size, pfile); + fclose(pfile); + } + free(file.data); + } +} + +int CheckUpdate() +{ + if (!IsNetworkInit()) + return -1; + + int revnumber = 0; + int currentrev = atoi(GetRev()); + +#ifdef FULLCHANNEL + struct block file = downloadfile( "http://svn.code.sf.net/p/usbloadergx/code/branches/updates/update_wad.txt" ); +#else + struct block file = downloadfile("http://svn.code.sf.net/p/usbloadergx/code/branches/updates/update_dol.txt"); +#endif + + if (file.data != NULL) + { + revnumber = atoi((char *) file.data); + free(file.data); + } + + if (revnumber > currentrev) + return revnumber; + + return -1; +} + +static int ApplicationDownload(void) +{ + std::string DownloadURL; + int newrev = 0; + int currentrev = atoi(GetRev()); + +#ifdef FULLCHANNEL + struct block file = downloadfile( "http://svn.code.sf.net/p/usbloadergx/code/branches/updates/update_wad.txt" ); +#else + struct block file = downloadfile("http://svn.code.sf.net/p/usbloadergx/code/branches/updates/update_dol.txt"); +#endif + + if (file.data != NULL) + { + // first line of the text file is the revisionc + newrev = atoi((char *) file.data); + // 2nd line of the text file is the url + char *ptr = strchr((char *)file.data, '\n'); + while(ptr && (*ptr == '\r' || *ptr == '\n' || *ptr == ' ')) + ptr++; + while(ptr && *ptr != '\0' && *ptr != '\r' && *ptr != '\n') + { + DownloadURL.push_back(*ptr); + ptr++; + } + + free(file.data); + } + + if (newrev <= currentrev) + { + WindowPrompt(tr( "No new updates." ), 0, tr( "OK" )); + return 0; + } + + bool update_error = false; + char tmppath[250]; + + #ifdef FULLCHANNEL + snprintf(tmppath, sizeof(tmppath), "%s/ULNR.wad", Settings.BootDevice); + #else + char realpath[250]; + snprintf(realpath, sizeof(realpath), "%sboot.dol", Settings.update_path); + snprintf(tmppath, sizeof(tmppath), "%sboot.tmp", Settings.update_path); + #endif + + int update_choice = WindowPrompt(fmt("Rev%i %s.", newrev, tr( "available" )), tr( "How do you want to update?" ), tr( "Update DOL" ), tr( "Update All" ), tr( "Cancel" )); + if (update_choice == 0) + return 0; + + int ret = DownloadFileToPath(DownloadURL.c_str(), tmppath, false); + if(ret < 1024*1024) + { + remove(tmppath); + WindowPrompt(tr("Failed updating"), tr("Error while downloding file"), tr( "OK" )); + if(update_choice == 1) + return -1; + + update_error = true; + } + else + { + #ifdef FULLCHANNEL + FILE * wadFile = fopen(tmppath, "rb"); + if(!wadFile) + { + update_error = true; + WindowPrompt(tr("Failed updating"), tr("Error opening downloaded file"), tr( "OK" )); + return -1; + } + + int error = Wad_Install( wadFile ); + if(error) + { + update_error = true; + ShowError(tr( "The wad installation failed with error %i" ), error); + } + else + WindowPrompt(tr( "Success" ), tr( "The wad file was installed" ), tr( "OK" )); + + RemoveFile(tmppath); + #else + gprintf("%s\n%s\n", realpath, tmppath); + RemoveFile(realpath); + if(!RenameFile(tmppath, realpath)) + update_error = true; + #endif + } + + if (update_choice == 2) + { + UpdateIconPng(); + UpdateMetaXml(); + UpdateGameTDB(); + DownloadAllLanguageFiles(newrev); + } + + if(update_error) + { + ShowError(tr( "Error while updating USB Loader GX." )); + return -1; + } + + if (update_choice > 0) + { + WindowPrompt(tr( "Successfully updated." ), tr( "Restarting..." ), 0, 0, 0, 0, 150); + RebootApp(); + } + + return 0; +} + +int UpdateApp() +{ + if (!IsNetworkInit() && !NetworkInitPrompt()) + { + WindowPrompt(tr("Error:"), tr("Could not initialize network!"), tr("OK")); + return -1; + } + + if (!CreateSubfolder(Settings.update_path)) + { + WindowPrompt(tr("Error:"), tr("Can't create directory"), tr("OK")); + return -1; + } + + int choice = WindowPrompt(tr( "What do you want to update?" ), 0, "USB Loader GX", tr( "WiiTDB.xml" ), tr( "Language Files" ), tr( "Cancel" )); + if(choice == 0) + return 0; + + if(choice == 1) + { + return ApplicationDownload(); + } + else if (choice == 2) + { + if(UpdateGameTDB() < 0) + { + WindowPrompt(fmt("%s", tr( "WiiTDB.xml is up to date." )), 0, tr("OK")); + return 1; + } + else + { + WindowPrompt(tr( "Successfully Updated" ), 0, tr( "OK" )); + return 1; + } + } + else if (choice == 3) + { + if(UpdateLanguageFiles() > 0) + WindowPrompt(tr( "Successfully Updated" ), 0, tr( "OK" )); + } + + return 1; +} diff --git a/source/network/update.h b/source/network/update.h new file mode 100644 index 0000000..b9e2b05 --- /dev/null +++ b/source/network/update.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2009 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * update.h + * + * Update operations + * for Wii-Xplorer 2009 + ***************************************************************************/ +#ifndef _UPDATEOPS_H_ +#define _UPDATEOPS_H_ + +int CheckUpdate(); +int CheckForBetaUpdate(); +int UpdateGameTDB(); +int UpdateApp(); + +#endif diff --git a/source/patches/bca.c b/source/patches/bca.c new file mode 100644 index 0000000..fbe87ec --- /dev/null +++ b/source/patches/bca.c @@ -0,0 +1,70 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include "mload/mload.h" +#include "mload/mload_modules.h" + +u32 do_bca_code(const char *BCAFilepath, u8 *gameid) +{ + if (!BCAFilepath || !gameid) return 0; + + if (IOS_GetVersion() == 222 || IOS_GetVersion() == 223) + { + FILE *fp; + u32 filesize; + char filepath[150]; + memset(filepath, 0, 150); + u8 bcaCode[64] ATTRIBUTE_ALIGN( 32 ); + + // Attempt to open the BCA file using the full game ID. + snprintf(filepath, sizeof(filepath), "%s%.6s.bca", BCAFilepath, gameid); + + fp = fopen(filepath, "rb"); + if (!fp) + { + // Not found. Try again without the system code or company code. + snprintf(filepath, sizeof(filepath), "%s%.3s.bca", BCAFilepath, gameid+1); + + fp = fopen(filepath, "rb"); + if (!fp) + { + // Not found. Use the default BCA. + memset(bcaCode, 0, 64); + bcaCode[0x33] = 1; + } + } + + if (fp) + { + // BCA file opened. + u32 ret = 0; + + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + + if (filesize == 64) + { + fseek(fp, 0, SEEK_SET); + ret = fread(bcaCode, 1, 64, fp); + } + fclose(fp); + + if (ret != 64) + { + // Error reading the BCA file. + // Use the default BCA. + memset(bcaCode, 0, 64); + bcaCode[0x33] = 1; + } + } + + Set_DIP_BCA_Datas(bcaCode); + } + return 0; +} diff --git a/source/patches/bca.h b/source/patches/bca.h new file mode 100644 index 0000000..cc7b3f6 --- /dev/null +++ b/source/patches/bca.h @@ -0,0 +1,15 @@ +#ifndef __BCA_H__ +#define __BCA_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + + u32 do_bca_code(const char *BCAFilepath, u8 *gameid); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/patches/codehandler.c b/source/patches/codehandler.c new file mode 100644 index 0000000..a5a80be --- /dev/null +++ b/source/patches/codehandler.c @@ -0,0 +1,277 @@ +/* + This file was autogenerated by raw2c. +Visit http://www.devkitpro.org +*/ + +const unsigned char codehandler[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x27, 0x74, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x21, 0xff, 0x58, 0x90, 0x01, 0x00, 0x08, + 0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0xac, 0x7c, 0x00, 0x00, 0x26, 0x90, 0x01, 0x00, 0x0c, + 0x7c, 0x09, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x10, 0x7c, 0x01, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x14, + 0xbc, 0x61, 0x00, 0x18, 0x7f, 0x20, 0x00, 0xa6, 0x63, 0x3a, 0x20, 0x00, 0x73, 0x5a, 0xf9, 0xff, + 0x7f, 0x40, 0x01, 0x24, 0xd8, 0x41, 0x00, 0x98, 0xd8, 0x61, 0x00, 0xa0, 0x3f, 0xe0, 0x80, 0x00, + 0x3e, 0x80, 0xcc, 0x00, 0xa3, 0x94, 0x40, 0x10, 0x63, 0x95, 0x00, 0xff, 0xb2, 0xb4, 0x40, 0x10, + 0x48, 0x00, 0x06, 0x55, 0x3a, 0xa0, 0x00, 0x00, 0x3a, 0xc0, 0x00, 0x19, 0x3a, 0xe0, 0x00, 0xd0, + 0x3f, 0x00, 0xcd, 0x00, 0x63, 0xf2, 0x27, 0x74, 0x80, 0x01, 0x00, 0xac, 0x90, 0x12, 0x00, 0x04, + 0x92, 0xb8, 0x64, 0x3c, 0x48, 0x00, 0x04, 0x2d, 0x41, 0x82, 0x05, 0xa4, 0x2c, 0x1d, 0x00, 0x04, + 0x40, 0x80, 0x00, 0x10, 0x2c, 0x1d, 0x00, 0x01, 0x41, 0x80, 0x05, 0x94, 0x48, 0x00, 0x03, 0x4c, + 0x41, 0x82, 0x04, 0xf0, 0x2c, 0x1d, 0x00, 0x06, 0x41, 0x82, 0x00, 0x8c, 0x2c, 0x1d, 0x00, 0x07, + 0x41, 0x82, 0x03, 0x30, 0x2c, 0x1d, 0x00, 0x08, 0x41, 0x82, 0x05, 0x80, 0x2c, 0x1d, 0x00, 0x09, + 0x41, 0x82, 0x00, 0xa0, 0x2c, 0x1d, 0x00, 0x10, 0x41, 0x82, 0x00, 0x98, 0x2c, 0x1d, 0x00, 0x2f, + 0x41, 0x82, 0x00, 0x70, 0x2c, 0x1d, 0x00, 0x30, 0x41, 0x82, 0x00, 0x78, 0x2c, 0x1d, 0x00, 0x38, + 0x41, 0x82, 0x05, 0x28, 0x2c, 0x1d, 0x00, 0x40, 0x41, 0x82, 0x03, 0x40, 0x2c, 0x1d, 0x00, 0x41, + 0x41, 0x82, 0x03, 0x58, 0x2c, 0x1d, 0x00, 0x44, 0x41, 0x82, 0x00, 0x68, 0x2c, 0x1d, 0x00, 0x50, + 0x41, 0x82, 0x00, 0x20, 0x2c, 0x1d, 0x00, 0x60, 0x41, 0x82, 0x00, 0x24, 0x2c, 0x1d, 0x00, 0x89, + 0x41, 0x82, 0x00, 0x50, 0x2c, 0x1d, 0x00, 0x99, 0x41, 0x82, 0x05, 0x0c, 0x48, 0x00, 0x05, 0x10, + 0x80, 0x72, 0x00, 0x00, 0x48, 0x00, 0x04, 0x29, 0x48, 0x00, 0x05, 0x04, 0x48, 0x00, 0x05, 0x89, + 0x48, 0x00, 0x04, 0xfc, 0x38, 0x80, 0x00, 0x01, 0x90, 0x92, 0x00, 0x00, 0x48, 0x00, 0x04, 0xf0, + 0x48, 0x00, 0x04, 0x09, 0x3a, 0x00, 0x00, 0xa0, 0x63, 0xec, 0x27, 0x98, 0x48, 0x00, 0x03, 0x14, + 0x38, 0x60, 0x01, 0x20, 0x63, 0xec, 0x27, 0x98, 0x48, 0x00, 0x03, 0xc9, 0x48, 0x00, 0x04, 0xd0, + 0x2f, 0x1d, 0x00, 0x10, 0x2e, 0x9d, 0x00, 0x44, 0x63, 0xe4, 0x1a, 0xb4, 0x3c, 0x60, 0x80, 0x00, + 0x60, 0x63, 0x03, 0x00, 0x48, 0x00, 0x05, 0x09, 0x38, 0x63, 0x0a, 0x00, 0x48, 0x00, 0x05, 0x01, + 0x38, 0x63, 0x06, 0x00, 0x48, 0x00, 0x04, 0xf9, 0x63, 0xec, 0x27, 0x88, 0x92, 0xac, 0x00, 0x00, + 0x92, 0xac, 0x00, 0x04, 0x92, 0xac, 0x00, 0x08, 0x63, 0xe4, 0x27, 0x98, 0x81, 0x24, 0x00, 0x18, + 0x80, 0x72, 0x00, 0x00, 0x2c, 0x03, 0x00, 0x02, 0x40, 0x82, 0x00, 0x0c, 0x41, 0x96, 0x00, 0x0c, + 0x48, 0x00, 0x00, 0x20, 0x38, 0x60, 0x00, 0x00, 0x90, 0x6c, 0x00, 0x0c, 0x40, 0x82, 0x00, 0x14, + 0x40, 0x96, 0x00, 0x10, 0x61, 0x29, 0x04, 0x00, 0x91, 0x24, 0x00, 0x18, 0x48, 0x00, 0x02, 0x14, + 0x55, 0x29, 0x05, 0xa8, 0x91, 0x24, 0x00, 0x18, 0x41, 0x96, 0x04, 0x54, 0x41, 0x9a, 0x00, 0x08, + 0x39, 0x8c, 0x00, 0x04, 0x38, 0x60, 0x00, 0x04, 0x48, 0x00, 0x03, 0x09, 0x40, 0x99, 0x00, 0x10, + 0x39, 0x8c, 0x00, 0x04, 0x38, 0x60, 0x00, 0x04, 0x48, 0x00, 0x02, 0xf9, 0x63, 0xe4, 0x27, 0x88, + 0x80, 0x64, 0x00, 0x00, 0x80, 0x84, 0x00, 0x04, 0x7c, 0x72, 0xfb, 0xa6, 0x7c, 0x95, 0xfb, 0xa6, + 0x48, 0x00, 0x04, 0x1c, 0x7c, 0x32, 0x43, 0xa6, 0x7c, 0x3a, 0x02, 0xa6, 0x7c, 0x73, 0x43, 0xa6, + 0x7c, 0x7b, 0x02, 0xa6, 0x54, 0x63, 0x05, 0xa8, 0x90, 0x60, 0x27, 0xb0, 0x54, 0x63, 0x06, 0x1e, + 0x60, 0x63, 0x20, 0x00, 0x7c, 0x7b, 0x03, 0xa6, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x1a, 0xe8, + 0x7c, 0x7a, 0x03, 0xa6, 0x4c, 0x00, 0x00, 0x64, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x27, 0x98, + 0x90, 0x23, 0x00, 0x14, 0x7c, 0x61, 0x1b, 0x78, 0x7c, 0x73, 0x42, 0xa6, 0xbc, 0x41, 0x00, 0x24, + 0x7c, 0x24, 0x0b, 0x78, 0x7c, 0x32, 0x42, 0xa6, 0x90, 0x04, 0x00, 0x1c, 0x90, 0x24, 0x00, 0x20, + 0x7c, 0x68, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x9c, 0x7c, 0x60, 0x00, 0x26, 0x90, 0x64, 0x00, 0x00, + 0x7c, 0x61, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x04, 0x7c, 0x69, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x08, + 0x7c, 0x72, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x0c, 0x7c, 0x73, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x10, + 0x39, 0x20, 0x00, 0x00, 0x7d, 0x32, 0xfb, 0xa6, 0x7d, 0x35, 0xfb, 0xa6, 0x3c, 0xa0, 0x80, 0x00, + 0x60, 0xa5, 0x1b, 0x70, 0x3f, 0xe0, 0xd0, 0x04, 0x63, 0xff, 0x00, 0xa0, 0x93, 0xe5, 0x00, 0x00, + 0x7c, 0x00, 0x28, 0x6c, 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x2f, 0xac, 0x4c, 0x00, 0x01, 0x2c, + 0xd0, 0x04, 0x00, 0xa0, 0x3b, 0xff, 0x00, 0x04, 0x3f, 0xff, 0x00, 0x20, 0x57, 0xf0, 0x01, 0x4b, + 0x41, 0x82, 0xff, 0xdc, 0x3f, 0xe0, 0x80, 0x00, 0x63, 0xe5, 0x27, 0x88, 0x82, 0x05, 0x00, 0x00, + 0x82, 0x25, 0x00, 0x04, 0x82, 0x65, 0x00, 0x0c, 0x2c, 0x13, 0x00, 0x00, 0x41, 0x82, 0x00, 0x74, + 0x2c, 0x13, 0x00, 0x02, 0x40, 0x82, 0x00, 0x18, 0x81, 0x24, 0x00, 0x14, 0x39, 0x33, 0x00, 0x03, + 0x91, 0x25, 0x00, 0x00, 0x91, 0x25, 0x00, 0x0c, 0x48, 0x00, 0x00, 0x6c, 0x7c, 0x10, 0x98, 0x00, + 0x41, 0x82, 0x00, 0x38, 0x7c, 0x11, 0x98, 0x00, 0x41, 0x82, 0x00, 0x30, 0x7d, 0x30, 0x8a, 0x14, + 0x91, 0x25, 0x00, 0x0c, 0x82, 0x05, 0x00, 0x08, 0x2c, 0x10, 0x00, 0x00, 0x41, 0x82, 0x00, 0x48, + 0x80, 0x64, 0x00, 0x10, 0x7c, 0x10, 0x18, 0x00, 0x40, 0x82, 0x00, 0x10, 0x3a, 0x00, 0x00, 0x00, + 0x92, 0x05, 0x00, 0x08, 0x48, 0x00, 0x00, 0x30, 0x3a, 0x20, 0x00, 0x00, 0x92, 0x25, 0x00, 0x0c, + 0x81, 0x24, 0x00, 0x18, 0x61, 0x29, 0x04, 0x00, 0x91, 0x24, 0x00, 0x18, 0x48, 0x00, 0x00, 0x30, + 0x7e, 0x12, 0xfb, 0xa6, 0x7e, 0x35, 0xfb, 0xa6, 0x39, 0x20, 0x00, 0x01, 0x91, 0x25, 0x00, 0x0c, + 0x48, 0x00, 0x00, 0x1c, 0x38, 0xa0, 0x00, 0x02, 0x63, 0xe4, 0x27, 0x74, 0x90, 0xa4, 0x00, 0x00, + 0x38, 0x60, 0x00, 0x11, 0x48, 0x00, 0x01, 0xb9, 0x4b, 0xff, 0xfc, 0x71, 0x7c, 0x20, 0x00, 0xa6, + 0x54, 0x21, 0x07, 0xfa, 0x54, 0x21, 0x04, 0x5e, 0x7c, 0x20, 0x01, 0x24, 0x63, 0xe1, 0x27, 0x98, + 0x80, 0x61, 0x00, 0x00, 0x7c, 0x6f, 0xf1, 0x20, 0x80, 0x61, 0x00, 0x14, 0x7c, 0x7a, 0x03, 0xa6, + 0x80, 0x61, 0x00, 0x18, 0x7c, 0x7b, 0x03, 0xa6, 0x80, 0x61, 0x00, 0x9c, 0x7c, 0x68, 0x03, 0xa6, + 0xb8, 0x41, 0x00, 0x24, 0x80, 0x01, 0x00, 0x1c, 0x80, 0x21, 0x00, 0x20, 0x4c, 0x00, 0x00, 0x64, + 0x92, 0xb2, 0x00, 0x00, 0x48, 0x00, 0x02, 0x54, 0x2e, 0x9d, 0x00, 0x02, 0x38, 0x60, 0x00, 0x08, + 0x63, 0xec, 0x27, 0x7c, 0x48, 0x00, 0x00, 0xfd, 0x80, 0xac, 0x00, 0x00, 0x80, 0x6c, 0x00, 0x04, + 0x98, 0x65, 0x00, 0x00, 0x41, 0x94, 0x00, 0x10, 0xb0, 0x65, 0x00, 0x00, 0x41, 0x96, 0x00, 0x08, + 0x90, 0x65, 0x00, 0x00, 0x7c, 0x00, 0x28, 0xac, 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x2f, 0xac, + 0x4c, 0x00, 0x01, 0x2c, 0x48, 0x00, 0x02, 0x08, 0x48, 0x00, 0x01, 0x21, 0x38, 0x60, 0x00, 0x04, + 0x63, 0xec, 0x27, 0x7c, 0x48, 0x00, 0x00, 0xbd, 0x82, 0x0c, 0x00, 0x00, 0x3d, 0x80, 0x80, 0x00, + 0x61, 0x8c, 0x28, 0xb8, 0x48, 0x00, 0x00, 0x1c, 0x48, 0x00, 0x01, 0x01, 0x38, 0x60, 0x00, 0x08, + 0x63, 0xec, 0x27, 0x7c, 0x48, 0x00, 0x00, 0x9d, 0x82, 0x0c, 0x00, 0x04, 0x81, 0x8c, 0x00, 0x00, + 0x63, 0xfb, 0x27, 0x84, 0x3a, 0x20, 0x0f, 0x80, 0x48, 0x00, 0x02, 0x39, 0x41, 0x82, 0x00, 0x20, + 0x7e, 0x23, 0x8b, 0x78, 0x48, 0x00, 0x00, 0x7d, 0x48, 0x00, 0x00, 0xd1, 0x41, 0x82, 0xff, 0xfc, + 0x7d, 0x8c, 0x72, 0x14, 0x35, 0x6b, 0xff, 0xff, 0x41, 0x81, 0xff, 0xe8, 0x80, 0x7b, 0x00, 0x00, + 0x2c, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x08, 0x48, 0x00, 0x00, 0x59, 0x7c, 0x00, 0x60, 0xac, + 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x67, 0xac, 0x4c, 0x00, 0x01, 0x2c, 0x48, 0x00, 0x01, 0x80, + 0x7f, 0xc8, 0x02, 0xa6, 0x3c, 0x60, 0xa0, 0x00, 0x48, 0x00, 0x00, 0x15, 0x76, 0x03, 0x08, 0x00, + 0x56, 0x1d, 0x86, 0x3e, 0x7f, 0xc8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x92, 0xf8, 0x68, 0x14, + 0x90, 0x78, 0x68, 0x24, 0x92, 0xd8, 0x68, 0x20, 0x80, 0xb8, 0x68, 0x20, 0x70, 0xa5, 0x00, 0x01, + 0x40, 0x82, 0xff, 0xf8, 0x82, 0x18, 0x68, 0x24, 0x90, 0xb8, 0x68, 0x14, 0x4e, 0x80, 0x00, 0x20, + 0x7d, 0x48, 0x02, 0xa6, 0x7c, 0x69, 0x03, 0xa6, 0x39, 0xc0, 0x00, 0x00, 0x48, 0x00, 0x00, 0x79, + 0x48, 0x00, 0x00, 0x75, 0x4b, 0xff, 0xff, 0xad, 0x41, 0x82, 0xff, 0xf4, 0x7f, 0xae, 0x61, 0xae, + 0x39, 0xce, 0x00, 0x01, 0x42, 0x00, 0xff, 0xe8, 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, + 0x7d, 0x48, 0x02, 0xa6, 0x7c, 0x69, 0x03, 0xa6, 0x39, 0xc0, 0x00, 0x00, 0x7c, 0x6c, 0x70, 0xae, + 0x48, 0x00, 0x00, 0x1d, 0x41, 0x82, 0xff, 0xf8, 0x39, 0xce, 0x00, 0x01, 0x42, 0x00, 0xff, 0xf0, + 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x38, 0x60, 0x00, 0xaa, 0x7f, 0xc8, 0x02, 0xa6, + 0x54, 0x63, 0xa0, 0x16, 0x64, 0x63, 0xb0, 0x00, 0x3a, 0xc0, 0x00, 0x19, 0x3a, 0xe0, 0x00, 0xd0, + 0x3f, 0x00, 0xcd, 0x00, 0x4b, 0xff, 0xff, 0x69, 0x56, 0x03, 0x37, 0xff, 0x7f, 0xc8, 0x03, 0xa6, + 0x4e, 0x80, 0x00, 0x20, 0x7f, 0xc8, 0x02, 0xa6, 0x3c, 0x60, 0xd0, 0x00, 0x4b, 0xff, 0xff, 0x51, + 0x56, 0x03, 0x37, 0xff, 0x41, 0x82, 0xff, 0xf4, 0x7f, 0xc8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, + 0x4b, 0xff, 0xff, 0xb9, 0x38, 0x60, 0x00, 0x08, 0x63, 0xec, 0x27, 0x7c, 0x4b, 0xff, 0xff, 0x55, + 0x80, 0xac, 0x00, 0x04, 0x81, 0x8c, 0x00, 0x00, 0x63, 0xfb, 0x27, 0x84, 0x62, 0xb1, 0xf8, 0x00, + 0x7e, 0x0c, 0x28, 0x50, 0x48, 0x00, 0x00, 0xed, 0x41, 0x81, 0x00, 0x10, 0x82, 0x3b, 0x00, 0x00, + 0x2c, 0x11, 0x00, 0x00, 0x41, 0x82, 0x00, 0x68, 0x7e, 0x23, 0x8b, 0x78, 0x4b, 0xff, 0xff, 0x55, + 0x4b, 0xff, 0xff, 0xa5, 0x4b, 0xff, 0xff, 0xa1, 0x4b, 0xff, 0xfe, 0xd9, 0x41, 0x82, 0xff, 0xf4, + 0x2c, 0x1d, 0x00, 0xcc, 0x41, 0x82, 0x00, 0x48, 0x2c, 0x1d, 0x00, 0xbb, 0x41, 0x82, 0xff, 0xdc, + 0x2c, 0x1d, 0x00, 0xaa, 0x40, 0x82, 0xff, 0xdc, 0x7d, 0x8c, 0x72, 0x14, 0x35, 0x6b, 0xff, 0xff, + 0x41, 0x80, 0x00, 0x2c, 0x4b, 0xff, 0xff, 0xb4, 0x7e, 0xb5, 0xfb, 0xa6, 0x7e, 0xb2, 0xfb, 0xa6, + 0x63, 0xe4, 0x27, 0x98, 0x81, 0x24, 0x00, 0x18, 0x55, 0x29, 0x05, 0xa8, 0x91, 0x24, 0x00, 0x18, + 0x48, 0x00, 0x00, 0x0c, 0x38, 0x60, 0x00, 0x80, 0x4b, 0xff, 0xff, 0x25, 0x80, 0x92, 0x00, 0x00, + 0x2c, 0x04, 0x00, 0x00, 0x40, 0x82, 0xfa, 0x50, 0xb3, 0x94, 0x40, 0x10, 0xc8, 0x41, 0x00, 0x98, + 0xc8, 0x61, 0x00, 0xa0, 0x7f, 0x20, 0x00, 0xa6, 0x80, 0x01, 0x00, 0xac, 0x7c, 0x08, 0x03, 0xa6, + 0x80, 0x01, 0x00, 0x0c, 0x7c, 0x0f, 0xf1, 0x20, 0x80, 0x01, 0x00, 0x10, 0x7c, 0x09, 0x03, 0xa6, + 0x80, 0x01, 0x00, 0x14, 0x7c, 0x01, 0x03, 0xa6, 0xb8, 0x61, 0x00, 0x18, 0x80, 0x01, 0x00, 0x08, + 0x38, 0x21, 0x00, 0xa8, 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20, 0x7e, 0x23, 0x20, 0x50, + 0x3c, 0xa0, 0x48, 0x00, 0x52, 0x25, 0x01, 0xba, 0x90, 0xa3, 0x00, 0x00, 0x7c, 0x00, 0x18, 0xac, + 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x1f, 0xac, 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20, + 0x7d, 0x70, 0x8b, 0xd7, 0x7d, 0x4b, 0x89, 0xd6, 0x7d, 0x4a, 0x80, 0x50, 0x91, 0x5b, 0x00, 0x00, + 0x4e, 0x80, 0x00, 0x20, 0x7f, 0xa8, 0x02, 0xa6, 0x3d, 0xe0, 0x80, 0x00, 0x61, 0xef, 0x28, 0xb8, + 0x63, 0xe7, 0x18, 0x08, 0x3c, 0xc0, 0x80, 0x00, 0x7c, 0xd0, 0x33, 0x78, 0x39, 0x00, 0x00, 0x00, + 0x3c, 0x60, 0x00, 0xd0, 0x60, 0x63, 0xc0, 0xde, 0x80, 0x8f, 0x00, 0x00, 0x7c, 0x03, 0x20, 0x00, + 0x40, 0x82, 0x00, 0x18, 0x80, 0x8f, 0x00, 0x04, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x0c, + 0x39, 0xef, 0x00, 0x08, 0x48, 0x00, 0x00, 0x0c, 0x7f, 0xa8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, + 0x80, 0x6f, 0x00, 0x00, 0x80, 0x8f, 0x00, 0x04, 0x39, 0xef, 0x00, 0x08, 0x71, 0x09, 0x00, 0x01, + 0x2f, 0x89, 0x00, 0x00, 0x39, 0x20, 0x00, 0x00, 0x54, 0x6a, 0x1f, 0x7e, 0x54, 0x65, 0x3f, 0x7e, + 0x74, 0x6b, 0x10, 0x00, 0x54, 0x63, 0x01, 0xfe, 0x40, 0x82, 0x00, 0x0c, 0x54, 0xcc, 0x00, 0x0c, + 0x48, 0x00, 0x00, 0x08, 0x7e, 0x0c, 0x83, 0x78, 0x2e, 0x05, 0x00, 0x00, 0x2c, 0x0a, 0x00, 0x01, + 0x41, 0xa0, 0x00, 0x2c, 0x41, 0xa2, 0x00, 0xe4, 0x2c, 0x0a, 0x00, 0x03, 0x41, 0xa0, 0x01, 0xac, + 0x41, 0x82, 0x02, 0x50, 0x2c, 0x0a, 0x00, 0x05, 0x41, 0x80, 0x02, 0xd4, 0x41, 0xa2, 0x04, 0xe0, + 0x2c, 0x0a, 0x00, 0x07, 0x41, 0xa0, 0x05, 0x0c, 0x48, 0x00, 0x05, 0xf0, 0x7d, 0x8c, 0x1a, 0x14, + 0x2c, 0x05, 0x00, 0x03, 0x41, 0x82, 0x00, 0x48, 0x41, 0x81, 0x00, 0x60, 0x40, 0xbe, 0xff, 0x84, + 0x2e, 0x05, 0x00, 0x01, 0x41, 0x91, 0x00, 0x2c, 0x54, 0x8a, 0x84, 0x3e, 0x41, 0x92, 0x00, 0x10, + 0x7c, 0x89, 0x61, 0xae, 0x39, 0x29, 0x00, 0x01, 0x48, 0x00, 0x00, 0x0c, 0x7c, 0x89, 0x63, 0x2e, + 0x39, 0x29, 0x00, 0x02, 0x35, 0x4a, 0xff, 0xff, 0x40, 0xa0, 0xff, 0xe4, 0x4b, 0xff, 0xff, 0x54, + 0x55, 0x8c, 0x00, 0x3a, 0x90, 0x8c, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x48, 0x7c, 0x89, 0x23, 0x78, + 0x40, 0x9e, 0x04, 0xc8, 0x35, 0x29, 0xff, 0xff, 0x41, 0x80, 0x04, 0xc0, 0x7c, 0xa9, 0x78, 0xae, + 0x7c, 0xa9, 0x61, 0xae, 0x4b, 0xff, 0xff, 0xf0, 0x39, 0xef, 0x00, 0x08, 0x40, 0xbe, 0xff, 0x24, + 0x80, 0xaf, 0xff, 0xf8, 0x81, 0x6f, 0xff, 0xfc, 0x54, 0xb1, 0x04, 0x3e, 0x54, 0xaa, 0x85, 0x3e, + 0x54, 0xa5, 0x27, 0x3e, 0x2e, 0x85, 0x00, 0x01, 0x41, 0x96, 0x00, 0x10, 0x41, 0xb5, 0x00, 0x14, + 0x7c, 0x89, 0x61, 0xae, 0x48, 0x00, 0x00, 0x10, 0x7c, 0x89, 0x63, 0x2e, 0x48, 0x00, 0x00, 0x08, + 0x7c, 0x89, 0x61, 0x2e, 0x7c, 0x84, 0x5a, 0x14, 0x7d, 0x29, 0x8a, 0x14, 0x35, 0x4a, 0xff, 0xff, + 0x40, 0x80, 0xff, 0xd4, 0x4b, 0xff, 0xfe, 0xdc, 0x54, 0x69, 0x07, 0xff, 0x41, 0x82, 0x00, 0x10, + 0x55, 0x08, 0xf8, 0x7e, 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00, 0x2e, 0x85, 0x00, 0x04, + 0x2d, 0x8a, 0x00, 0x05, 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x78, 0x41, 0x8d, 0x04, 0xb8, + 0x7d, 0x8c, 0x1a, 0x14, 0x41, 0x8c, 0x00, 0x0c, 0x41, 0x94, 0x00, 0x30, 0x48, 0x00, 0x00, 0x1c, + 0x40, 0x94, 0x00, 0x10, 0x55, 0x8c, 0x00, 0x3a, 0x81, 0x6c, 0x00, 0x00, 0x48, 0x00, 0x00, 0x1c, + 0x55, 0x8c, 0x00, 0x3c, 0xa1, 0x6c, 0x00, 0x00, 0x7c, 0x89, 0x20, 0xf8, 0x55, 0x29, 0x84, 0x3e, + 0x7d, 0x6b, 0x48, 0x38, 0x54, 0x84, 0x04, 0x3e, 0x7f, 0x0b, 0x20, 0x40, 0x70, 0xa9, 0x00, 0x03, + 0x41, 0x82, 0x00, 0x18, 0x2c, 0x09, 0x00, 0x02, 0x41, 0x82, 0x00, 0x18, 0x41, 0x81, 0x00, 0x1c, + 0x40, 0x9a, 0x00, 0x20, 0x48, 0x00, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x18, 0x48, 0x00, 0x00, 0x10, + 0x41, 0x99, 0x00, 0x10, 0x48, 0x00, 0x00, 0x08, 0x41, 0x98, 0x00, 0x08, 0x61, 0x08, 0x00, 0x01, + 0x40, 0x8e, 0xfe, 0x40, 0x41, 0x94, 0xfe, 0x3c, 0x81, 0x6f, 0xff, 0xf8, 0x40, 0x9e, 0x00, 0x20, + 0x70, 0x6c, 0x00, 0x08, 0x41, 0x82, 0x00, 0x0c, 0x71, 0x0c, 0x00, 0x01, 0x41, 0x82, 0x00, 0x10, + 0x39, 0x8b, 0x00, 0x10, 0x51, 0x8b, 0x03, 0x36, 0x48, 0x00, 0x00, 0x08, 0x55, 0x6b, 0x07, 0x16, + 0x91, 0x6f, 0xff, 0xf8, 0x4b, 0xff, 0xfe, 0x0c, 0x40, 0xbe, 0xfe, 0x08, 0x54, 0x69, 0x16, 0xba, + 0x54, 0x6e, 0x87, 0xfe, 0x2d, 0x8e, 0x00, 0x00, 0x2e, 0x05, 0x00, 0x04, 0x70, 0xae, 0x00, 0x03, + 0x2e, 0x8e, 0x00, 0x02, 0x41, 0x94, 0x00, 0x14, 0x41, 0x96, 0x00, 0x50, 0x7c, 0x64, 0x07, 0x34, + 0x7c, 0x84, 0x7a, 0x14, 0x48, 0x00, 0x00, 0x68, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, + 0x7d, 0x27, 0x48, 0x2e, 0x7c, 0x84, 0x4a, 0x14, 0x41, 0x8e, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14, + 0x2e, 0x8e, 0x00, 0x01, 0x41, 0x96, 0x00, 0x08, 0x80, 0x84, 0x00, 0x00, 0x54, 0x63, 0x67, 0xff, + 0x41, 0x82, 0x00, 0x3c, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0x84, 0x32, 0x14, 0x48, 0x00, 0x00, 0x30, + 0x7c, 0x84, 0x82, 0x14, 0x48, 0x00, 0x00, 0x28, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, + 0x7d, 0x27, 0x48, 0x2e, 0x7c, 0x84, 0x4a, 0x14, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0xcc, 0x21, 0x2e, + 0x4b, 0xff, 0xfd, 0x80, 0x7e, 0x0c, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x78, 0x40, 0x90, 0x00, 0x0c, + 0x7c, 0x86, 0x23, 0x78, 0x4b, 0xff, 0xfd, 0x6c, 0x7c, 0x90, 0x23, 0x78, 0x4b, 0xff, 0xfd, 0x64, + 0x54, 0x89, 0x1e, 0x78, 0x39, 0x29, 0x00, 0x40, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x80, 0x00, 0x48, + 0x54, 0x6b, 0x50, 0x03, 0x41, 0x82, 0x00, 0x14, 0x41, 0x81, 0x00, 0x08, 0x48, 0x00, 0x00, 0x10, + 0x41, 0xbe, 0xfd, 0x40, 0x48, 0x00, 0x00, 0x08, 0x40, 0xbe, 0xfd, 0x38, 0x2c, 0x05, 0x00, 0x03, + 0x41, 0x81, 0x00, 0x10, 0x41, 0xa2, 0x00, 0x10, 0x7d, 0xe7, 0x48, 0x2e, 0x4b, 0xff, 0xfd, 0x24, + 0x7d, 0xe7, 0x49, 0x2e, 0x7c, 0x64, 0x07, 0x34, 0x54, 0x84, 0x1a, 0x78, 0x7d, 0xef, 0x22, 0x14, + 0x4b, 0xff, 0xfd, 0x10, 0x40, 0xbe, 0xfd, 0x0c, 0x7c, 0xa7, 0x4a, 0x14, 0x40, 0x92, 0x00, 0x14, + 0x54, 0x64, 0x04, 0x3e, 0x91, 0xe5, 0x00, 0x00, 0x90, 0x85, 0x00, 0x04, 0x4b, 0xff, 0xfc, 0xf4, + 0x81, 0x25, 0x00, 0x04, 0x2c, 0x09, 0x00, 0x00, 0x41, 0xa2, 0xfc, 0xe8, 0x39, 0x29, 0xff, 0xff, + 0x91, 0x25, 0x00, 0x04, 0x81, 0xe5, 0x00, 0x00, 0x4b, 0xff, 0xfc, 0xd8, 0x40, 0xbe, 0xfc, 0xd4, + 0x54, 0x6b, 0x16, 0xba, 0x7f, 0x47, 0x5a, 0x14, 0x81, 0x3a, 0x00, 0x00, 0x54, 0x6e, 0x67, 0xbe, + 0x41, 0x92, 0x00, 0x84, 0x2e, 0x05, 0x00, 0x05, 0x40, 0x90, 0x01, 0x74, 0x2e, 0x05, 0x00, 0x03, + 0x40, 0x90, 0x00, 0x90, 0x2e, 0x05, 0x00, 0x01, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, + 0x7c, 0x8c, 0x22, 0x14, 0x2f, 0x0e, 0x00, 0x01, 0x40, 0x92, 0x00, 0x24, 0x41, 0xb9, 0x00, 0x18, + 0x41, 0x9a, 0x00, 0x0c, 0x88, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf8, 0xa0, 0x84, 0x00, 0x00, + 0x48, 0x00, 0x00, 0xf0, 0x80, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xe8, 0x54, 0x73, 0xe5, 0x3e, + 0x41, 0xb9, 0x00, 0x20, 0x41, 0x9a, 0x00, 0x10, 0x99, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x01, + 0x48, 0x00, 0x00, 0x18, 0xb1, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x02, 0x48, 0x00, 0x00, 0x0c, + 0x91, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x04, 0x36, 0x73, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4, + 0x4b, 0xff, 0xfc, 0x40, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, 0x7c, 0x84, 0x62, 0x14, + 0x71, 0xc5, 0x00, 0x01, 0x41, 0x82, 0x00, 0x9c, 0x7c, 0x84, 0x4a, 0x14, 0x48, 0x00, 0x00, 0x94, + 0x54, 0x6a, 0x87, 0xbe, 0x54, 0x8e, 0x16, 0xba, 0x7e, 0x67, 0x72, 0x14, 0x40, 0x92, 0x00, 0x08, + 0x3a, 0x6f, 0xff, 0xfc, 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00, 0x71, 0x4b, 0x00, 0x01, + 0x41, 0x82, 0x00, 0x08, 0x7c, 0x9a, 0x23, 0x78, 0x71, 0x4b, 0x00, 0x02, 0x41, 0x82, 0x00, 0x10, + 0x7d, 0x33, 0x4b, 0x78, 0x40, 0xb2, 0x00, 0x08, 0x7e, 0x6c, 0x9a, 0x14, 0x54, 0x65, 0x67, 0x3f, + 0x2c, 0x05, 0x00, 0x09, 0x40, 0x80, 0x00, 0x54, 0x48, 0x00, 0x00, 0x79, 0x7c, 0x89, 0x22, 0x14, + 0x48, 0x00, 0x00, 0x40, 0x7c, 0x89, 0x21, 0xd6, 0x48, 0x00, 0x00, 0x38, 0x7d, 0x24, 0x23, 0x78, + 0x48, 0x00, 0x00, 0x30, 0x7d, 0x24, 0x20, 0x38, 0x48, 0x00, 0x00, 0x28, 0x7d, 0x24, 0x22, 0x78, + 0x48, 0x00, 0x00, 0x20, 0x7d, 0x24, 0x20, 0x30, 0x48, 0x00, 0x00, 0x18, 0x7d, 0x24, 0x24, 0x30, + 0x48, 0x00, 0x00, 0x10, 0x5d, 0x24, 0x20, 0x3e, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x24, 0x26, 0x30, + 0x90, 0x9a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x8c, 0x2c, 0x05, 0x00, 0x0a, 0x41, 0x81, 0xfb, 0x84, + 0xc0, 0x5a, 0x00, 0x00, 0xc0, 0x73, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0c, 0xec, 0x43, 0x10, 0x2a, + 0x48, 0x00, 0x00, 0x08, 0xec, 0x43, 0x00, 0xb2, 0xd0, 0x5a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x64, + 0x7d, 0x48, 0x02, 0xa6, 0x54, 0xa5, 0x1e, 0x78, 0x7d, 0x4a, 0x2a, 0x14, 0x80, 0x9a, 0x00, 0x00, + 0x81, 0x33, 0x00, 0x00, 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x40, 0xbe, 0xfb, 0x44, + 0x54, 0x69, 0xc0, 0x3e, 0x7d, 0x8e, 0x63, 0x78, 0x48, 0x00, 0x00, 0x35, 0x41, 0x92, 0x00, 0x0c, + 0x7e, 0x31, 0x22, 0x14, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x29, 0x22, 0x14, 0x54, 0x64, 0xc4, 0x3f, + 0x38, 0xa0, 0x00, 0x00, 0x41, 0x82, 0xfb, 0x1c, 0x7d, 0x45, 0x88, 0xae, 0x7d, 0x45, 0x49, 0xae, + 0x38, 0xa5, 0x00, 0x01, 0x7c, 0x05, 0x20, 0x00, 0x4b, 0xff, 0xff, 0xec, 0x2e, 0x8a, 0x00, 0x04, + 0x55, 0x31, 0x36, 0xba, 0x2c, 0x11, 0x00, 0x3c, 0x7e, 0x27, 0x88, 0x2e, 0x40, 0x82, 0x00, 0x08, + 0x7d, 0xd1, 0x73, 0x78, 0x41, 0x96, 0x00, 0x08, 0xa2, 0x31, 0x00, 0x00, 0x55, 0x29, 0x56, 0xba, + 0x2c, 0x09, 0x00, 0x3c, 0x7d, 0x27, 0x48, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xc9, 0x73, 0x78, + 0x41, 0x96, 0x00, 0x08, 0xa1, 0x29, 0x00, 0x00, 0x4e, 0x80, 0x00, 0x20, 0x2c, 0x05, 0x00, 0x04, + 0x40, 0x80, 0x00, 0x28, 0x7c, 0x89, 0x23, 0x78, 0x7d, 0xc3, 0x62, 0x14, 0x55, 0xce, 0x00, 0x3c, + 0x4b, 0xff, 0xff, 0xad, 0x7c, 0x84, 0x20, 0xf8, 0x54, 0x84, 0x04, 0x3e, 0x7d, 0x2b, 0x20, 0x38, + 0x7e, 0x24, 0x20, 0x38, 0x4b, 0xff, 0xfb, 0xc4, 0x54, 0x6b, 0xe4, 0x3e, 0x4b, 0xff, 0xfb, 0xbc, + 0x7c, 0x9a, 0x23, 0x78, 0x54, 0x84, 0x18, 0x38, 0x40, 0x92, 0x00, 0x20, 0x40, 0x9e, 0x00, 0x0c, + 0x7d, 0xe8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x21, 0x7d, 0xe4, 0x7a, 0x14, 0x39, 0xef, 0x00, 0x07, + 0x55, 0xef, 0x00, 0x38, 0x4b, 0xff, 0xfa, 0x6c, 0x2e, 0x05, 0x00, 0x03, 0x41, 0x91, 0x00, 0x5c, + 0x3c, 0xa0, 0x48, 0x00, 0x7d, 0x83, 0x62, 0x14, 0x55, 0x8c, 0x00, 0x3a, 0x40, 0x92, 0x00, 0x20, + 0x40, 0xbe, 0xfa, 0x50, 0x57, 0x44, 0x00, 0x3a, 0x7c, 0x8c, 0x20, 0x50, 0x50, 0x85, 0x01, 0xba, + 0x50, 0x65, 0x07, 0xfe, 0x90, 0xac, 0x00, 0x00, 0x4b, 0xff, 0xfa, 0x38, 0x40, 0xbe, 0xff, 0xbc, + 0x7d, 0x2c, 0x78, 0x50, 0x51, 0x25, 0x01, 0xba, 0x90, 0xac, 0x00, 0x00, 0x39, 0x8c, 0x00, 0x04, + 0x7d, 0x6f, 0x22, 0x14, 0x39, 0x6b, 0xff, 0xfc, 0x7d, 0x2b, 0x60, 0x50, 0x51, 0x25, 0x01, 0xba, + 0x90, 0xab, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x94, 0x2e, 0x05, 0x00, 0x06, 0x41, 0x92, 0x00, 0x28, + 0x4b, 0xff, 0xfb, 0x28, 0x55, 0x8c, 0x84, 0x3e, 0x57, 0x44, 0x84, 0x3e, 0x57, 0x5a, 0x04, 0x3e, + 0x7c, 0x0c, 0x20, 0x00, 0x41, 0x80, 0xfb, 0xa8, 0x7c, 0x0c, 0xd0, 0x00, 0x40, 0x80, 0xfb, 0xa0, + 0x4b, 0xff, 0xf9, 0xe0, 0x57, 0x45, 0xff, 0xfe, 0x68, 0xa5, 0x00, 0x01, 0x71, 0x03, 0x00, 0x01, + 0x7c, 0x05, 0x18, 0x00, 0x41, 0x82, 0x00, 0x1c, 0x51, 0x1a, 0x0f, 0xbc, 0x6b, 0x5a, 0x00, 0x02, + 0x57, 0x45, 0xff, 0xff, 0x41, 0x82, 0x00, 0x08, 0x6b, 0x5a, 0x00, 0x01, 0x93, 0x4f, 0xff, 0xfc, + 0x53, 0x48, 0x07, 0xfe, 0x4b, 0xff, 0xf9, 0xac, 0x2c, 0x0b, 0x00, 0x00, 0x41, 0x82, 0x01, 0x38, + 0x2c, 0x05, 0x00, 0x01, 0x41, 0x82, 0x00, 0x18, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x82, 0x00, 0x14, + 0x2c, 0x05, 0x00, 0x03, 0x41, 0x82, 0x00, 0x70, 0x4b, 0xff, 0xf9, 0x80, 0x54, 0xcc, 0x00, 0x0c, + 0x54, 0x97, 0x46, 0x3e, 0x54, 0x98, 0xc4, 0x3e, 0x54, 0x84, 0x06, 0x3e, 0x40, 0x9e, 0x00, 0xfc, + 0x56, 0xf9, 0x06, 0x31, 0x7d, 0x9a, 0x63, 0x78, 0x7f, 0x43, 0xd2, 0x14, 0x57, 0x5a, 0x00, 0x3a, + 0x41, 0x82, 0x00, 0x18, 0x7e, 0xf7, 0x07, 0x74, 0x7e, 0xf7, 0x00, 0xd0, 0x1f, 0x37, 0x00, 0x02, + 0x3b, 0x39, 0x00, 0x04, 0x7f, 0x59, 0xd0, 0x50, 0x2c, 0x17, 0x00, 0x00, 0x41, 0x82, 0x00, 0x1c, + 0x3b, 0x20, 0x00, 0x00, 0x7e, 0xe9, 0x03, 0xa6, 0xa3, 0x7a, 0x00, 0x04, 0x7f, 0x79, 0xca, 0x78, + 0x3b, 0x5a, 0x00, 0x02, 0x42, 0x00, 0xff, 0xf4, 0x7c, 0x18, 0xc8, 0x00, 0x40, 0x82, 0x00, 0xac, + 0x4b, 0xff, 0xfe, 0x90, 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x9c, 0x54, 0x77, 0xb0, 0x03, + 0x41, 0x81, 0x00, 0x88, 0x41, 0x80, 0x00, 0x8c, 0x54, 0x7e, 0x06, 0x3e, 0x1f, 0xde, 0x00, 0x02, + 0x54, 0x97, 0x00, 0x1e, 0x6e, 0xf8, 0x80, 0x00, 0x2c, 0x18, 0x00, 0x00, 0x40, 0x82, 0x00, 0x08, + 0x62, 0xf7, 0x30, 0x00, 0x54, 0x98, 0x80, 0x1e, 0x1f, 0x3e, 0x00, 0x04, 0x7f, 0x19, 0xc0, 0x50, + 0x3b, 0x20, 0x00, 0x00, 0x1f, 0x59, 0x00, 0x04, 0x7f, 0x6f, 0xd0, 0x2e, 0x7f, 0x57, 0xd0, 0x2e, + 0x3b, 0x39, 0x00, 0x01, 0x7c, 0x17, 0xc0, 0x40, 0x41, 0x81, 0x00, 0x34, 0x7c, 0x19, 0xf0, 0x00, + 0x41, 0x81, 0x00, 0x14, 0x7c, 0x1a, 0xd8, 0x00, 0x41, 0x82, 0xff, 0xdc, 0x3a, 0xf7, 0x00, 0x04, + 0x4b, 0xff, 0xff, 0xd0, 0x80, 0x6f, 0xff, 0xf8, 0x60, 0x63, 0x03, 0x00, 0x90, 0x6f, 0xff, 0xf8, + 0x92, 0xef, 0xff, 0xfc, 0x7e, 0xf0, 0xbb, 0x78, 0x48, 0x00, 0x00, 0x1c, 0x80, 0x6f, 0xff, 0xf8, + 0x60, 0x63, 0x01, 0x00, 0x90, 0x6f, 0xff, 0xf8, 0x61, 0x08, 0x00, 0x01, 0x48, 0x00, 0x00, 0x08, + 0x7c, 0x90, 0x23, 0x78, 0x54, 0x64, 0x06, 0x3e, 0x1c, 0x84, 0x00, 0x08, 0x7d, 0xe4, 0x7a, 0x14, + 0x4b, 0xff, 0xf8, 0x70, 0x40, 0x92, 0x00, 0x0c, 0x39, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x14, + 0x54, 0x69, 0x06, 0xff, 0x54, 0x65, 0x67, 0xfe, 0x7d, 0x08, 0x4c, 0x30, 0x55, 0x17, 0xff, 0xff, + 0x40, 0x82, 0x00, 0x08, 0x7d, 0x08, 0x2a, 0x78, 0x54, 0x85, 0x00, 0x1f, 0x41, 0x82, 0x00, 0x08, + 0x7c, 0xa6, 0x2b, 0x78, 0x54, 0x85, 0x80, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xb0, 0x2b, 0x78, + 0x4b, 0xff, 0xf8, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +}; +const int codehandler_size = sizeof(codehandler); diff --git a/source/patches/codehandler.h b/source/patches/codehandler.h new file mode 100644 index 0000000..08b069d --- /dev/null +++ b/source/patches/codehandler.h @@ -0,0 +1,14 @@ +/* + This file was autogenerated by raw2c. +Visit http://www.devkitpro.org +*/ + +//--------------------------------------------------------------------------------- +#ifndef _codehandler_h_ +#define _codehandler_h_ +//--------------------------------------------------------------------------------- +extern const unsigned char codehandler[]; +extern const int codehandler_size; +//--------------------------------------------------------------------------------- +#endif //_codehandler_h_ +//--------------------------------------------------------------------------------- diff --git a/source/patches/codehandleronly.h b/source/patches/codehandleronly.h new file mode 100644 index 0000000..d125bae --- /dev/null +++ b/source/patches/codehandleronly.h @@ -0,0 +1,180 @@ +/* + This file was autogenerated by raw2c. +Visit http://www.devkitpro.org +*/ + +const unsigned char codehandleronly[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x21, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x21, 0xff, 0x58, 0x90, 0x01, 0x00, 0x08, + 0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0xac, 0x7c, 0x00, 0x00, 0x26, 0x90, 0x01, 0x00, 0x0c, + 0x7c, 0x09, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x10, 0x7c, 0x01, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x14, + 0xbc, 0x61, 0x00, 0x18, 0x7f, 0x20, 0x00, 0xa6, 0x63, 0x3a, 0x20, 0x00, 0x73, 0x5a, 0xf9, 0xff, + 0x7f, 0x40, 0x01, 0x24, 0xd8, 0x41, 0x00, 0x98, 0xd8, 0x61, 0x00, 0xa0, 0x3f, 0xe0, 0x80, 0x00, + 0x3e, 0x80, 0xcc, 0x00, 0xa3, 0x94, 0x40, 0x10, 0x63, 0x95, 0x00, 0xff, 0xb2, 0xb4, 0x40, 0x10, + 0x7f, 0xa8, 0x02, 0xa6, 0x3d, 0xe0, 0x80, 0x00, 0x61, 0xef, 0x22, 0xa8, 0x63, 0xe7, 0x18, 0x08, + 0x3c, 0xc0, 0x80, 0x00, 0x7c, 0xd0, 0x33, 0x78, 0x39, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x00, 0xd0, + 0x60, 0x63, 0xc0, 0xde, 0x80, 0x8f, 0x00, 0x00, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x18, + 0x80, 0x8f, 0x00, 0x04, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x0c, 0x39, 0xef, 0x00, 0x08, + 0x48, 0x00, 0x00, 0x4c, 0x7f, 0xa8, 0x03, 0xa6, 0xb3, 0x94, 0x40, 0x10, 0xc8, 0x41, 0x00, 0x98, + 0xc8, 0x61, 0x00, 0xa0, 0x7f, 0x20, 0x00, 0xa6, 0x80, 0x01, 0x00, 0xac, 0x7c, 0x08, 0x03, 0xa6, + 0x80, 0x01, 0x00, 0x0c, 0x7c, 0x0f, 0xf1, 0x20, 0x80, 0x01, 0x00, 0x10, 0x7c, 0x09, 0x03, 0xa6, + 0x80, 0x01, 0x00, 0x14, 0x7c, 0x01, 0x03, 0xa6, 0xb8, 0x61, 0x00, 0x18, 0x80, 0x01, 0x00, 0x08, + 0x38, 0x21, 0x00, 0xa8, 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20, 0x80, 0x6f, 0x00, 0x00, + 0x80, 0x8f, 0x00, 0x04, 0x39, 0xef, 0x00, 0x08, 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00, + 0x39, 0x20, 0x00, 0x00, 0x54, 0x6a, 0x1f, 0x7e, 0x54, 0x65, 0x3f, 0x7e, 0x74, 0x6b, 0x10, 0x00, + 0x54, 0x63, 0x01, 0xfe, 0x40, 0x82, 0x00, 0x0c, 0x54, 0xcc, 0x00, 0x0c, 0x48, 0x00, 0x00, 0x08, + 0x7e, 0x0c, 0x83, 0x78, 0x2e, 0x05, 0x00, 0x00, 0x2c, 0x0a, 0x00, 0x01, 0x41, 0xa0, 0x00, 0x2c, + 0x41, 0xa2, 0x00, 0xe4, 0x2c, 0x0a, 0x00, 0x03, 0x41, 0xa0, 0x01, 0xac, 0x41, 0x82, 0x02, 0x50, + 0x2c, 0x0a, 0x00, 0x05, 0x41, 0x80, 0x02, 0xd4, 0x41, 0xa2, 0x04, 0xe0, 0x2c, 0x0a, 0x00, 0x07, + 0x41, 0xa0, 0x05, 0x0c, 0x48, 0x00, 0x05, 0xf0, 0x7d, 0x8c, 0x1a, 0x14, 0x2c, 0x05, 0x00, 0x03, + 0x41, 0x82, 0x00, 0x48, 0x41, 0x81, 0x00, 0x60, 0x40, 0xbe, 0xff, 0x84, 0x2e, 0x05, 0x00, 0x01, + 0x41, 0x91, 0x00, 0x2c, 0x54, 0x8a, 0x84, 0x3e, 0x41, 0x92, 0x00, 0x10, 0x7c, 0x89, 0x61, 0xae, + 0x39, 0x29, 0x00, 0x01, 0x48, 0x00, 0x00, 0x0c, 0x7c, 0x89, 0x63, 0x2e, 0x39, 0x29, 0x00, 0x02, + 0x35, 0x4a, 0xff, 0xff, 0x40, 0xa0, 0xff, 0xe4, 0x4b, 0xff, 0xff, 0x54, 0x55, 0x8c, 0x00, 0x3a, + 0x90, 0x8c, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x48, 0x7c, 0x89, 0x23, 0x78, 0x40, 0x9e, 0x04, 0xc8, + 0x35, 0x29, 0xff, 0xff, 0x41, 0x80, 0x04, 0xc0, 0x7c, 0xa9, 0x78, 0xae, 0x7c, 0xa9, 0x61, 0xae, + 0x4b, 0xff, 0xff, 0xf0, 0x39, 0xef, 0x00, 0x08, 0x40, 0xbe, 0xff, 0x24, 0x80, 0xaf, 0xff, 0xf8, + 0x81, 0x6f, 0xff, 0xfc, 0x54, 0xb1, 0x04, 0x3e, 0x54, 0xaa, 0x85, 0x3e, 0x54, 0xa5, 0x27, 0x3e, + 0x2e, 0x85, 0x00, 0x01, 0x41, 0x96, 0x00, 0x10, 0x41, 0xb5, 0x00, 0x14, 0x7c, 0x89, 0x61, 0xae, + 0x48, 0x00, 0x00, 0x10, 0x7c, 0x89, 0x63, 0x2e, 0x48, 0x00, 0x00, 0x08, 0x7c, 0x89, 0x61, 0x2e, + 0x7c, 0x84, 0x5a, 0x14, 0x7d, 0x29, 0x8a, 0x14, 0x35, 0x4a, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4, + 0x4b, 0xff, 0xfe, 0xdc, 0x54, 0x69, 0x07, 0xff, 0x41, 0x82, 0x00, 0x10, 0x55, 0x08, 0xf8, 0x7e, + 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00, 0x2e, 0x85, 0x00, 0x04, 0x2d, 0x8a, 0x00, 0x05, + 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x78, 0x41, 0x8d, 0x04, 0xb8, 0x7d, 0x8c, 0x1a, 0x14, + 0x41, 0x8c, 0x00, 0x0c, 0x41, 0x94, 0x00, 0x30, 0x48, 0x00, 0x00, 0x1c, 0x40, 0x94, 0x00, 0x10, + 0x55, 0x8c, 0x00, 0x3a, 0x81, 0x6c, 0x00, 0x00, 0x48, 0x00, 0x00, 0x1c, 0x55, 0x8c, 0x00, 0x3c, + 0xa1, 0x6c, 0x00, 0x00, 0x7c, 0x89, 0x20, 0xf8, 0x55, 0x29, 0x84, 0x3e, 0x7d, 0x6b, 0x48, 0x38, + 0x54, 0x84, 0x04, 0x3e, 0x7f, 0x0b, 0x20, 0x40, 0x70, 0xa9, 0x00, 0x03, 0x41, 0x82, 0x00, 0x18, + 0x2c, 0x09, 0x00, 0x02, 0x41, 0x82, 0x00, 0x18, 0x41, 0x81, 0x00, 0x1c, 0x40, 0x9a, 0x00, 0x20, + 0x48, 0x00, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x18, 0x48, 0x00, 0x00, 0x10, 0x41, 0x99, 0x00, 0x10, + 0x48, 0x00, 0x00, 0x08, 0x41, 0x98, 0x00, 0x08, 0x61, 0x08, 0x00, 0x01, 0x40, 0x8e, 0xfe, 0x40, + 0x41, 0x94, 0xfe, 0x3c, 0x81, 0x6f, 0xff, 0xf8, 0x40, 0x9e, 0x00, 0x20, 0x70, 0x6c, 0x00, 0x08, + 0x41, 0x82, 0x00, 0x0c, 0x71, 0x0c, 0x00, 0x01, 0x41, 0x82, 0x00, 0x10, 0x39, 0x8b, 0x00, 0x10, + 0x51, 0x8b, 0x03, 0x36, 0x48, 0x00, 0x00, 0x08, 0x55, 0x6b, 0x07, 0x16, 0x91, 0x6f, 0xff, 0xf8, + 0x4b, 0xff, 0xfe, 0x0c, 0x40, 0xbe, 0xfe, 0x08, 0x54, 0x69, 0x16, 0xba, 0x54, 0x6e, 0x87, 0xfe, + 0x2d, 0x8e, 0x00, 0x00, 0x2e, 0x05, 0x00, 0x04, 0x70, 0xae, 0x00, 0x03, 0x2e, 0x8e, 0x00, 0x02, + 0x41, 0x94, 0x00, 0x14, 0x41, 0x96, 0x00, 0x50, 0x7c, 0x64, 0x07, 0x34, 0x7c, 0x84, 0x7a, 0x14, + 0x48, 0x00, 0x00, 0x68, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, 0x7d, 0x27, 0x48, 0x2e, + 0x7c, 0x84, 0x4a, 0x14, 0x41, 0x8e, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14, 0x2e, 0x8e, 0x00, 0x01, + 0x41, 0x96, 0x00, 0x08, 0x80, 0x84, 0x00, 0x00, 0x54, 0x63, 0x67, 0xff, 0x41, 0x82, 0x00, 0x3c, + 0x40, 0x90, 0x00, 0x0c, 0x7c, 0x84, 0x32, 0x14, 0x48, 0x00, 0x00, 0x30, 0x7c, 0x84, 0x82, 0x14, + 0x48, 0x00, 0x00, 0x28, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, 0x7d, 0x27, 0x48, 0x2e, + 0x7c, 0x84, 0x4a, 0x14, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0xcc, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x80, + 0x7e, 0x0c, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x78, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0x86, 0x23, 0x78, + 0x4b, 0xff, 0xfd, 0x6c, 0x7c, 0x90, 0x23, 0x78, 0x4b, 0xff, 0xfd, 0x64, 0x54, 0x89, 0x1e, 0x78, + 0x39, 0x29, 0x00, 0x40, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x80, 0x00, 0x48, 0x54, 0x6b, 0x50, 0x03, + 0x41, 0x82, 0x00, 0x14, 0x41, 0x81, 0x00, 0x08, 0x48, 0x00, 0x00, 0x10, 0x41, 0xbe, 0xfd, 0x40, + 0x48, 0x00, 0x00, 0x08, 0x40, 0xbe, 0xfd, 0x38, 0x2c, 0x05, 0x00, 0x03, 0x41, 0x81, 0x00, 0x10, + 0x41, 0xa2, 0x00, 0x10, 0x7d, 0xe7, 0x48, 0x2e, 0x4b, 0xff, 0xfd, 0x24, 0x7d, 0xe7, 0x49, 0x2e, + 0x7c, 0x64, 0x07, 0x34, 0x54, 0x84, 0x1a, 0x78, 0x7d, 0xef, 0x22, 0x14, 0x4b, 0xff, 0xfd, 0x10, + 0x40, 0xbe, 0xfd, 0x0c, 0x7c, 0xa7, 0x4a, 0x14, 0x40, 0x92, 0x00, 0x14, 0x54, 0x64, 0x04, 0x3e, + 0x91, 0xe5, 0x00, 0x00, 0x90, 0x85, 0x00, 0x04, 0x4b, 0xff, 0xfc, 0xf4, 0x81, 0x25, 0x00, 0x04, + 0x2c, 0x09, 0x00, 0x00, 0x41, 0xa2, 0xfc, 0xe8, 0x39, 0x29, 0xff, 0xff, 0x91, 0x25, 0x00, 0x04, + 0x81, 0xe5, 0x00, 0x00, 0x4b, 0xff, 0xfc, 0xd8, 0x40, 0xbe, 0xfc, 0xd4, 0x54, 0x6b, 0x16, 0xba, + 0x7f, 0x47, 0x5a, 0x14, 0x81, 0x3a, 0x00, 0x00, 0x54, 0x6e, 0x67, 0xbe, 0x41, 0x92, 0x00, 0x84, + 0x2e, 0x05, 0x00, 0x05, 0x40, 0x90, 0x01, 0x74, 0x2e, 0x05, 0x00, 0x03, 0x40, 0x90, 0x00, 0x90, + 0x2e, 0x05, 0x00, 0x01, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14, + 0x2f, 0x0e, 0x00, 0x01, 0x40, 0x92, 0x00, 0x24, 0x41, 0xb9, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x0c, + 0x88, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf8, 0xa0, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf0, + 0x80, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xe8, 0x54, 0x73, 0xe5, 0x3e, 0x41, 0xb9, 0x00, 0x20, + 0x41, 0x9a, 0x00, 0x10, 0x99, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x01, 0x48, 0x00, 0x00, 0x18, + 0xb1, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x02, 0x48, 0x00, 0x00, 0x0c, 0x91, 0x24, 0x00, 0x00, + 0x38, 0x84, 0x00, 0x04, 0x36, 0x73, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4, 0x4b, 0xff, 0xfc, 0x40, + 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, 0x7c, 0x84, 0x62, 0x14, 0x71, 0xc5, 0x00, 0x01, + 0x41, 0x82, 0x00, 0x9c, 0x7c, 0x84, 0x4a, 0x14, 0x48, 0x00, 0x00, 0x94, 0x54, 0x6a, 0x87, 0xbe, + 0x54, 0x8e, 0x16, 0xba, 0x7e, 0x67, 0x72, 0x14, 0x40, 0x92, 0x00, 0x08, 0x3a, 0x6f, 0xff, 0xfc, + 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00, 0x71, 0x4b, 0x00, 0x01, 0x41, 0x82, 0x00, 0x08, + 0x7c, 0x9a, 0x23, 0x78, 0x71, 0x4b, 0x00, 0x02, 0x41, 0x82, 0x00, 0x10, 0x7d, 0x33, 0x4b, 0x78, + 0x40, 0xb2, 0x00, 0x08, 0x7e, 0x6c, 0x9a, 0x14, 0x54, 0x65, 0x67, 0x3f, 0x2c, 0x05, 0x00, 0x09, + 0x40, 0x80, 0x00, 0x54, 0x48, 0x00, 0x00, 0x79, 0x7c, 0x89, 0x22, 0x14, 0x48, 0x00, 0x00, 0x40, + 0x7c, 0x89, 0x21, 0xd6, 0x48, 0x00, 0x00, 0x38, 0x7d, 0x24, 0x23, 0x78, 0x48, 0x00, 0x00, 0x30, + 0x7d, 0x24, 0x20, 0x38, 0x48, 0x00, 0x00, 0x28, 0x7d, 0x24, 0x22, 0x78, 0x48, 0x00, 0x00, 0x20, + 0x7d, 0x24, 0x20, 0x30, 0x48, 0x00, 0x00, 0x18, 0x7d, 0x24, 0x24, 0x30, 0x48, 0x00, 0x00, 0x10, + 0x5d, 0x24, 0x20, 0x3e, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x24, 0x26, 0x30, 0x90, 0x9a, 0x00, 0x00, + 0x4b, 0xff, 0xfb, 0x8c, 0x2c, 0x05, 0x00, 0x0a, 0x41, 0x81, 0xfb, 0x84, 0xc0, 0x5a, 0x00, 0x00, + 0xc0, 0x73, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0c, 0xec, 0x43, 0x10, 0x2a, 0x48, 0x00, 0x00, 0x08, + 0xec, 0x43, 0x00, 0xb2, 0xd0, 0x5a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x64, 0x7d, 0x48, 0x02, 0xa6, + 0x54, 0xa5, 0x1e, 0x78, 0x7d, 0x4a, 0x2a, 0x14, 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00, + 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x40, 0xbe, 0xfb, 0x44, 0x54, 0x69, 0xc0, 0x3e, + 0x7d, 0x8e, 0x63, 0x78, 0x48, 0x00, 0x00, 0x35, 0x41, 0x92, 0x00, 0x0c, 0x7e, 0x31, 0x22, 0x14, + 0x48, 0x00, 0x00, 0x08, 0x7d, 0x29, 0x22, 0x14, 0x54, 0x64, 0xc4, 0x3f, 0x38, 0xa0, 0x00, 0x00, + 0x41, 0x82, 0xfb, 0x1c, 0x7d, 0x45, 0x88, 0xae, 0x7d, 0x45, 0x49, 0xae, 0x38, 0xa5, 0x00, 0x01, + 0x7c, 0x05, 0x20, 0x00, 0x4b, 0xff, 0xff, 0xec, 0x2e, 0x8a, 0x00, 0x04, 0x55, 0x31, 0x36, 0xba, + 0x2c, 0x11, 0x00, 0x3c, 0x7e, 0x27, 0x88, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xd1, 0x73, 0x78, + 0x41, 0x96, 0x00, 0x08, 0xa2, 0x31, 0x00, 0x00, 0x55, 0x29, 0x56, 0xba, 0x2c, 0x09, 0x00, 0x3c, + 0x7d, 0x27, 0x48, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xc9, 0x73, 0x78, 0x41, 0x96, 0x00, 0x08, + 0xa1, 0x29, 0x00, 0x00, 0x4e, 0x80, 0x00, 0x20, 0x2c, 0x05, 0x00, 0x04, 0x40, 0x80, 0x00, 0x28, + 0x7c, 0x89, 0x23, 0x78, 0x7d, 0xc3, 0x62, 0x14, 0x55, 0xce, 0x00, 0x3c, 0x4b, 0xff, 0xff, 0xad, + 0x7c, 0x84, 0x20, 0xf8, 0x54, 0x84, 0x04, 0x3e, 0x7d, 0x2b, 0x20, 0x38, 0x7e, 0x24, 0x20, 0x38, + 0x4b, 0xff, 0xfb, 0xc4, 0x54, 0x6b, 0xe4, 0x3e, 0x4b, 0xff, 0xfb, 0xbc, 0x7c, 0x9a, 0x23, 0x78, + 0x54, 0x84, 0x18, 0x38, 0x40, 0x92, 0x00, 0x20, 0x40, 0x9e, 0x00, 0x0c, 0x7d, 0xe8, 0x03, 0xa6, + 0x4e, 0x80, 0x00, 0x21, 0x7d, 0xe4, 0x7a, 0x14, 0x39, 0xef, 0x00, 0x07, 0x55, 0xef, 0x00, 0x38, + 0x4b, 0xff, 0xfa, 0x6c, 0x2e, 0x05, 0x00, 0x03, 0x41, 0x91, 0x00, 0x5c, 0x3c, 0xa0, 0x48, 0x00, + 0x7d, 0x83, 0x62, 0x14, 0x55, 0x8c, 0x00, 0x3a, 0x40, 0x92, 0x00, 0x20, 0x40, 0xbe, 0xfa, 0x50, + 0x57, 0x44, 0x00, 0x3a, 0x7c, 0x8c, 0x20, 0x50, 0x50, 0x85, 0x01, 0xba, 0x50, 0x65, 0x07, 0xfe, + 0x90, 0xac, 0x00, 0x00, 0x4b, 0xff, 0xfa, 0x38, 0x40, 0xbe, 0xff, 0xbc, 0x7d, 0x2c, 0x78, 0x50, + 0x51, 0x25, 0x01, 0xba, 0x90, 0xac, 0x00, 0x00, 0x39, 0x8c, 0x00, 0x04, 0x7d, 0x6f, 0x22, 0x14, + 0x39, 0x6b, 0xff, 0xfc, 0x7d, 0x2b, 0x60, 0x50, 0x51, 0x25, 0x01, 0xba, 0x90, 0xab, 0x00, 0x00, + 0x4b, 0xff, 0xff, 0x94, 0x2e, 0x05, 0x00, 0x06, 0x41, 0x92, 0x00, 0x28, 0x4b, 0xff, 0xfb, 0x28, + 0x55, 0x8c, 0x84, 0x3e, 0x57, 0x44, 0x84, 0x3e, 0x57, 0x5a, 0x04, 0x3e, 0x7c, 0x0c, 0x20, 0x00, + 0x41, 0x80, 0xfb, 0xa8, 0x7c, 0x0c, 0xd0, 0x00, 0x40, 0x80, 0xfb, 0xa0, 0x4b, 0xff, 0xf9, 0xe0, + 0x57, 0x45, 0xff, 0xfe, 0x68, 0xa5, 0x00, 0x01, 0x71, 0x03, 0x00, 0x01, 0x7c, 0x05, 0x18, 0x00, + 0x41, 0x82, 0x00, 0x1c, 0x51, 0x1a, 0x0f, 0xbc, 0x6b, 0x5a, 0x00, 0x02, 0x57, 0x45, 0xff, 0xff, + 0x41, 0x82, 0x00, 0x08, 0x6b, 0x5a, 0x00, 0x01, 0x93, 0x4f, 0xff, 0xfc, 0x53, 0x48, 0x07, 0xfe, + 0x4b, 0xff, 0xf9, 0xac, 0x2c, 0x0b, 0x00, 0x00, 0x41, 0x82, 0x01, 0x38, 0x2c, 0x05, 0x00, 0x01, + 0x41, 0x82, 0x00, 0x18, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x82, 0x00, 0x14, 0x2c, 0x05, 0x00, 0x03, + 0x41, 0x82, 0x00, 0x70, 0x4b, 0xff, 0xf9, 0x40, 0x54, 0xcc, 0x00, 0x0c, 0x54, 0x97, 0x46, 0x3e, + 0x54, 0x98, 0xc4, 0x3e, 0x54, 0x84, 0x06, 0x3e, 0x40, 0x9e, 0x00, 0xfc, 0x56, 0xf9, 0x06, 0x31, + 0x7d, 0x9a, 0x63, 0x78, 0x7f, 0x43, 0xd2, 0x14, 0x57, 0x5a, 0x00, 0x3a, 0x41, 0x82, 0x00, 0x18, + 0x7e, 0xf7, 0x07, 0x74, 0x7e, 0xf7, 0x00, 0xd0, 0x1f, 0x37, 0x00, 0x02, 0x3b, 0x39, 0x00, 0x04, + 0x7f, 0x59, 0xd0, 0x50, 0x2c, 0x17, 0x00, 0x00, 0x41, 0x82, 0x00, 0x1c, 0x3b, 0x20, 0x00, 0x00, + 0x7e, 0xe9, 0x03, 0xa6, 0xa3, 0x7a, 0x00, 0x04, 0x7f, 0x79, 0xca, 0x78, 0x3b, 0x5a, 0x00, 0x02, + 0x42, 0x00, 0xff, 0xf4, 0x7c, 0x18, 0xc8, 0x00, 0x40, 0x82, 0x00, 0xac, 0x4b, 0xff, 0xfe, 0x90, + 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x9c, 0x54, 0x77, 0xb0, 0x03, 0x41, 0x81, 0x00, 0x88, + 0x41, 0x80, 0x00, 0x8c, 0x54, 0x7e, 0x06, 0x3e, 0x1f, 0xde, 0x00, 0x02, 0x54, 0x97, 0x00, 0x1e, + 0x6e, 0xf8, 0x80, 0x00, 0x2c, 0x18, 0x00, 0x00, 0x40, 0x82, 0x00, 0x08, 0x62, 0xf7, 0x30, 0x00, + 0x54, 0x98, 0x80, 0x1e, 0x1f, 0x3e, 0x00, 0x04, 0x7f, 0x19, 0xc0, 0x50, 0x3b, 0x20, 0x00, 0x00, + 0x1f, 0x59, 0x00, 0x04, 0x7f, 0x6f, 0xd0, 0x2e, 0x7f, 0x57, 0xd0, 0x2e, 0x3b, 0x39, 0x00, 0x01, + 0x7c, 0x17, 0xc0, 0x40, 0x41, 0x81, 0x00, 0x34, 0x7c, 0x19, 0xf0, 0x00, 0x41, 0x81, 0x00, 0x14, + 0x7c, 0x1a, 0xd8, 0x00, 0x41, 0x82, 0xff, 0xdc, 0x3a, 0xf7, 0x00, 0x04, 0x4b, 0xff, 0xff, 0xd0, + 0x80, 0x6f, 0xff, 0xf8, 0x60, 0x63, 0x03, 0x00, 0x90, 0x6f, 0xff, 0xf8, 0x92, 0xef, 0xff, 0xfc, + 0x7e, 0xf0, 0xbb, 0x78, 0x48, 0x00, 0x00, 0x1c, 0x80, 0x6f, 0xff, 0xf8, 0x60, 0x63, 0x01, 0x00, + 0x90, 0x6f, 0xff, 0xf8, 0x61, 0x08, 0x00, 0x01, 0x48, 0x00, 0x00, 0x08, 0x7c, 0x90, 0x23, 0x78, + 0x54, 0x64, 0x06, 0x3e, 0x1c, 0x84, 0x00, 0x08, 0x7d, 0xe4, 0x7a, 0x14, 0x4b, 0xff, 0xf8, 0x70, + 0x40, 0x92, 0x00, 0x0c, 0x39, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x14, 0x54, 0x69, 0x06, 0xff, + 0x54, 0x65, 0x67, 0xfe, 0x7d, 0x08, 0x4c, 0x30, 0x55, 0x17, 0xff, 0xff, 0x40, 0x82, 0x00, 0x08, + 0x7d, 0x08, 0x2a, 0x78, 0x54, 0x85, 0x00, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xa6, 0x2b, 0x78, + 0x54, 0x85, 0x80, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xb0, 0x2b, 0x78, 0x4b, 0xff, 0xf8, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +}; +const int codehandleronly_size = sizeof(codehandleronly); diff --git a/source/patches/codehandlerslota.c b/source/patches/codehandlerslota.c new file mode 100644 index 0000000..1f45411 --- /dev/null +++ b/source/patches/codehandlerslota.c @@ -0,0 +1,277 @@ +/* + This file was autogenerated by raw2c. +Visit http://www.devkitpro.org +*/ + +const unsigned char codehandlerslota[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x27, 0x74, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x21, 0xff, 0x58, 0x90, 0x01, 0x00, 0x08, + 0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0xac, 0x7c, 0x00, 0x00, 0x26, 0x90, 0x01, 0x00, 0x0c, + 0x7c, 0x09, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x10, 0x7c, 0x01, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x14, + 0xbc, 0x61, 0x00, 0x18, 0x7f, 0x20, 0x00, 0xa6, 0x63, 0x3a, 0x20, 0x00, 0x73, 0x5a, 0xf9, 0xff, + 0x7f, 0x40, 0x01, 0x24, 0xd8, 0x41, 0x00, 0x98, 0xd8, 0x61, 0x00, 0xa0, 0x3f, 0xe0, 0x80, 0x00, + 0x3e, 0x80, 0xcc, 0x00, 0xa3, 0x94, 0x40, 0x10, 0x63, 0x95, 0x00, 0xff, 0xb2, 0xb4, 0x40, 0x10, + 0x48, 0x00, 0x06, 0x55, 0x3a, 0xa0, 0x00, 0x00, 0x3a, 0xc0, 0x00, 0x19, 0x3a, 0xe0, 0x00, 0xd0, + 0x3f, 0x00, 0xcd, 0x00, 0x63, 0xf2, 0x27, 0x74, 0x80, 0x01, 0x00, 0xac, 0x90, 0x12, 0x00, 0x04, + 0x92, 0xb8, 0x64, 0x3c, 0x48, 0x00, 0x04, 0x2d, 0x41, 0x82, 0x05, 0xa4, 0x2c, 0x1d, 0x00, 0x04, + 0x40, 0x80, 0x00, 0x10, 0x2c, 0x1d, 0x00, 0x01, 0x41, 0x80, 0x05, 0x94, 0x48, 0x00, 0x03, 0x4c, + 0x41, 0x82, 0x04, 0xf0, 0x2c, 0x1d, 0x00, 0x06, 0x41, 0x82, 0x00, 0x8c, 0x2c, 0x1d, 0x00, 0x07, + 0x41, 0x82, 0x03, 0x30, 0x2c, 0x1d, 0x00, 0x08, 0x41, 0x82, 0x05, 0x80, 0x2c, 0x1d, 0x00, 0x09, + 0x41, 0x82, 0x00, 0xa0, 0x2c, 0x1d, 0x00, 0x10, 0x41, 0x82, 0x00, 0x98, 0x2c, 0x1d, 0x00, 0x2f, + 0x41, 0x82, 0x00, 0x70, 0x2c, 0x1d, 0x00, 0x30, 0x41, 0x82, 0x00, 0x78, 0x2c, 0x1d, 0x00, 0x38, + 0x41, 0x82, 0x05, 0x28, 0x2c, 0x1d, 0x00, 0x40, 0x41, 0x82, 0x03, 0x40, 0x2c, 0x1d, 0x00, 0x41, + 0x41, 0x82, 0x03, 0x58, 0x2c, 0x1d, 0x00, 0x44, 0x41, 0x82, 0x00, 0x68, 0x2c, 0x1d, 0x00, 0x50, + 0x41, 0x82, 0x00, 0x20, 0x2c, 0x1d, 0x00, 0x60, 0x41, 0x82, 0x00, 0x24, 0x2c, 0x1d, 0x00, 0x89, + 0x41, 0x82, 0x00, 0x50, 0x2c, 0x1d, 0x00, 0x99, 0x41, 0x82, 0x05, 0x0c, 0x48, 0x00, 0x05, 0x10, + 0x80, 0x72, 0x00, 0x00, 0x48, 0x00, 0x04, 0x29, 0x48, 0x00, 0x05, 0x04, 0x48, 0x00, 0x05, 0x89, + 0x48, 0x00, 0x04, 0xfc, 0x38, 0x80, 0x00, 0x01, 0x90, 0x92, 0x00, 0x00, 0x48, 0x00, 0x04, 0xf0, + 0x48, 0x00, 0x04, 0x09, 0x3a, 0x00, 0x00, 0xa0, 0x63, 0xec, 0x27, 0x98, 0x48, 0x00, 0x03, 0x14, + 0x38, 0x60, 0x01, 0x20, 0x63, 0xec, 0x27, 0x98, 0x48, 0x00, 0x03, 0xc9, 0x48, 0x00, 0x04, 0xd0, + 0x2f, 0x1d, 0x00, 0x10, 0x2e, 0x9d, 0x00, 0x44, 0x63, 0xe4, 0x1a, 0xb4, 0x3c, 0x60, 0x80, 0x00, + 0x60, 0x63, 0x03, 0x00, 0x48, 0x00, 0x05, 0x09, 0x38, 0x63, 0x0a, 0x00, 0x48, 0x00, 0x05, 0x01, + 0x38, 0x63, 0x06, 0x00, 0x48, 0x00, 0x04, 0xf9, 0x63, 0xec, 0x27, 0x88, 0x92, 0xac, 0x00, 0x00, + 0x92, 0xac, 0x00, 0x04, 0x92, 0xac, 0x00, 0x08, 0x63, 0xe4, 0x27, 0x98, 0x81, 0x24, 0x00, 0x18, + 0x80, 0x72, 0x00, 0x00, 0x2c, 0x03, 0x00, 0x02, 0x40, 0x82, 0x00, 0x0c, 0x41, 0x96, 0x00, 0x0c, + 0x48, 0x00, 0x00, 0x20, 0x38, 0x60, 0x00, 0x00, 0x90, 0x6c, 0x00, 0x0c, 0x40, 0x82, 0x00, 0x14, + 0x40, 0x96, 0x00, 0x10, 0x61, 0x29, 0x04, 0x00, 0x91, 0x24, 0x00, 0x18, 0x48, 0x00, 0x02, 0x14, + 0x55, 0x29, 0x05, 0xa8, 0x91, 0x24, 0x00, 0x18, 0x41, 0x96, 0x04, 0x54, 0x41, 0x9a, 0x00, 0x08, + 0x39, 0x8c, 0x00, 0x04, 0x38, 0x60, 0x00, 0x04, 0x48, 0x00, 0x03, 0x09, 0x40, 0x99, 0x00, 0x10, + 0x39, 0x8c, 0x00, 0x04, 0x38, 0x60, 0x00, 0x04, 0x48, 0x00, 0x02, 0xf9, 0x63, 0xe4, 0x27, 0x88, + 0x80, 0x64, 0x00, 0x00, 0x80, 0x84, 0x00, 0x04, 0x7c, 0x72, 0xfb, 0xa6, 0x7c, 0x95, 0xfb, 0xa6, + 0x48, 0x00, 0x04, 0x1c, 0x7c, 0x32, 0x43, 0xa6, 0x7c, 0x3a, 0x02, 0xa6, 0x7c, 0x73, 0x43, 0xa6, + 0x7c, 0x7b, 0x02, 0xa6, 0x54, 0x63, 0x05, 0xa8, 0x90, 0x60, 0x27, 0xb0, 0x54, 0x63, 0x06, 0x1e, + 0x60, 0x63, 0x20, 0x00, 0x7c, 0x7b, 0x03, 0xa6, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x1a, 0xe8, + 0x7c, 0x7a, 0x03, 0xa6, 0x4c, 0x00, 0x00, 0x64, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x27, 0x98, + 0x90, 0x23, 0x00, 0x14, 0x7c, 0x61, 0x1b, 0x78, 0x7c, 0x73, 0x42, 0xa6, 0xbc, 0x41, 0x00, 0x24, + 0x7c, 0x24, 0x0b, 0x78, 0x7c, 0x32, 0x42, 0xa6, 0x90, 0x04, 0x00, 0x1c, 0x90, 0x24, 0x00, 0x20, + 0x7c, 0x68, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x9c, 0x7c, 0x60, 0x00, 0x26, 0x90, 0x64, 0x00, 0x00, + 0x7c, 0x61, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x04, 0x7c, 0x69, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x08, + 0x7c, 0x72, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x0c, 0x7c, 0x73, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x10, + 0x39, 0x20, 0x00, 0x00, 0x7d, 0x32, 0xfb, 0xa6, 0x7d, 0x35, 0xfb, 0xa6, 0x3c, 0xa0, 0x80, 0x00, + 0x60, 0xa5, 0x1b, 0x70, 0x3f, 0xe0, 0xd0, 0x04, 0x63, 0xff, 0x00, 0xa0, 0x93, 0xe5, 0x00, 0x00, + 0x7c, 0x00, 0x28, 0x6c, 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x2f, 0xac, 0x4c, 0x00, 0x01, 0x2c, + 0xd0, 0x04, 0x00, 0xa0, 0x3b, 0xff, 0x00, 0x04, 0x3f, 0xff, 0x00, 0x20, 0x57, 0xf0, 0x01, 0x4b, + 0x41, 0x82, 0xff, 0xdc, 0x3f, 0xe0, 0x80, 0x00, 0x63, 0xe5, 0x27, 0x88, 0x82, 0x05, 0x00, 0x00, + 0x82, 0x25, 0x00, 0x04, 0x82, 0x65, 0x00, 0x0c, 0x2c, 0x13, 0x00, 0x00, 0x41, 0x82, 0x00, 0x74, + 0x2c, 0x13, 0x00, 0x02, 0x40, 0x82, 0x00, 0x18, 0x81, 0x24, 0x00, 0x14, 0x39, 0x33, 0x00, 0x03, + 0x91, 0x25, 0x00, 0x00, 0x91, 0x25, 0x00, 0x0c, 0x48, 0x00, 0x00, 0x6c, 0x7c, 0x10, 0x98, 0x00, + 0x41, 0x82, 0x00, 0x38, 0x7c, 0x11, 0x98, 0x00, 0x41, 0x82, 0x00, 0x30, 0x7d, 0x30, 0x8a, 0x14, + 0x91, 0x25, 0x00, 0x0c, 0x82, 0x05, 0x00, 0x08, 0x2c, 0x10, 0x00, 0x00, 0x41, 0x82, 0x00, 0x48, + 0x80, 0x64, 0x00, 0x10, 0x7c, 0x10, 0x18, 0x00, 0x40, 0x82, 0x00, 0x10, 0x3a, 0x00, 0x00, 0x00, + 0x92, 0x05, 0x00, 0x08, 0x48, 0x00, 0x00, 0x30, 0x3a, 0x20, 0x00, 0x00, 0x92, 0x25, 0x00, 0x0c, + 0x81, 0x24, 0x00, 0x18, 0x61, 0x29, 0x04, 0x00, 0x91, 0x24, 0x00, 0x18, 0x48, 0x00, 0x00, 0x30, + 0x7e, 0x12, 0xfb, 0xa6, 0x7e, 0x35, 0xfb, 0xa6, 0x39, 0x20, 0x00, 0x01, 0x91, 0x25, 0x00, 0x0c, + 0x48, 0x00, 0x00, 0x1c, 0x38, 0xa0, 0x00, 0x02, 0x63, 0xe4, 0x27, 0x74, 0x90, 0xa4, 0x00, 0x00, + 0x38, 0x60, 0x00, 0x11, 0x48, 0x00, 0x01, 0xb9, 0x4b, 0xff, 0xfc, 0x71, 0x7c, 0x20, 0x00, 0xa6, + 0x54, 0x21, 0x07, 0xfa, 0x54, 0x21, 0x04, 0x5e, 0x7c, 0x20, 0x01, 0x24, 0x63, 0xe1, 0x27, 0x98, + 0x80, 0x61, 0x00, 0x00, 0x7c, 0x6f, 0xf1, 0x20, 0x80, 0x61, 0x00, 0x14, 0x7c, 0x7a, 0x03, 0xa6, + 0x80, 0x61, 0x00, 0x18, 0x7c, 0x7b, 0x03, 0xa6, 0x80, 0x61, 0x00, 0x9c, 0x7c, 0x68, 0x03, 0xa6, + 0xb8, 0x41, 0x00, 0x24, 0x80, 0x01, 0x00, 0x1c, 0x80, 0x21, 0x00, 0x20, 0x4c, 0x00, 0x00, 0x64, + 0x92, 0xb2, 0x00, 0x00, 0x48, 0x00, 0x02, 0x54, 0x2e, 0x9d, 0x00, 0x02, 0x38, 0x60, 0x00, 0x08, + 0x63, 0xec, 0x27, 0x7c, 0x48, 0x00, 0x00, 0xfd, 0x80, 0xac, 0x00, 0x00, 0x80, 0x6c, 0x00, 0x04, + 0x98, 0x65, 0x00, 0x00, 0x41, 0x94, 0x00, 0x10, 0xb0, 0x65, 0x00, 0x00, 0x41, 0x96, 0x00, 0x08, + 0x90, 0x65, 0x00, 0x00, 0x7c, 0x00, 0x28, 0xac, 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x2f, 0xac, + 0x4c, 0x00, 0x01, 0x2c, 0x48, 0x00, 0x02, 0x08, 0x48, 0x00, 0x01, 0x21, 0x38, 0x60, 0x00, 0x04, + 0x63, 0xec, 0x27, 0x7c, 0x48, 0x00, 0x00, 0xbd, 0x82, 0x0c, 0x00, 0x00, 0x3d, 0x80, 0x80, 0x00, + 0x61, 0x8c, 0x28, 0xb8, 0x48, 0x00, 0x00, 0x1c, 0x48, 0x00, 0x01, 0x01, 0x38, 0x60, 0x00, 0x08, + 0x63, 0xec, 0x27, 0x7c, 0x48, 0x00, 0x00, 0x9d, 0x82, 0x0c, 0x00, 0x04, 0x81, 0x8c, 0x00, 0x00, + 0x63, 0xfb, 0x27, 0x84, 0x3a, 0x20, 0x0f, 0x80, 0x48, 0x00, 0x02, 0x39, 0x41, 0x82, 0x00, 0x20, + 0x7e, 0x23, 0x8b, 0x78, 0x48, 0x00, 0x00, 0x7d, 0x48, 0x00, 0x00, 0xd1, 0x41, 0x82, 0xff, 0xfc, + 0x7d, 0x8c, 0x72, 0x14, 0x35, 0x6b, 0xff, 0xff, 0x41, 0x81, 0xff, 0xe8, 0x80, 0x7b, 0x00, 0x00, + 0x2c, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x08, 0x48, 0x00, 0x00, 0x59, 0x7c, 0x00, 0x60, 0xac, + 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x67, 0xac, 0x4c, 0x00, 0x01, 0x2c, 0x48, 0x00, 0x01, 0x80, + 0x7f, 0xc8, 0x02, 0xa6, 0x3c, 0x60, 0xa0, 0x00, 0x48, 0x00, 0x00, 0x15, 0x76, 0x03, 0x08, 0x00, + 0x56, 0x1d, 0x86, 0x3e, 0x7f, 0xc8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x92, 0xf8, 0x68, 0x00, + 0x90, 0x78, 0x68, 0x10, 0x92, 0xd8, 0x68, 0x0c, 0x80, 0xb8, 0x68, 0x0c, 0x70, 0xa5, 0x00, 0x01, + 0x40, 0x82, 0xff, 0xf8, 0x82, 0x18, 0x68, 0x10, 0x90, 0xb8, 0x68, 0x00, 0x4e, 0x80, 0x00, 0x20, + 0x7d, 0x48, 0x02, 0xa6, 0x7c, 0x69, 0x03, 0xa6, 0x39, 0xc0, 0x00, 0x00, 0x48, 0x00, 0x00, 0x79, + 0x48, 0x00, 0x00, 0x75, 0x4b, 0xff, 0xff, 0xad, 0x41, 0x82, 0xff, 0xf4, 0x7f, 0xae, 0x61, 0xae, + 0x39, 0xce, 0x00, 0x01, 0x42, 0x00, 0xff, 0xe8, 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, + 0x7d, 0x48, 0x02, 0xa6, 0x7c, 0x69, 0x03, 0xa6, 0x39, 0xc0, 0x00, 0x00, 0x7c, 0x6c, 0x70, 0xae, + 0x48, 0x00, 0x00, 0x1d, 0x41, 0x82, 0xff, 0xf8, 0x39, 0xce, 0x00, 0x01, 0x42, 0x00, 0xff, 0xf0, + 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x38, 0x60, 0x00, 0xaa, 0x7f, 0xc8, 0x02, 0xa6, + 0x54, 0x63, 0xa0, 0x16, 0x64, 0x63, 0xb0, 0x00, 0x3a, 0xc0, 0x00, 0x19, 0x3a, 0xe0, 0x00, 0xd0, + 0x3f, 0x00, 0xcd, 0x00, 0x4b, 0xff, 0xff, 0x69, 0x56, 0x03, 0x37, 0xff, 0x7f, 0xc8, 0x03, 0xa6, + 0x4e, 0x80, 0x00, 0x20, 0x7f, 0xc8, 0x02, 0xa6, 0x3c, 0x60, 0xd0, 0x00, 0x4b, 0xff, 0xff, 0x51, + 0x56, 0x03, 0x37, 0xff, 0x41, 0x82, 0xff, 0xf4, 0x7f, 0xc8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, + 0x4b, 0xff, 0xff, 0xb9, 0x38, 0x60, 0x00, 0x08, 0x63, 0xec, 0x27, 0x7c, 0x4b, 0xff, 0xff, 0x55, + 0x80, 0xac, 0x00, 0x04, 0x81, 0x8c, 0x00, 0x00, 0x63, 0xfb, 0x27, 0x84, 0x62, 0xb1, 0xf8, 0x00, + 0x7e, 0x0c, 0x28, 0x50, 0x48, 0x00, 0x00, 0xed, 0x41, 0x81, 0x00, 0x10, 0x82, 0x3b, 0x00, 0x00, + 0x2c, 0x11, 0x00, 0x00, 0x41, 0x82, 0x00, 0x68, 0x7e, 0x23, 0x8b, 0x78, 0x4b, 0xff, 0xff, 0x55, + 0x4b, 0xff, 0xff, 0xa5, 0x4b, 0xff, 0xff, 0xa1, 0x4b, 0xff, 0xfe, 0xd9, 0x41, 0x82, 0xff, 0xf4, + 0x2c, 0x1d, 0x00, 0xcc, 0x41, 0x82, 0x00, 0x48, 0x2c, 0x1d, 0x00, 0xbb, 0x41, 0x82, 0xff, 0xdc, + 0x2c, 0x1d, 0x00, 0xaa, 0x40, 0x82, 0xff, 0xdc, 0x7d, 0x8c, 0x72, 0x14, 0x35, 0x6b, 0xff, 0xff, + 0x41, 0x80, 0x00, 0x2c, 0x4b, 0xff, 0xff, 0xb4, 0x7e, 0xb5, 0xfb, 0xa6, 0x7e, 0xb2, 0xfb, 0xa6, + 0x63, 0xe4, 0x27, 0x98, 0x81, 0x24, 0x00, 0x18, 0x55, 0x29, 0x05, 0xa8, 0x91, 0x24, 0x00, 0x18, + 0x48, 0x00, 0x00, 0x0c, 0x38, 0x60, 0x00, 0x80, 0x4b, 0xff, 0xff, 0x25, 0x80, 0x92, 0x00, 0x00, + 0x2c, 0x04, 0x00, 0x00, 0x40, 0x82, 0xfa, 0x50, 0xb3, 0x94, 0x40, 0x10, 0xc8, 0x41, 0x00, 0x98, + 0xc8, 0x61, 0x00, 0xa0, 0x7f, 0x20, 0x00, 0xa6, 0x80, 0x01, 0x00, 0xac, 0x7c, 0x08, 0x03, 0xa6, + 0x80, 0x01, 0x00, 0x0c, 0x7c, 0x0f, 0xf1, 0x20, 0x80, 0x01, 0x00, 0x10, 0x7c, 0x09, 0x03, 0xa6, + 0x80, 0x01, 0x00, 0x14, 0x7c, 0x01, 0x03, 0xa6, 0xb8, 0x61, 0x00, 0x18, 0x80, 0x01, 0x00, 0x08, + 0x38, 0x21, 0x00, 0xa8, 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20, 0x7e, 0x23, 0x20, 0x50, + 0x3c, 0xa0, 0x48, 0x00, 0x52, 0x25, 0x01, 0xba, 0x90, 0xa3, 0x00, 0x00, 0x7c, 0x00, 0x18, 0xac, + 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x1f, 0xac, 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20, + 0x7d, 0x70, 0x8b, 0xd7, 0x7d, 0x4b, 0x89, 0xd6, 0x7d, 0x4a, 0x80, 0x50, 0x91, 0x5b, 0x00, 0x00, + 0x4e, 0x80, 0x00, 0x20, 0x7f, 0xa8, 0x02, 0xa6, 0x3d, 0xe0, 0x80, 0x00, 0x61, 0xef, 0x28, 0xb8, + 0x63, 0xe7, 0x18, 0x08, 0x3c, 0xc0, 0x80, 0x00, 0x7c, 0xd0, 0x33, 0x78, 0x39, 0x00, 0x00, 0x00, + 0x3c, 0x60, 0x00, 0xd0, 0x60, 0x63, 0xc0, 0xde, 0x80, 0x8f, 0x00, 0x00, 0x7c, 0x03, 0x20, 0x00, + 0x40, 0x82, 0x00, 0x18, 0x80, 0x8f, 0x00, 0x04, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x0c, + 0x39, 0xef, 0x00, 0x08, 0x48, 0x00, 0x00, 0x0c, 0x7f, 0xa8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, + 0x80, 0x6f, 0x00, 0x00, 0x80, 0x8f, 0x00, 0x04, 0x39, 0xef, 0x00, 0x08, 0x71, 0x09, 0x00, 0x01, + 0x2f, 0x89, 0x00, 0x00, 0x39, 0x20, 0x00, 0x00, 0x54, 0x6a, 0x1f, 0x7e, 0x54, 0x65, 0x3f, 0x7e, + 0x74, 0x6b, 0x10, 0x00, 0x54, 0x63, 0x01, 0xfe, 0x40, 0x82, 0x00, 0x0c, 0x54, 0xcc, 0x00, 0x0c, + 0x48, 0x00, 0x00, 0x08, 0x7e, 0x0c, 0x83, 0x78, 0x2e, 0x05, 0x00, 0x00, 0x2c, 0x0a, 0x00, 0x01, + 0x41, 0xa0, 0x00, 0x2c, 0x41, 0xa2, 0x00, 0xe4, 0x2c, 0x0a, 0x00, 0x03, 0x41, 0xa0, 0x01, 0xac, + 0x41, 0x82, 0x02, 0x50, 0x2c, 0x0a, 0x00, 0x05, 0x41, 0x80, 0x02, 0xd4, 0x41, 0xa2, 0x04, 0xe0, + 0x2c, 0x0a, 0x00, 0x07, 0x41, 0xa0, 0x05, 0x0c, 0x48, 0x00, 0x05, 0xf0, 0x7d, 0x8c, 0x1a, 0x14, + 0x2c, 0x05, 0x00, 0x03, 0x41, 0x82, 0x00, 0x48, 0x41, 0x81, 0x00, 0x60, 0x40, 0xbe, 0xff, 0x84, + 0x2e, 0x05, 0x00, 0x01, 0x41, 0x91, 0x00, 0x2c, 0x54, 0x8a, 0x84, 0x3e, 0x41, 0x92, 0x00, 0x10, + 0x7c, 0x89, 0x61, 0xae, 0x39, 0x29, 0x00, 0x01, 0x48, 0x00, 0x00, 0x0c, 0x7c, 0x89, 0x63, 0x2e, + 0x39, 0x29, 0x00, 0x02, 0x35, 0x4a, 0xff, 0xff, 0x40, 0xa0, 0xff, 0xe4, 0x4b, 0xff, 0xff, 0x54, + 0x55, 0x8c, 0x00, 0x3a, 0x90, 0x8c, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x48, 0x7c, 0x89, 0x23, 0x78, + 0x40, 0x9e, 0x04, 0xc8, 0x35, 0x29, 0xff, 0xff, 0x41, 0x80, 0x04, 0xc0, 0x7c, 0xa9, 0x78, 0xae, + 0x7c, 0xa9, 0x61, 0xae, 0x4b, 0xff, 0xff, 0xf0, 0x39, 0xef, 0x00, 0x08, 0x40, 0xbe, 0xff, 0x24, + 0x80, 0xaf, 0xff, 0xf8, 0x81, 0x6f, 0xff, 0xfc, 0x54, 0xb1, 0x04, 0x3e, 0x54, 0xaa, 0x85, 0x3e, + 0x54, 0xa5, 0x27, 0x3e, 0x2e, 0x85, 0x00, 0x01, 0x41, 0x96, 0x00, 0x10, 0x41, 0xb5, 0x00, 0x14, + 0x7c, 0x89, 0x61, 0xae, 0x48, 0x00, 0x00, 0x10, 0x7c, 0x89, 0x63, 0x2e, 0x48, 0x00, 0x00, 0x08, + 0x7c, 0x89, 0x61, 0x2e, 0x7c, 0x84, 0x5a, 0x14, 0x7d, 0x29, 0x8a, 0x14, 0x35, 0x4a, 0xff, 0xff, + 0x40, 0x80, 0xff, 0xd4, 0x4b, 0xff, 0xfe, 0xdc, 0x54, 0x69, 0x07, 0xff, 0x41, 0x82, 0x00, 0x10, + 0x55, 0x08, 0xf8, 0x7e, 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00, 0x2e, 0x85, 0x00, 0x04, + 0x2d, 0x8a, 0x00, 0x05, 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x78, 0x41, 0x8d, 0x04, 0xb8, + 0x7d, 0x8c, 0x1a, 0x14, 0x41, 0x8c, 0x00, 0x0c, 0x41, 0x94, 0x00, 0x30, 0x48, 0x00, 0x00, 0x1c, + 0x40, 0x94, 0x00, 0x10, 0x55, 0x8c, 0x00, 0x3a, 0x81, 0x6c, 0x00, 0x00, 0x48, 0x00, 0x00, 0x1c, + 0x55, 0x8c, 0x00, 0x3c, 0xa1, 0x6c, 0x00, 0x00, 0x7c, 0x89, 0x20, 0xf8, 0x55, 0x29, 0x84, 0x3e, + 0x7d, 0x6b, 0x48, 0x38, 0x54, 0x84, 0x04, 0x3e, 0x7f, 0x0b, 0x20, 0x40, 0x70, 0xa9, 0x00, 0x03, + 0x41, 0x82, 0x00, 0x18, 0x2c, 0x09, 0x00, 0x02, 0x41, 0x82, 0x00, 0x18, 0x41, 0x81, 0x00, 0x1c, + 0x40, 0x9a, 0x00, 0x20, 0x48, 0x00, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x18, 0x48, 0x00, 0x00, 0x10, + 0x41, 0x99, 0x00, 0x10, 0x48, 0x00, 0x00, 0x08, 0x41, 0x98, 0x00, 0x08, 0x61, 0x08, 0x00, 0x01, + 0x40, 0x8e, 0xfe, 0x40, 0x41, 0x94, 0xfe, 0x3c, 0x81, 0x6f, 0xff, 0xf8, 0x40, 0x9e, 0x00, 0x20, + 0x70, 0x6c, 0x00, 0x08, 0x41, 0x82, 0x00, 0x0c, 0x71, 0x0c, 0x00, 0x01, 0x41, 0x82, 0x00, 0x10, + 0x39, 0x8b, 0x00, 0x10, 0x51, 0x8b, 0x03, 0x36, 0x48, 0x00, 0x00, 0x08, 0x55, 0x6b, 0x07, 0x16, + 0x91, 0x6f, 0xff, 0xf8, 0x4b, 0xff, 0xfe, 0x0c, 0x40, 0xbe, 0xfe, 0x08, 0x54, 0x69, 0x16, 0xba, + 0x54, 0x6e, 0x87, 0xfe, 0x2d, 0x8e, 0x00, 0x00, 0x2e, 0x05, 0x00, 0x04, 0x70, 0xae, 0x00, 0x03, + 0x2e, 0x8e, 0x00, 0x02, 0x41, 0x94, 0x00, 0x14, 0x41, 0x96, 0x00, 0x50, 0x7c, 0x64, 0x07, 0x34, + 0x7c, 0x84, 0x7a, 0x14, 0x48, 0x00, 0x00, 0x68, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, + 0x7d, 0x27, 0x48, 0x2e, 0x7c, 0x84, 0x4a, 0x14, 0x41, 0x8e, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14, + 0x2e, 0x8e, 0x00, 0x01, 0x41, 0x96, 0x00, 0x08, 0x80, 0x84, 0x00, 0x00, 0x54, 0x63, 0x67, 0xff, + 0x41, 0x82, 0x00, 0x3c, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0x84, 0x32, 0x14, 0x48, 0x00, 0x00, 0x30, + 0x7c, 0x84, 0x82, 0x14, 0x48, 0x00, 0x00, 0x28, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, + 0x7d, 0x27, 0x48, 0x2e, 0x7c, 0x84, 0x4a, 0x14, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0xcc, 0x21, 0x2e, + 0x4b, 0xff, 0xfd, 0x80, 0x7e, 0x0c, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x78, 0x40, 0x90, 0x00, 0x0c, + 0x7c, 0x86, 0x23, 0x78, 0x4b, 0xff, 0xfd, 0x6c, 0x7c, 0x90, 0x23, 0x78, 0x4b, 0xff, 0xfd, 0x64, + 0x54, 0x89, 0x1e, 0x78, 0x39, 0x29, 0x00, 0x40, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x80, 0x00, 0x48, + 0x54, 0x6b, 0x50, 0x03, 0x41, 0x82, 0x00, 0x14, 0x41, 0x81, 0x00, 0x08, 0x48, 0x00, 0x00, 0x10, + 0x41, 0xbe, 0xfd, 0x40, 0x48, 0x00, 0x00, 0x08, 0x40, 0xbe, 0xfd, 0x38, 0x2c, 0x05, 0x00, 0x03, + 0x41, 0x81, 0x00, 0x10, 0x41, 0xa2, 0x00, 0x10, 0x7d, 0xe7, 0x48, 0x2e, 0x4b, 0xff, 0xfd, 0x24, + 0x7d, 0xe7, 0x49, 0x2e, 0x7c, 0x64, 0x07, 0x34, 0x54, 0x84, 0x1a, 0x78, 0x7d, 0xef, 0x22, 0x14, + 0x4b, 0xff, 0xfd, 0x10, 0x40, 0xbe, 0xfd, 0x0c, 0x7c, 0xa7, 0x4a, 0x14, 0x40, 0x92, 0x00, 0x14, + 0x54, 0x64, 0x04, 0x3e, 0x91, 0xe5, 0x00, 0x00, 0x90, 0x85, 0x00, 0x04, 0x4b, 0xff, 0xfc, 0xf4, + 0x81, 0x25, 0x00, 0x04, 0x2c, 0x09, 0x00, 0x00, 0x41, 0xa2, 0xfc, 0xe8, 0x39, 0x29, 0xff, 0xff, + 0x91, 0x25, 0x00, 0x04, 0x81, 0xe5, 0x00, 0x00, 0x4b, 0xff, 0xfc, 0xd8, 0x40, 0xbe, 0xfc, 0xd4, + 0x54, 0x6b, 0x16, 0xba, 0x7f, 0x47, 0x5a, 0x14, 0x81, 0x3a, 0x00, 0x00, 0x54, 0x6e, 0x67, 0xbe, + 0x41, 0x92, 0x00, 0x84, 0x2e, 0x05, 0x00, 0x05, 0x40, 0x90, 0x01, 0x74, 0x2e, 0x05, 0x00, 0x03, + 0x40, 0x90, 0x00, 0x90, 0x2e, 0x05, 0x00, 0x01, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, + 0x7c, 0x8c, 0x22, 0x14, 0x2f, 0x0e, 0x00, 0x01, 0x40, 0x92, 0x00, 0x24, 0x41, 0xb9, 0x00, 0x18, + 0x41, 0x9a, 0x00, 0x0c, 0x88, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf8, 0xa0, 0x84, 0x00, 0x00, + 0x48, 0x00, 0x00, 0xf0, 0x80, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xe8, 0x54, 0x73, 0xe5, 0x3e, + 0x41, 0xb9, 0x00, 0x20, 0x41, 0x9a, 0x00, 0x10, 0x99, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x01, + 0x48, 0x00, 0x00, 0x18, 0xb1, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x02, 0x48, 0x00, 0x00, 0x0c, + 0x91, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x04, 0x36, 0x73, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4, + 0x4b, 0xff, 0xfc, 0x40, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, 0x7c, 0x84, 0x62, 0x14, + 0x71, 0xc5, 0x00, 0x01, 0x41, 0x82, 0x00, 0x9c, 0x7c, 0x84, 0x4a, 0x14, 0x48, 0x00, 0x00, 0x94, + 0x54, 0x6a, 0x87, 0xbe, 0x54, 0x8e, 0x16, 0xba, 0x7e, 0x67, 0x72, 0x14, 0x40, 0x92, 0x00, 0x08, + 0x3a, 0x6f, 0xff, 0xfc, 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00, 0x71, 0x4b, 0x00, 0x01, + 0x41, 0x82, 0x00, 0x08, 0x7c, 0x9a, 0x23, 0x78, 0x71, 0x4b, 0x00, 0x02, 0x41, 0x82, 0x00, 0x10, + 0x7d, 0x33, 0x4b, 0x78, 0x40, 0xb2, 0x00, 0x08, 0x7e, 0x6c, 0x9a, 0x14, 0x54, 0x65, 0x67, 0x3f, + 0x2c, 0x05, 0x00, 0x09, 0x40, 0x80, 0x00, 0x54, 0x48, 0x00, 0x00, 0x79, 0x7c, 0x89, 0x22, 0x14, + 0x48, 0x00, 0x00, 0x40, 0x7c, 0x89, 0x21, 0xd6, 0x48, 0x00, 0x00, 0x38, 0x7d, 0x24, 0x23, 0x78, + 0x48, 0x00, 0x00, 0x30, 0x7d, 0x24, 0x20, 0x38, 0x48, 0x00, 0x00, 0x28, 0x7d, 0x24, 0x22, 0x78, + 0x48, 0x00, 0x00, 0x20, 0x7d, 0x24, 0x20, 0x30, 0x48, 0x00, 0x00, 0x18, 0x7d, 0x24, 0x24, 0x30, + 0x48, 0x00, 0x00, 0x10, 0x5d, 0x24, 0x20, 0x3e, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x24, 0x26, 0x30, + 0x90, 0x9a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x8c, 0x2c, 0x05, 0x00, 0x0a, 0x41, 0x81, 0xfb, 0x84, + 0xc0, 0x5a, 0x00, 0x00, 0xc0, 0x73, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0c, 0xec, 0x43, 0x10, 0x2a, + 0x48, 0x00, 0x00, 0x08, 0xec, 0x43, 0x00, 0xb2, 0xd0, 0x5a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x64, + 0x7d, 0x48, 0x02, 0xa6, 0x54, 0xa5, 0x1e, 0x78, 0x7d, 0x4a, 0x2a, 0x14, 0x80, 0x9a, 0x00, 0x00, + 0x81, 0x33, 0x00, 0x00, 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x40, 0xbe, 0xfb, 0x44, + 0x54, 0x69, 0xc0, 0x3e, 0x7d, 0x8e, 0x63, 0x78, 0x48, 0x00, 0x00, 0x35, 0x41, 0x92, 0x00, 0x0c, + 0x7e, 0x31, 0x22, 0x14, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x29, 0x22, 0x14, 0x54, 0x64, 0xc4, 0x3f, + 0x38, 0xa0, 0x00, 0x00, 0x41, 0x82, 0xfb, 0x1c, 0x7d, 0x45, 0x88, 0xae, 0x7d, 0x45, 0x49, 0xae, + 0x38, 0xa5, 0x00, 0x01, 0x7c, 0x05, 0x20, 0x00, 0x4b, 0xff, 0xff, 0xec, 0x2e, 0x8a, 0x00, 0x04, + 0x55, 0x31, 0x36, 0xba, 0x2c, 0x11, 0x00, 0x3c, 0x7e, 0x27, 0x88, 0x2e, 0x40, 0x82, 0x00, 0x08, + 0x7d, 0xd1, 0x73, 0x78, 0x41, 0x96, 0x00, 0x08, 0xa2, 0x31, 0x00, 0x00, 0x55, 0x29, 0x56, 0xba, + 0x2c, 0x09, 0x00, 0x3c, 0x7d, 0x27, 0x48, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xc9, 0x73, 0x78, + 0x41, 0x96, 0x00, 0x08, 0xa1, 0x29, 0x00, 0x00, 0x4e, 0x80, 0x00, 0x20, 0x2c, 0x05, 0x00, 0x04, + 0x40, 0x80, 0x00, 0x28, 0x7c, 0x89, 0x23, 0x78, 0x7d, 0xc3, 0x62, 0x14, 0x55, 0xce, 0x00, 0x3c, + 0x4b, 0xff, 0xff, 0xad, 0x7c, 0x84, 0x20, 0xf8, 0x54, 0x84, 0x04, 0x3e, 0x7d, 0x2b, 0x20, 0x38, + 0x7e, 0x24, 0x20, 0x38, 0x4b, 0xff, 0xfb, 0xc4, 0x54, 0x6b, 0xe4, 0x3e, 0x4b, 0xff, 0xfb, 0xbc, + 0x7c, 0x9a, 0x23, 0x78, 0x54, 0x84, 0x18, 0x38, 0x40, 0x92, 0x00, 0x20, 0x40, 0x9e, 0x00, 0x0c, + 0x7d, 0xe8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x21, 0x7d, 0xe4, 0x7a, 0x14, 0x39, 0xef, 0x00, 0x07, + 0x55, 0xef, 0x00, 0x38, 0x4b, 0xff, 0xfa, 0x6c, 0x2e, 0x05, 0x00, 0x03, 0x41, 0x91, 0x00, 0x5c, + 0x3c, 0xa0, 0x48, 0x00, 0x7d, 0x83, 0x62, 0x14, 0x55, 0x8c, 0x00, 0x3a, 0x40, 0x92, 0x00, 0x20, + 0x40, 0xbe, 0xfa, 0x50, 0x57, 0x44, 0x00, 0x3a, 0x7c, 0x8c, 0x20, 0x50, 0x50, 0x85, 0x01, 0xba, + 0x50, 0x65, 0x07, 0xfe, 0x90, 0xac, 0x00, 0x00, 0x4b, 0xff, 0xfa, 0x38, 0x40, 0xbe, 0xff, 0xbc, + 0x7d, 0x2c, 0x78, 0x50, 0x51, 0x25, 0x01, 0xba, 0x90, 0xac, 0x00, 0x00, 0x39, 0x8c, 0x00, 0x04, + 0x7d, 0x6f, 0x22, 0x14, 0x39, 0x6b, 0xff, 0xfc, 0x7d, 0x2b, 0x60, 0x50, 0x51, 0x25, 0x01, 0xba, + 0x90, 0xab, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x94, 0x2e, 0x05, 0x00, 0x06, 0x41, 0x92, 0x00, 0x28, + 0x4b, 0xff, 0xfb, 0x28, 0x55, 0x8c, 0x84, 0x3e, 0x57, 0x44, 0x84, 0x3e, 0x57, 0x5a, 0x04, 0x3e, + 0x7c, 0x0c, 0x20, 0x00, 0x41, 0x80, 0xfb, 0xa8, 0x7c, 0x0c, 0xd0, 0x00, 0x40, 0x80, 0xfb, 0xa0, + 0x4b, 0xff, 0xf9, 0xe0, 0x57, 0x45, 0xff, 0xfe, 0x68, 0xa5, 0x00, 0x01, 0x71, 0x03, 0x00, 0x01, + 0x7c, 0x05, 0x18, 0x00, 0x41, 0x82, 0x00, 0x1c, 0x51, 0x1a, 0x0f, 0xbc, 0x6b, 0x5a, 0x00, 0x02, + 0x57, 0x45, 0xff, 0xff, 0x41, 0x82, 0x00, 0x08, 0x6b, 0x5a, 0x00, 0x01, 0x93, 0x4f, 0xff, 0xfc, + 0x53, 0x48, 0x07, 0xfe, 0x4b, 0xff, 0xf9, 0xac, 0x2c, 0x0b, 0x00, 0x00, 0x41, 0x82, 0x01, 0x38, + 0x2c, 0x05, 0x00, 0x01, 0x41, 0x82, 0x00, 0x18, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x82, 0x00, 0x14, + 0x2c, 0x05, 0x00, 0x03, 0x41, 0x82, 0x00, 0x70, 0x4b, 0xff, 0xf9, 0x80, 0x54, 0xcc, 0x00, 0x0c, + 0x54, 0x97, 0x46, 0x3e, 0x54, 0x98, 0xc4, 0x3e, 0x54, 0x84, 0x06, 0x3e, 0x40, 0x9e, 0x00, 0xfc, + 0x56, 0xf9, 0x06, 0x31, 0x7d, 0x9a, 0x63, 0x78, 0x7f, 0x43, 0xd2, 0x14, 0x57, 0x5a, 0x00, 0x3a, + 0x41, 0x82, 0x00, 0x18, 0x7e, 0xf7, 0x07, 0x74, 0x7e, 0xf7, 0x00, 0xd0, 0x1f, 0x37, 0x00, 0x02, + 0x3b, 0x39, 0x00, 0x04, 0x7f, 0x59, 0xd0, 0x50, 0x2c, 0x17, 0x00, 0x00, 0x41, 0x82, 0x00, 0x1c, + 0x3b, 0x20, 0x00, 0x00, 0x7e, 0xe9, 0x03, 0xa6, 0xa3, 0x7a, 0x00, 0x04, 0x7f, 0x79, 0xca, 0x78, + 0x3b, 0x5a, 0x00, 0x02, 0x42, 0x00, 0xff, 0xf4, 0x7c, 0x18, 0xc8, 0x00, 0x40, 0x82, 0x00, 0xac, + 0x4b, 0xff, 0xfe, 0x90, 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x9c, 0x54, 0x77, 0xb0, 0x03, + 0x41, 0x81, 0x00, 0x88, 0x41, 0x80, 0x00, 0x8c, 0x54, 0x7e, 0x06, 0x3e, 0x1f, 0xde, 0x00, 0x02, + 0x54, 0x97, 0x00, 0x1e, 0x6e, 0xf8, 0x80, 0x00, 0x2c, 0x18, 0x00, 0x00, 0x40, 0x82, 0x00, 0x08, + 0x62, 0xf7, 0x30, 0x00, 0x54, 0x98, 0x80, 0x1e, 0x1f, 0x3e, 0x00, 0x04, 0x7f, 0x19, 0xc0, 0x50, + 0x3b, 0x20, 0x00, 0x00, 0x1f, 0x59, 0x00, 0x04, 0x7f, 0x6f, 0xd0, 0x2e, 0x7f, 0x57, 0xd0, 0x2e, + 0x3b, 0x39, 0x00, 0x01, 0x7c, 0x17, 0xc0, 0x40, 0x41, 0x81, 0x00, 0x34, 0x7c, 0x19, 0xf0, 0x00, + 0x41, 0x81, 0x00, 0x14, 0x7c, 0x1a, 0xd8, 0x00, 0x41, 0x82, 0xff, 0xdc, 0x3a, 0xf7, 0x00, 0x04, + 0x4b, 0xff, 0xff, 0xd0, 0x80, 0x6f, 0xff, 0xf8, 0x60, 0x63, 0x03, 0x00, 0x90, 0x6f, 0xff, 0xf8, + 0x92, 0xef, 0xff, 0xfc, 0x7e, 0xf0, 0xbb, 0x78, 0x48, 0x00, 0x00, 0x1c, 0x80, 0x6f, 0xff, 0xf8, + 0x60, 0x63, 0x01, 0x00, 0x90, 0x6f, 0xff, 0xf8, 0x61, 0x08, 0x00, 0x01, 0x48, 0x00, 0x00, 0x08, + 0x7c, 0x90, 0x23, 0x78, 0x54, 0x64, 0x06, 0x3e, 0x1c, 0x84, 0x00, 0x08, 0x7d, 0xe4, 0x7a, 0x14, + 0x4b, 0xff, 0xf8, 0x70, 0x40, 0x92, 0x00, 0x0c, 0x39, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x14, + 0x54, 0x69, 0x06, 0xff, 0x54, 0x65, 0x67, 0xfe, 0x7d, 0x08, 0x4c, 0x30, 0x55, 0x17, 0xff, 0xff, + 0x40, 0x82, 0x00, 0x08, 0x7d, 0x08, 0x2a, 0x78, 0x54, 0x85, 0x00, 0x1f, 0x41, 0x82, 0x00, 0x08, + 0x7c, 0xa6, 0x2b, 0x78, 0x54, 0x85, 0x80, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xb0, 0x2b, 0x78, + 0x4b, 0xff, 0xf8, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +}; +const int codehandlerslota_size = sizeof(codehandlerslota); diff --git a/source/patches/codehandlerslota.h b/source/patches/codehandlerslota.h new file mode 100644 index 0000000..5b5c93a --- /dev/null +++ b/source/patches/codehandlerslota.h @@ -0,0 +1,14 @@ +/* + This file was autogenerated by raw2c. +Visit http://www.devkitpro.org +*/ + +//--------------------------------------------------------------------------------- +#ifndef _codehandlerslota_h_ +#define _codehandlerslota_h_ +//--------------------------------------------------------------------------------- +extern const unsigned char codehandlerslota[]; +extern const int codehandlerslota_size; +//--------------------------------------------------------------------------------- +#endif //_codehandlerslota_h_ +//--------------------------------------------------------------------------------- diff --git a/source/patches/defaultgameconfig.h b/source/patches/defaultgameconfig.h new file mode 100644 index 0000000..0f8f350 --- /dev/null +++ b/source/patches/defaultgameconfig.h @@ -0,0 +1,11 @@ +/* + This file was autogenerated by raw2c. +Visit http://www.devkitpro.org +*/ + +const unsigned char defaultgameconfig[] = { + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x0a, 0x68, 0x6f, 0x6f, 0x6b, 0x74, 0x79, 0x70, + 0x65, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x76, 0x69, 0x64, 0x74, 0x76, 0x20, 0x3d, 0x20, 0x31, 0x0a, + 0x30, 0x30, 0x32, 0x66, 0x69, 0x78, 0x20, 0x3d, 0x20, 0x31, 0x0A +}; +const int defaultgameconfig_size = sizeof(defaultgameconfig); diff --git a/source/patches/dolpatcher.c b/source/patches/dolpatcher.c new file mode 100644 index 0000000..bc2daf3 --- /dev/null +++ b/source/patches/dolpatcher.c @@ -0,0 +1,19 @@ +#include +#include + +bool PatchDOL(u8 * Address, int Size, const u8 * SearchPattern, int SearchSize, const u8 * PatchData, int PatchSize) +{ + u8 * Addr = Address; + u8 * Addr_end = Address + Size; + + while (Addr <= Addr_end - SearchSize) + { + if (memcmp(Addr, SearchPattern, SearchSize) == 0) + { + memcpy(Addr, PatchData, PatchSize); + return true; + } + Addr += 4; + } + return false; +} diff --git a/source/patches/dolpatcher.h b/source/patches/dolpatcher.h new file mode 100644 index 0000000..09eb319 --- /dev/null +++ b/source/patches/dolpatcher.h @@ -0,0 +1,8 @@ +#ifndef DOLPATCHER_C_ +#define DOLPATCHER_C_ + +#include + +bool PatchDOL(u8 * Address, int Size, const u8 * SearchPattern, int SearchSize, const u8 * PatchData, int PatchSize); + +#endif diff --git a/source/patches/dvd_broadway.c b/source/patches/dvd_broadway.c new file mode 100644 index 0000000..55a4394 --- /dev/null +++ b/source/patches/dvd_broadway.c @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2008 Nuke (wiinuke@gmail.com) + * + * this file is part of GeckoOS for USB Gecko + * http://www.usbgecko.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvd_broadway.h" + +#define DI_CMDCTX_CNT 4 + +#define DVD_DISKIDSIZE 0x20 +#define DVD_DRVINFSIZE 0x20 + +#define IOCTL_DI_INQUIRY 0x12 +#define IOCTL_DI_READID 0x70 +#define IOCTL_DI_READ 0x71 +#define IOCTL_DI_WAITCVRCLOSE 0x79 +#define IOCTL_DI_COVER 0x7A +#define IOCTL_DI_RESETNOTIFY 0x7E +#define IOCTL_DI_RESET 0x8A +#define IOCTL_DI_OPENPART 0x8B +#define IOCTL_DI_CLOSEPART 0x8C +#define IOCTL_DI_UNENCREAD 0x8D +#define IOCTL_DI_ENABLE_DVD 0x8E +#define IOCTL_DI_SEEK 0xAB +#define IOCTL_DI_READ_DVDVIDEO 0xD0 +#define IOCTL_DI_STOPLASER 0xD2 +#define IOCTL_DI_OFFSET 0xD9 +#define IOCTL_DI_REQERROR 0xE0 +#define IOCTL_DI_STOPMOTOR 0xE3 +#define IOCTL_DI_SETOFFBASE 0xF0 +#define IOCTL_DI_GETOFFBASE 0xF1 +#define IOCTL_DI_SETCRYPTMODE 0xF2 +#define IOCTL_DI_GETCRYPTMODE 0xF3 +#define IOCTL_DI_SETDVDROMMODE 0xF4 +#define IOCTL_DI_GETDVDROMMODE 0xF5 + +#define _SHIFTL(v, s, w) \ + ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +struct dicommand +{ + u32 diReg[8]; +}; + +struct dicontext +{ + lwp_node node; + dvdcallbacklow cb; + struct dicommand *cmd; +}; + +static s32 __dvd_fd = -1; +static u32 __dvd_spinupval = 1; +static lwp_queue __di_contextq; +static u32 __dvd_readlength = 0; +static u32 __dvd_cbinprogress = 0; +static u32 __dvd_reqinprogress = 0; +static u32 __dvd_lowinitcalled = 0; +static struct dicommand *__di_commands = NULL; +static struct dicontext __di_contexts[DI_CMDCTX_CNT]; +static u32 __di_regbuffer[0x08] ATTRIBUTE_ALIGN( 32 ); +static u32 __di_regvalcache[0x08] ATTRIBUTE_ALIGN( 32 ); +static u32 __di_lastticketerror[0x08] ATTRIBUTE_ALIGN( 32 ); +static ioctlv __di_iovector[0x08] ATTRIBUTE_ALIGN( 32 ); +static char __di_fs[] ATTRIBUTE_ALIGN( 32 ) = "/dev/di"; + +extern u32 __IPC_ClntInit(); + +static __inline__ lwp_node* __lwp_queue_head(lwp_queue *queue) +{ + return (lwp_node*) queue; +} + +static __inline__ lwp_node* __lwp_queue_tail(lwp_queue *queue) +{ + return (lwp_node*) &queue->perm_null; +} + +static __inline__ void __lwp_queue_init_empty(lwp_queue *queue) +{ + queue->first = __lwp_queue_tail(queue); + queue->perm_null = NULL; + queue->last = __lwp_queue_head(queue); +} + +static struct dicontext* __dvd_getcontext(dvdcallbacklow cb) +{ + struct dicontext *ctx; + + ctx = (struct dicontext*) __lwp_queue_get(&__di_contextq); + if (ctx != NULL) ctx->cb = cb; + + return ctx; +} + +static s32 __dvd_iostransactionCB(s32 result, void *usrdata) +{ + struct dicontext *ctx = (struct dicontext*) usrdata; + + __dvd_reqinprogress = 0; + + if (ctx->cb != NULL) + { + __dvd_cbinprogress = 1; + if (result != 0) __dvd_readlength = 0; + ctx->cb(result); + __dvd_cbinprogress = 0; + } + __lwp_queue_append(&__di_contextq, &ctx->node); + + return 0; +} + +static s32 __dvd_ioscoverregisterCB(s32 result, void *usrdata) +{ + struct dicontext *ctx = (struct dicontext*) usrdata; + + __dvd_reqinprogress = 0; + __di_regvalcache[1] = __di_regbuffer[0]; + + if (ctx->cb != NULL) + { + __dvd_cbinprogress = 1; + ctx->cb(result); + __dvd_cbinprogress = 0; + } + __lwp_queue_append(&__di_contextq, &ctx->node); + + return 0; +} + +static s32 __dvd_ioscovercloseCB(s32 result, void *usrdata) +{ + struct dicontext *ctx = (struct dicontext*) usrdata; + + __dvd_reqinprogress = 0; + + if (ctx->cb != NULL) + { + __dvd_cbinprogress = 1; + ctx->cb(result); + __dvd_cbinprogress = 0; + } + __lwp_queue_append(&__di_contextq, &ctx->node); + + return 0; +} + +s32 bwDVD_LowInit() +{ + s32 i, ret = 0; + u32 ipclo, ipchi; + lwp_queue inactives; + struct dicontext *ctx; + + if (__dvd_lowinitcalled == 0) + { + ret = __IPC_ClntInit(); + if (ret < 0) return ret; + + ipclo = (((u32) IPC_GetBufferLo() + 0x1f) & ~0x1f); + ipchi = (u32) IPC_GetBufferHi(); + if (ipchi >= (ipclo + (sizeof(struct dicommand) * DI_CMDCTX_CNT))) + { + __di_commands = (struct dicommand*) ipclo; + IPC_SetBufferLo((void*) (ipclo + (sizeof(struct dicommand) * DI_CMDCTX_CNT))); + + memset(__di_commands, 0, (sizeof(struct dicommand) * DI_CMDCTX_CNT)); + + i = 0; + __lwp_queue_init_empty(&__di_contextq); + __lwp_queue_initialize(&inactives, __di_contexts, DI_CMDCTX_CNT, sizeof(struct dicontext)); + while ((ctx = (struct dicontext*) __lwp_queue_get(&inactives)) != NULL) + { + ctx->cmd = &__di_commands[i]; + ctx->cb = NULL; + __lwp_queue_append(&__di_contextq, &ctx->node); + + i++; + } + } + + ret = IOS_Open(__di_fs, 0); + if (ret < 0) return ret; + + __dvd_fd = ret; + // __dvd_lowinitcalled = 1; + + // printf("DVD_LowInit(%d)\n",ret); + } + return 0; +} + +s32 bwDVD_LowInquiry(dvddrvinfo *info, dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_INQUIRY << 24); + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_INQUIRY, cmd->diReg, sizeof(struct dicommand), info, DVD_DRVINFSIZE, + __dvd_iostransactionCB, ctx); + + return ret; +} + +s32 bwDVD_LowReadID(dvddiskid *diskID, dvdcallbacklow cb) +{ + s32 ret = 0; + struct dicontext *ctx; + struct dicommand *cmd; + + // printf("DVD_LowReadID()\n"); + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_READID << 24); + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_READID, cmd->diReg, sizeof(struct dicommand), diskID, DVD_DISKIDSIZE, + __dvd_iostransactionCB, ctx); + + // printf("DVD_LowReadID(%d)\n",ret); + return ret; +} + +s32 bwDVD_LowRead(void *buf, u32 len, u32 offset, dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + if (buf == NULL || ((u32) buf % 32) != 0) return -1; + + __dvd_reqinprogress = 1; + __dvd_readlength = len; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_READ << 24); + cmd->diReg[1] = len; + cmd->diReg[2] = offset; + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_READ, cmd->diReg, sizeof(struct dicommand), buf, len, + __dvd_iostransactionCB, ctx); + + return ret; +} + +// never got this function working, probably removed from wii +s32 bwDVD_LowReadVideo(void *buf, u32 len, u32 offset, dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + __dvd_readlength = len; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_READ_DVDVIDEO << 24); + cmd->diReg[1] = len; + cmd->diReg[2] = offset; + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_READ_DVDVIDEO, cmd->diReg, sizeof(struct dicommand), buf, len, + __dvd_iostransactionCB, ctx); + + return ret; +} + +s32 bwDVD_LowStopLaser(dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_STOPLASER << 24); + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_STOPLASER, cmd->diReg, sizeof(struct dicommand), __di_regvalcache, 0x20, + __dvd_iostransactionCB, ctx); + + return ret; +} + +// never got this function working, probably removed from wii +s32 bwDVD_EnableVideo(dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_ENABLE_DVD << 24); + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_ENABLE_DVD, cmd->diReg, sizeof(struct dicommand), __di_regvalcache, 0x20, + __dvd_iostransactionCB, ctx); + + return ret; +} + +s32 bwDVD_LowSeek(u32 offset, dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_SEEK << 24); + cmd->diReg[1] = offset; + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_SEEK, cmd->diReg, sizeof(struct dicommand), NULL, 0, + __dvd_iostransactionCB, ctx); + + return ret; +} + +s32 bwDVD_LowOffset(u64 offset, dvdcallbacklow cb) +{ + s32 ret; + //u32 *off = (u32*)(void*)(&offset); + union + { + u64 off64; + u32 off32[2]; + } off; + off.off64 = offset; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_OFFSET << 24); + cmd->diReg[1] = 0; + if (off.off32[0]) cmd->diReg[1] = 1; + cmd->diReg[2] = off.off32[1]; + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_OFFSET, cmd->diReg, sizeof(struct dicommand), __di_regvalcache, 0x20, + __dvd_iostransactionCB, ctx); + + return ret; +} + +s32 bwDVD_LowPrepareCoverRegister(dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_COVER << 24); + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_COVER, cmd->diReg, sizeof(struct dicommand), __di_regbuffer, 0x20, + __dvd_ioscoverregisterCB, ctx); + + return ret; +} + +s32 bwDVD_LowOpenPartition(u32 offset, void *eticket, u32 certin_len, void *certificate_in, void *certificate_out, + dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + if (eticket != NULL && ((u32) eticket % 32) != 0) return -1; + if (certificate_in != NULL && ((u32) certificate_in % 32) != 0) return -1; + if (certificate_out != NULL && ((u32) certificate_out % 32) != 0) return -1; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_OPENPART << 24); + cmd->diReg[1] = offset; + + __di_iovector[0].data = cmd; + __di_iovector[0].len = sizeof(struct dicommand); + + __di_iovector[1].data = eticket; + if (eticket == NULL) + __di_iovector[1].len = 0; + else __di_iovector[1].len = 676; + + __di_iovector[2].data = certificate_in; + if (certificate_in == NULL) + __di_iovector[2].len = 0; + else __di_iovector[2].len = certin_len; + + __di_iovector[3].data = certificate_out; + __di_iovector[3].len = 18916; + __di_iovector[4].data = __di_lastticketerror; + __di_iovector[4].len = 0x20; + ret = IOS_IoctlvAsync(__dvd_fd, IOCTL_DI_OPENPART, 3, 2, __di_iovector, __dvd_iostransactionCB, ctx); + + return ret; +} + +s32 bwDVD_LowClosePartition(dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_CLOSEPART << 24); + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_CLOSEPART, cmd->diReg, sizeof(struct dicommand), NULL, 0, + __dvd_iostransactionCB, ctx); + + return ret; +} + +s32 bwDVD_LowUnencryptedRead(void *buf, u32 len, u32 offset, dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + __dvd_readlength = len; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_UNENCREAD << 24); + cmd->diReg[1] = len; + cmd->diReg[2] = offset; + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_UNENCREAD, cmd->diReg, sizeof(struct dicommand), buf, len, + __dvd_iostransactionCB, ctx); + + return ret; +} + +s32 bwDVD_LowWaitCoverClose(dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_WAITCVRCLOSE << 24); + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_WAITCVRCLOSE, cmd->diReg, sizeof(struct dicommand), NULL, 0, + __dvd_ioscovercloseCB, ctx); + + return ret; +} + +s32 bwDVD_LowResetNotify() +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + if (__dvd_cbinprogress == 1) return -1; + + ctx = __dvd_getcontext(NULL); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_RESETNOTIFY << 24); + ret = IOS_Ioctl(__dvd_fd, IOCTL_DI_RESETNOTIFY, cmd->diReg, sizeof(struct dicommand), NULL, 0); + + return ret; +} + +s32 bwDVD_LowReset(dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + // printf("DVD_LowReset()\n"); + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_RESET << 24); + cmd->diReg[1] = __dvd_spinupval; + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_RESET, cmd->diReg, sizeof(struct dicommand), NULL, 0, + __dvd_iostransactionCB, ctx); + + // printf("DVD_LowReset(%d)\n",ret); + return ret; +} + +s32 bwDVD_LowStopMotor(u8 stop1, u8 stop2, dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_STOPMOTOR << 24); + cmd->diReg[1] = (stop1 << 24); + cmd->diReg[2] = (stop2 << 24); + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_STOPMOTOR, cmd->diReg, sizeof(struct dicommand), __di_regvalcache, 0x20, + __dvd_iostransactionCB, ctx); + + return ret; + +} + +s32 bwDVD_LowRequestError(dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_REQERROR << 24); + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_REQERROR, cmd->diReg, sizeof(struct dicommand), __di_regvalcache, 0x20, + __dvd_iostransactionCB, ctx); + + return ret; +} + +s32 bwDVD_SetDecryption(s32 mode, dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_SETCRYPTMODE << 24); + cmd->diReg[1] = mode; + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_SETCRYPTMODE, cmd->diReg, sizeof(struct dicommand), __di_regvalcache, 0x20, + __dvd_iostransactionCB, ctx); + + return ret; + +} + +s32 bwDVD_SetOffset(u32 offset, dvdcallbacklow cb) +{ + s32 ret; + struct dicontext *ctx; + struct dicommand *cmd; + + __dvd_reqinprogress = 1; + + ctx = __dvd_getcontext(cb); + if (ctx == NULL) return IPC_ENOMEM; + + cmd = ctx->cmd; + cmd->diReg[0] = (IOCTL_DI_SETOFFBASE << 24); + cmd->diReg[1] = offset; + ret = IOS_IoctlAsync(__dvd_fd, IOCTL_DI_SETOFFBASE, cmd->diReg, sizeof(struct dicommand), __di_regvalcache, 0x20, + __dvd_iostransactionCB, ctx); + + return ret; + +} diff --git a/source/patches/dvd_broadway.h b/source/patches/dvd_broadway.h new file mode 100644 index 0000000..7777c56 --- /dev/null +++ b/source/patches/dvd_broadway.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Nuke (wiinuke@gmail.com) + * + * this file is part of GeckoOS for USB Gecko + * http://www.usbgecko.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __DVD_BROADWAY_H__ +#define __DVD_BROADWAY_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef void (*dvdcallbacklow)(s32 result); + + s32 bwDVD_LowInit(); + s32 bwDVD_LowInquiry(dvddrvinfo *info, dvdcallbacklow cb); + s32 bwDVD_LowReadID(dvddiskid *diskID, dvdcallbacklow cb); + s32 bwDVD_LowClosePartition(dvdcallbacklow cb); + s32 bwDVD_LowOpenPartition(u32 offset, void *eticket, u32 certin_len, void *certificate_in, void *certificate_out, + dvdcallbacklow cb); + s32 bwDVD_LowUnencryptedRead(void *buf, u32 len, u32 offset, dvdcallbacklow cb); + s32 bwDVD_LowReset(dvdcallbacklow cb); + s32 bwDVD_LowWaitCoverClose(dvdcallbacklow cb); + s32 bwDVD_LowRead(void *buf, u32 len, u32 offset, dvdcallbacklow cb); + s32 bwDVD_EnableVideo(dvdcallbacklow cb); + s32 bwDVD_LowReadVideo(void *buf, u32 len, u32 offset, dvdcallbacklow cb); + s32 bwDVD_SetDecryption(s32 mode, dvdcallbacklow cb); + s32 bwDVD_SetOffset(u32 offset, dvdcallbacklow cb); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/source/patches/fwrite_patch.h b/source/patches/fwrite_patch.h new file mode 100644 index 0000000..6c3bbdb --- /dev/null +++ b/source/patches/fwrite_patch.h @@ -0,0 +1,9 @@ +unsigned char fwrite_patch_bin[] = { 0x7c, 0x84, 0x29, 0xd6, 0x39, 0x40, 0x00, 0x00, 0x94, 0x21, 0xff, 0xf0, 0x93, + 0xe1, 0x00, 0x0c, 0x7f, 0x8a, 0x20, 0x00, 0x40, 0x9c, 0x00, 0x64, 0x3d, 0x00, 0xcd, 0x00, 0x3d, 0x60, 0xcd, + 0x00, 0x3d, 0x20, 0xcd, 0x00, 0x61, 0x08, 0x68, 0x14, 0x61, 0x6b, 0x68, 0x24, 0x61, 0x29, 0x68, 0x20, 0x39, + 0x80, 0x00, 0xd0, 0x38, 0xc0, 0x00, 0x19, 0x38, 0xe0, 0x00, 0x00, 0x91, 0x88, 0x00, 0x00, 0x7c, 0x03, 0x50, + 0xae, 0x54, 0x00, 0xa0, 0x16, 0x64, 0x00, 0xb0, 0x00, 0x90, 0x0b, 0x00, 0x00, 0x90, 0xc9, 0x00, 0x00, 0x80, + 0x09, 0x00, 0x00, 0x70, 0x1f, 0x00, 0x01, 0x40, 0x82, 0xff, 0xf8, 0x80, 0x0b, 0x00, 0x00, 0x90, 0xe8, 0x00, + 0x00, 0x54, 0x00, 0x37, 0xfe, 0x7d, 0x4a, 0x02, 0x14, 0x7f, 0x8a, 0x20, 0x00, 0x41, 0x9c, 0xff, 0xc8, 0x7c, + 0xa3, 0x2b, 0x78, 0x83, 0xe1, 0x00, 0x0c, 0x38, 0x21, 0x00, 0x10, 0x4e, 0x80, 0x00, 0x20 }; +unsigned int fwrite_patch_bin_len = 136; diff --git a/source/patches/gamepatches.c b/source/patches/gamepatches.c new file mode 100644 index 0000000..3c80781 --- /dev/null +++ b/source/patches/gamepatches.c @@ -0,0 +1,1313 @@ +#include +#include +#include +#include +#include "usbloader/disc.h" +#include "dolpatcher.h" +#include "wip.h" +#include "gecko.h" +#include "patchcode.h" +#include "gamepatches.h" +#include "memory/memory.h" +#include "memory/mem2.h" +#include "settings/SettingsEnums.h" +#include "svnrev.h" + +typedef struct _appDOL +{ + u8 *dst; + int len; +} appDOL; + +static appDOL *dolList = NULL; +static int dolCount = 0; +extern GXRModeObj *rmode; + +void RegisterDOL(u8 *dst, int len) +{ + if(!dolList) + dolList = (appDOL *) MEM2_alloc(sizeof(appDOL)); + + appDOL *tmp = (appDOL *) MEM2_realloc(dolList, (dolCount+1)*sizeof(appDOL)); + if(!tmp) + { + MEM2_free(dolList); + dolCount = 0; + return; + } + + dolList = tmp; + dolList[dolCount].dst = dst; + dolList[dolCount].len = len; + dolCount++; +} + +void ClearDOLList() +{ + if(dolList) + MEM2_free(dolList); + dolList = NULL; + dolCount = 0; +} + +void gamepatches(u8 videoSelected, u8 videoPatchDol, u8 aspectForce, u8 languageChoice, u8 patchcountrystring, + u8 vipatch, u8 sneekVideoPatch, u8 hooktype, u64 returnTo, u8 privateServer) +{ + int i; + + /* If a wip file is loaded for this game this does nothing - Dimok */ + PoPPatch(); + NSMBPatch(); + + for(i = 0; i < dolCount; ++i) + { + u8 *dst = dolList[i].dst; + int len = dolList[i].len; + + VideoModePatcher(dst, len, videoSelected, videoPatchDol); + + dogamehooks(hooktype, dst, len); + + if (vipatch) + vidolpatcher(dst, len); + + if(sneekVideoPatch) + sneek_video_patch(dst, len); + + /*LANGUAGE PATCH - FISHEARS*/ + langpatcher(dst, len, languageChoice); + + /*Thanks to WiiPower*/ + if (patchcountrystring == 1) + PatchCountryStrings(dst, len); + + do_wip_code(dst, len); + + Anti_002_fix(dst, len); + + if(returnTo) + PatchReturnTo(dst, len, (u32) returnTo); + + if(aspectForce < 2) + PatchAspectRatio(dst, len, aspectForce); + + if(privateServer) + PrivateServerPatcher(dst, len, privateServer); + + DCFlushRange(dst, len); + ICInvalidateRange(dst, len); + } + + /* ERROR 002 fix (thanks to WiiPower for sharing this)*/ + *(u32 *)0x80003140 = *(u32 *)0x80003188; + + DCFlushRange((void*) 0x80000000, 0x3f00); + + free_wip(); + ClearDOLList(); +} + +/** Anti 002 fix for IOS 249 rev > 12 thanks to WiiPower **/ +bool Anti_002_fix(u8 * Address, int Size) +{ + u8 SearchPattern[12] = { 0x2C, 0x00, 0x00, 0x00, 0x48, 0x00, 0x02, 0x14, 0x3C, 0x60, 0x80, 0x00 }; + u8 PatchData[12] = { 0x2C, 0x00, 0x00, 0x00, 0x40, 0x82, 0x02, 0x14, 0x3C, 0x60, 0x80, 0x00 }; + return PatchDOL(Address, Size, (const u8 *) SearchPattern, sizeof(SearchPattern), (const u8 *) PatchData, sizeof(PatchData)); +} + + +/** 480p Pixel Fix Patch by leseratte + fix for a Nintendo Revolution SDK bug found by Extrems affecting early Wii console when using 480p video mode. + https://shmups.system11.org/viewtopic.php?p=1361158#p1361158 + https://github.com/ExtremsCorner/libogc-rice/commit/941d687e271fada68c359bbed98bed1fbb454448 + **/ +void PatchFix480p() +{ + u8 prefix[2] = { 0x4b, 0xff }; + + /// Patch offset: ----------VVVVVVVV + u32 Pattern_MKW[8] = { 0x38000065, 0x9b810019, 0x38810018, 0x386000e0, 0x98010018, 0x38a00002}; + u32 patches_MKW[2] = { 0x38600003, 0x98610019 }; + /// Used by: MKWii, Wii Play, Need for Speed Nitro, Wii Sports, ... + + /// Patch offset: ----------------------------------------------VVVVVVVV + u32 Pattern_NSMB[8] = { 0x38000065, 0x9801001c, 0x3881001c, 0x386000e0, 0x9b81001d, 0x38a00002}; + u32 patches_NSMB[2] = { 0x38a00003, 0x98a1001d }; + /// Used by: New Super Mario Bros, ... + + /* + * Code block that is being patched (in MKW): + * + * 4bffe30d: bl WaitMicroTime + * 38000065: li r0, 0x65 + * 9b810019: stb r28, 25(r1) // store the wrong value (1) + * 38810018: addi r4, r1, 0x18 + * 386000e0: li r3, 0xe0 + * 98010018: stb r0, 24(r1) + * 38a00002: li r5, 2 + * 4bffe73d: bl __VISendI2CData + * + * r28 is a register that is set to 1 at the beginning of the function. + * However, its contents are used elsewhere as well, so we can't just modify this one function. + * + * The following code first searches for one of the patterns above, then replaces the + * "stb r28, 25(r1)" instruction that stores the wrong value on the stack with a branch instead + * That branch branches to the injected custom code ("li r3, 3; stb r3, 25(r1)") that stores the + * correct value (3) instead. At the end of the injected code will be another branch that branches + * back to the instruction after the one that has been replaced (so, to "addi r4, r1, 0x18"). + * r3 can safely be used as a temporary register because its contents will be replaced immediately + * afterwards anyways. + * + */ + + void * offset = NULL; + void * addr = (void*)0x80000000; + u32 len = 0x900000; + + void * patch_ptr = 0 ; + void * a = addr; + + while ((char*)a < ((char*)addr + len)) { + if (memcmp(a, &Pattern_MKW, 6 * 4) == 0) { + // Found pattern? + if (memcmp(a - 4, &prefix, 2) == 0) { + if (memcmp(a + 8*4, &prefix, 2) == 0) { + offset = a + 4; + hexdump (a, 30); + patch_ptr = &patches_MKW; + break; + } + } + } + else if (memcmp(a, &Pattern_NSMB, 6 * 4) == 0) { + // Found pattern? + if (memcmp(a - 4, &prefix, 2) == 0) { + if (memcmp(a + 8*4, &prefix, 2) == 0) { + offset = a + 16; + hexdump (a, 30); + patch_ptr = &patches_NSMB; + break; + } + } + } + a+= 4; + } + + + + if (offset == 0) { + // offset is still 0, we didn't find the pattern, return + gprintf("Didn't find offset for 480p patch!\n"); + return; + } + + // If we are here, we found the offset. Lets grab some space + // from the heap for our patch + u32 old_heap_ptr = *(u32*)0x80003110; + *((u32*)0x80003110) = (old_heap_ptr - 0x20); + u32 heap_space = old_heap_ptr-0x20; + + gprintf("Found offset for 480p patch - create branch from 0x%x to heap (0x%x)\n", offset, heap_space); + hexdump (offset, 30); + + memcpy((void*)heap_space, patch_ptr, 8); + + *((u32*)offset) = 0x48000000 + (((u32)(heap_space) - ((u32)(offset))) & 0x3ffffff); + *((u32*)((u32)heap_space + 8)) = 0x48000000 + (((u32)((u32)offset + 4) - ((u32)(heap_space + 8))) & 0x3ffffff); + return; +} + +/** Patch URLs for private Servers - Thanks to ToadKing/wiilauncher-nossl **/ +void PrivateServerPatcher(void *addr, u32 len, u8 privateServer) +{ + + // Patch protocol https -> http + char *cur = (char *)addr; + const char *end = cur + len - 8; + do + { + if (memcmp(cur, "https://", 8) == 0 && cur[8] != 0) + { + int len = strlen(cur); + memmove(cur + 4, cur + 5, len - 5); + cur[len - 1] = 0; + cur += len; + } + } while (++cur < end); + + // Patch nintendowifi.net -> private server domain + if(privateServer == PRIVSERV_WIIMMFI ) + { + domainpatcher(addr, len, "wiimmfi.de"); + } + + //else if(privateServer == PRIVSERV_CUSTOM) + //domainpatcher(dst, len, Settings.CustomPrivateServer); + +} + +u32 do_new_wiimmfi() +{ + + // As of November 2018, Wiimmfi requires a special Wiimmfi patcher + // update which does a bit more than just patch the server adresses. + // This function is being called by GameBooter.cpp, right before + // jumping to the entry point (only for Mario Kart Wii & Wiimmfi), + // and applies all the necessary new patches to the game. + // This includes support for the new patcher update plus + // support for StaticR.rel patching. + + // This function has been implemented by Leseratte. Please don't + // try to modify it without speaking to the Wiimmfi team because + // doing so could have unintended side effects. + + // check region: + char region = *((char *)(0x80000003)); + char * patched; + void * patch1_offset, *patch2_offset, *patch3_offset; + + // define some offsets and variables depending on the region: + switch (region) { + case 'P': + patched = (char*)0x80276054; + patch1_offset = (void*)0x800ee3a0; + patch2_offset = (void*)0x801d4efc; + patch3_offset = (void*)0x801A72E0; + break; + case 'E': + patched = (char*)0x80271d14; + patch1_offset = (void*)0x800ee300; + patch2_offset = (void*)0x801d4e5c; + patch3_offset = (void*)0x801A7240; + break; + case 'J': + patched = (char*)0x802759f4; + patch1_offset = (void*)0x800ee2c0; + patch2_offset = (void*)0x801d4e1c; + patch3_offset = (void*)0x801A7200; + break; + case 'K': + patched = (char*)0x80263E34; + patch1_offset = (void*)0x800ee418; + patch2_offset = (void*)0x801d5258; + patch3_offset = (void*)0x801A763c; + break; + default: + return -1; + } + + if (*patched != '*') return -2; // ISO already patched + + // This RAM address is set (no asterisk) by all officially + // updated patchers, so if it is modified, the image is already + // patched with a new patcher and we don't need to patch anything. + + // For statistics and easier debugging in case of problems, Wiimmfi + // wants to know what patcher a game has been patched with, thus, + // let the game know the exact USB-Loader version. + char * fmt = "USB-Loader GX v3.0 R%-30s"; + char patcher[50] = {0}; + snprintf((char *)&patcher, 49, fmt, GetRev()); + strncpy(patched, (char *)&patcher, 42); + + // Do the plain old patching with the string search + PrivateServerPatcher((void*)0x80004000, 0x385200, PRIVSERV_WIIMMFI); + + // Replace some URLs for Wiimmfi's new update system + char newURL1[] = "http://ca.nas.wiimmfi.de/ca"; + char newURL2[] = "http://naswii.wiimmfi.de/ac"; + char newURL3P[] = "https://main.nas.wiimmfi.de/pp"; + char newURL3E[] = "https://main.nas.wiimmfi.de/pe"; + char newURL3J[] = "https://main.nas.wiimmfi.de/pj"; + char newURL3K[] = "https://main.nas.wiimmfi.de/pk"; + + + // Write the URLs to the proper place and do some other patching. + switch (region) { + case 'P': + memcpy((void*)0x8027A400, newURL1, sizeof(newURL1)); + memcpy((void*)0x8027A400 + 0x28, newURL2, sizeof(newURL2)); + memcpy((void*)0x8027A400 + 0x4C, newURL3P, sizeof(newURL3P)); + *(u32*)0x802a146c = 0x733a2f2f; + *(u32*)0x800ecaac = 0x3bc00000; + break; + case 'E': + memcpy((void*)0x802760C0, newURL1, sizeof(newURL1)); + memcpy((void*)0x802760C0 + 0x28, newURL2, sizeof(newURL2)); + memcpy((void*)0x802760C0 + 0x4C, newURL3E, sizeof(newURL3E)); + *(u32*)0x8029D12C = 0x733a2f2f; + *(u32*)0x800ECA0C = 0x3bc00000; + break; + case 'J': + memcpy((void*)0x80279DA0, newURL1, sizeof(newURL1)); + memcpy((void*)0x80279DA0 + 0x28, newURL2, sizeof(newURL2)); + memcpy((void*)0x80279DA0 + 0x4C, newURL3J, sizeof(newURL3J)); + *(u32*)0x802A0E0C = 0x733a2f2f; + *(u32*)0x800EC9CC = 0x3bc00000; + break; + case 'K': + memcpy((void*)0x802682B0, newURL1, sizeof(newURL1)); + memcpy((void*)0x802682B0 + 0x28, newURL2, sizeof(newURL2)); + memcpy((void*)0x802682B0 + 0x4C, newURL3K, sizeof(newURL3K)); + *(u32*)0x8028F474 = 0x733a2f2f; + *(u32*)0x800ECB24 = 0x3bc00000; + break; + } + + // Make some space on heap (0x400) for our custom code. + u32 old_heap_ptr = *(u32*)0x80003110; + *((u32*)0x80003110) = (old_heap_ptr - 0x400); + u32 heap_space = old_heap_ptr-0x400; + memset((void*)old_heap_ptr-0x400, 0xed, 0x400); + + // Binary blobs with Wiimmfi patches. Do not modify. + // Provided by Leseratte on 2018-12-14. + + int binary[] = { 0x37C849A2, 0x8BC32FA4, 0xC9A34B71, 0x1BCB49A2, + 0x2F119304, 0x5F402684, 0x3E4FDA29, 0x50849A21, + 0xB88B3452, 0x627FC9C1, 0xDC24D119, 0x5844350F, + 0xD893444F, 0x19A588DC, 0x16C91184, 0x0C3E237C, + 0x75906CED, 0x6E68A55E, 0x58791842, 0x072237E9, + 0xAB24906F, 0x0A8BDF21, 0x4D11BE42, 0x1AAEDDC8, + 0x1C42F908, 0x280CF2B2, 0x453A1BA4, 0x9A56C869, + 0x786F108E, 0xE8DF05D2, 0x6DB641EB, 0x6DFC84BB, + 0x7E980914, 0x0D7FB324, 0x23442185, 0xA7744966, + 0x53901359, 0xBF2103CC, 0xC24A4EB7, 0x32049A02, + 0xC1683466, 0xCA93689D, 0xD8245106, 0xA84987CF, + 0xEC9B47C9, 0x6FA688FE, 0x0A4D11A6, 0x8B653C7B, + 0x09D27E30, 0x5B936208, 0x5DD336DE, 0xCD092487, + 0xEF2C6D36, 0x1E09DF2D, 0x75B1BE47, 0xE68A7F22, + 0xB0E5F90D, 0xEC49F216, 0xAD1DCC24, 0xE2B5C841, + 0x066F6F63, 0xF4D90926, 0x299F42CD, 0xA3F125D6, + 0x077B093C, 0xB5721268, 0x1BE424D1, 0xEBC30BF0, + 0x77867BED, 0x4F0C9BCA, 0x3E195930, 0xDC32DE2C, + 0x1865D189, 0x70C67E7A, 0x71FA7329, 0x532233D3, + 0x06D2E87B, 0x6CBEBA7F, 0x99F08532, 0x52FA601C, + 0x05F4B82C, 0x4B64839C, 0xB5C65009, 0x1B8396E3, + 0x0A8B2DAF, 0x0DB85BE6, 0x12F1B71D, 0x186F6E4D, + 0x2870DC2E, 0x5960B8E6, 0x8F4D71BD, 0x0614E3C3, + 0x05E8C725, 0x365D8E3D, 0x74351CDE, 0xE1AB3930, + 0xFEDA721B, 0xE53AE4E9, 0xC3B4C9A6, 0xBAE59346, + 0x6D45269D, 0x634E4D1A, 0x2FD99A30, 0x26393449, + 0xE49768D1, 0x81E1D1A1, 0xFCE1A34A, 0x7EB44697, + 0xEB2F8D2D, 0xCECFE5AF, 0x81BD34B6, 0xB1F1696E, + 0x5E6ED2B2, 0xA473A4A0, 0x41664B70, 0xBF40968A, + 0x662F2CCB, 0xC5DF5B8C, 0xB632B772, 0x74EB6F39, + 0xE017DC71, 0xFDA3B890, 0xE3C9713D, 0xCE53E397, + 0xA12BC743, 0x5AD98EA5, 0xBC721C9F, 0x4568395A, + 0x925E72B4, 0x2D7DE4D7, 0x6777C9C7, 0xD6619396, + 0xA502268A, 0x77884D75, 0xF79E9AF0, 0xE6FC3461, + 0xF07468A5, 0xF866D11D, 0xF90CA342, 0xCF9546FF, + 0x87A48D81, 0x06881A51, 0x309C34D1, 0x79B669CE, + 0xFAADD2D7, 0xC8D7A5D1, 0x89214BE5, 0x1B8396EF, + 0x0A8B2DE9, 0x0D985B06, 0x12F1B711, 0x186F6E57, + 0x2850DC0E, 0x5960B8EA, 0x8F4D71AC, 0x0614E3E3, + 0x05E8C729, 0x365D8E39, 0x74351CFE, 0x518E3943, + 0x4A397268, 0x9D58E4B8, 0xD394C9A2, 0x0E069344, + 0xB522268B, 0x636E4D77, 0x2FF99A37, 0xF6DC346D, + 0xE49268B4, 0x2001D1A0, 0x4929A365, 0x7B764691, + 0xFFC68D49, 0x16A81A53, 0x247A34D2, 0xA1D16967, + 0x4B6DD2D5, 0xDDF4A5B7, 0x454A4B70, 0x0FAE96E2, + 0x0A8A2DC7, 0x0D98A47A, 0x06DCB71D, 0x0CCC6E38, + 0x55F25CFB, 0xB08C1E88, 0xDF4259C9, 0x0714E387, + 0xB00D47AF, 0x7B722975, 0x48BE349A, 0x29CC393C, + 0xEA797228, 0x98986471, 0x3778E1A3, 0xD7626D06, + 0x1567268D, 0x668ECD00, 0xD614F5C8, 0x133037CF, + 0x92F26CF2, 0x00000000, 0x00000000, 0x00000000}; + + // Prepare patching process .... + int i = 3; + int idx = 0; + for (; i < 202; i++) { + if (i == 67 || i == 82) idx++; + binary[i] = binary[i] ^ binary[idx]; + binary[idx] = ((binary[idx] << 1) | ((binary[idx] >> (32 - 1)) & ~(0xfffffffe))); + } + + + // Binary blob needs some changes for regions other than PAL ... + switch (region) { + case 'E': + binary[29] = binary[67]; + binary[37] = binary[68]; + binary[43] = binary[69]; + binary[185] = 0x61295C74; + binary[189] = 0x61295D40; + binary[198] = 0x61086F5C; + break; + case 'J': + binary[29] = binary[70]; + binary[37] = binary[71]; + binary[43] = binary[72]; + binary[185] = 0x612997CC; + binary[189] = 0x61299898; + binary[198] = 0x61086F1C; + break; + case 'K': + binary[6] = binary[73]; + binary[9] = binary[74]; + binary[11] = binary[75]; + binary[23] = binary[76]; + binary[29] = binary[77]; + binary[33] = binary[78]; + binary[37] = binary[79]; + binary[43] = binary[80]; + binary[63] = binary[81]; + binary[184] = 0x3D208088; + binary[185] = 0x61298AA4; + binary[188] = 0x3D208088; + binary[189] = 0x61298B58; + binary[198] = 0x61087358; + break; + } + + + // Installing all the patches. + + memcpy((void*)heap_space, (void*)binary, 820); + u32 code_offset_1 = heap_space + 12; + u32 code_offset_2 = heap_space + 88; + u32 code_offset_3 = heap_space + 92; + u32 code_offset_4 = heap_space + 264; + u32 code_offset_5 = heap_space + 328; + + + *((u32*)patch1_offset) = 0x48000000 + (((u32)(code_offset_1) - ((u32)(patch1_offset))) & 0x3ffffff); + *((u32*)code_offset_2) = 0x48000000 + (((u32)(patch1_offset + 4) - ((u32)(code_offset_2))) & 0x3ffffff); + *((u32*)patch2_offset) = 0x48000000 + (((u32)(code_offset_3) - ((u32)(patch2_offset))) & 0x3ffffff); + *((u32*)code_offset_4) = 0x48000000 + (((u32)(patch2_offset + 4) - ((u32)(code_offset_4))) & 0x3ffffff); + *((u32*)patch3_offset) = 0x48000000 + (((u32)(code_offset_5) - ((u32)(patch3_offset))) & 0x3ffffff); + + // Patches successfully installed + // returns 0 when all patching is done and game is ready to be booted. + return 0; +} + +void domainpatcher(void *addr, u32 len, const char* domain) +{ + if(strlen("nintendowifi.net") < strlen(domain)) + return; + + char *cur = (char *)addr; + const char *end = cur + len - 16; + + do + { + if (memcmp(cur, "nintendowifi.net", 16) == 0) + { + int len = strlen(cur); + u8 i; + memcpy(cur, domain, strlen(domain)); + memmove(cur + strlen(domain), cur + 16, len - 16); + for(i = 16 - strlen(domain); i > 0 ; i--) + cur[len - i ] = 0; + cur += len; + } + } while (++cur < end); +} + +bool NSMBPatch() +{ + WIP_Code * CodeList = NULL; + + if (memcmp("SMNE01", (char *) 0x80000000, 6) == 0) + { + CodeList = MEM2_alloc(3 * sizeof(WIP_Code)); + if(!CodeList) + return false; + + CodeList[0].offset = 0x001AB610; + CodeList[0].srcaddress = 0x9421FFD0; + CodeList[0].dstaddress = 0x4E800020; + CodeList[1].offset = 0x001CED53; + CodeList[1].srcaddress = 0xDA000000; + CodeList[1].dstaddress = 0x71000000; + CodeList[2].offset = 0x001CED6B; + CodeList[2].srcaddress = 0xDA000000; + CodeList[2].dstaddress = 0x71000000; + + } + else if (memcmp("SMNP01", (char *) 0x80000000, 6) == 0) + { + CodeList = MEM2_alloc(3 * sizeof(WIP_Code)); + if(!CodeList) + return false; + + CodeList[0].offset = 0x001AB750; + CodeList[0].srcaddress = 0x9421FFD0; + CodeList[0].dstaddress = 0x4E800020; + CodeList[1].offset = 0x001CEE90; + CodeList[1].srcaddress = 0x38A000DA; + CodeList[1].dstaddress = 0x38A00071; + CodeList[2].offset = 0x001CEEA8; + CodeList[2].srcaddress = 0x388000DA; + CodeList[2].dstaddress = 0x38800071; + } + else if (memcmp("SMNJ01", (char *) 0x80000000, 6) == 0) + { + CodeList = MEM2_alloc(3 * sizeof(WIP_Code)); + if(!CodeList) + return false; + + CodeList[0].offset = 0x001AB420; + CodeList[0].srcaddress = 0x9421FFD0; + CodeList[0].dstaddress = 0x4E800020; + CodeList[1].offset = 0x001CEB63; + CodeList[1].srcaddress = 0xDA000000; + CodeList[1].dstaddress = 0x71000000; + CodeList[2].offset = 0x001CEB7B; + CodeList[2].srcaddress = 0xDA000000; + CodeList[2].dstaddress = 0x71000000; + } + + if (CodeList && set_wip_list(CodeList, 3) == false) + { + MEM2_free(CodeList); + CodeList = NULL; + return false; + } + + + return CodeList != NULL; +} + +bool PoPPatch() +{ + if (memcmp("SPX", (char *) 0x80000000, 3) != 0 && memcmp("RPW", (char *) 0x80000000, 3) != 0) + return false; + + WIP_Code * CodeList = MEM2_alloc(5 * sizeof(WIP_Code)); + CodeList[0].offset = 0x007AAC6A; + CodeList[0].srcaddress = 0x7A6B6F6A; + CodeList[0].dstaddress = 0x6F6A7A6B; + CodeList[1].offset = 0x007AAC75; + CodeList[1].srcaddress = 0x7C7A6939; + CodeList[1].dstaddress = 0x69397C7A; + CodeList[2].offset = 0x007AAC82; + CodeList[2].srcaddress = 0x7376686B; + CodeList[2].dstaddress = 0x686B7376; + CodeList[3].offset = 0x007AAC92; + CodeList[3].srcaddress = 0x80717570; + CodeList[3].dstaddress = 0x75708071; + CodeList[4].offset = 0x007AAC9D; + CodeList[4].srcaddress = 0x82806F3F; + CodeList[4].dstaddress = 0x6F3F8280; + + if (set_wip_list(CodeList, 5) == false) + { + MEM2_free(CodeList); + CodeList = NULL; + return false; + } + + return true; +} + +/** Insert the individual gamepatches above with the patterns and patch data **/ +/** Following is only the VideoPatcher **/ + +// Some missing video modes +static GXRModeObj TVPal528Prog = { + 6, // viDisplayMode + 640, // fbWidth + 528, // efbHeight + 528, // xfbHeight + 40, // viXOrigin // (VI_MAX_WIDTH_PAL - 640)/2, + 23, // viYOrigin // game uses 0x17 instead of 0x18 so we don't use (VI_MAX_HEIGHT_PAL - 528)/2 + 640, // viWidth + 528, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 0, // line n-1 + 0, // line n-1 + 21, // line n + 22, // line n + 21, // line n + 0, // line n+1 + 0 // line n+1 + } +}; + +static GXRModeObj TVPal528ProgSoft = { + 6, // viDisplayMode + 640, // fbWidth + 528, // efbHeight + 528, // xfbHeight + 40, // viXOrigin + 23, // viYOrigin + 640, // viWidth + 528, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_FALSE, // aa + + // sample points arranged in increasing Y order + { + {6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {6,6},{6,6},{6,6}, // pix 1 + {6,6},{6,6},{6,6}, // pix 2 + {6,6},{6,6},{6,6} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 8, // line n-1 + 8, // line n-1 + 10, // line n + 12, // line n + 10, // line n + 8, // line n+1 + 8 // line n+1 + } + +}; + +static GXRModeObj TVPal524ProgAa = { + 6, // viDisplayMode + 640, // fbWidth + 264, // efbHeight + 524, // xfbHeight + 40, // viXOrigin + 23, // viYOrigin + 640, // viWidth + 524, // viHeight + VI_XFBMODE_SF, // xFBmode + GX_FALSE, // field_rendering + GX_TRUE, // aa + + // sample points arranged in increasing Y order + { + {3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each + {3,2},{9,6},{3,10}, // pix 1 + {9,2},{3,6},{9,10}, // pix 2 + {9,2},{3,6},{9,10} // pix 3 + }, + + // vertical filter[7], 1/64 units, 6 bits each + { + 4, // line n-1 + 8, // line n-1 + 12, // line n + 16, // line n + 12, // line n + 8, // line n+1 + 4 // line n+1 + } + +}; + +static GXRModeObj* vmodes[] = { + &TVNtsc240Ds, + &TVNtsc240DsAa, + &TVNtsc240Int, + &TVNtsc240IntAa, + &TVNtsc480Int, + &TVNtsc480IntAa, + &TVNtsc480IntDf, + &TVNtsc480Prog, + &TVNtsc480ProgSoft, + &TVNtsc480ProgAa, + &TVMpal480IntDf, + &TVPal264Ds, + &TVPal264DsAa, + &TVPal264Int, + &TVPal264IntAa, + &TVPal524ProgAa, + &TVPal524IntAa, + &TVPal528Int, + &TVPal528IntDf, + &TVPal528Prog, + &TVPal528ProgSoft, + &TVPal576IntDfScale, + &TVEurgb60Hz240Ds, + &TVEurgb60Hz240DsAa, + &TVEurgb60Hz240Int, + &TVEurgb60Hz240IntAa, + &TVEurgb60Hz480Int, + &TVEurgb60Hz480IntDf, + &TVEurgb60Hz480IntAa, + &TVEurgb60Hz480Prog, + &TVEurgb60Hz480ProgSoft, + &TVEurgb60Hz480ProgAa +}; + +static const char * vmodes_name[] = { + "TVNtsc240Ds", + "TVNtsc240DsAa", + "TVNtsc240Int", + "TVNtsc240IntAa", + "TVNtsc480Int", + "TVNtsc480IntAa", + "TVNtsc480IntDf", + "TVNtsc480Prog", + "TVNtsc480ProgSoft", + "TVNtsc480ProgAa", + "TVMpal480IntDf", + "TVPal264Ds", + "TVPal264DsAa", + "TVPal264Int", + "TVPal264IntAa", + "TVPal524ProgAa", + "TVPal524IntAa", + "TVPal528Int", + "TVPal528IntDf", + "TVPal528Prog", + "TVPal528ProgSoft", + "TVPal576IntDfScale", + "TVEurgb60Hz240Ds", + "TVEurgb60Hz240DsAa", + "TVEurgb60Hz240Int", + "TVEurgb60Hz240IntAa", + "TVEurgb60Hz480Int", + "TVEurgb60Hz480IntDf", + "TVEurgb60Hz480IntAa", + "TVEurgb60Hz480Prog", + "TVEurgb60Hz480ProgSoft", + "TVEurgb60Hz480ProgAa" +}; + +static GXRModeObj* PAL2NTSC[] = { + &TVMpal480IntDf, &TVNtsc480IntDf, + &TVPal264Ds, &TVNtsc240Ds, + &TVPal264DsAa, &TVNtsc240DsAa, + &TVPal264Int, &TVNtsc240Int, + &TVPal264IntAa, &TVNtsc240IntAa, + &TVPal524IntAa, &TVNtsc480IntAa, + &TVPal528Int, &TVNtsc480Int, + &TVPal528IntDf, &TVNtsc480IntDf, + &TVPal528Prog, &TVNtsc480Prog, + &TVPal576IntDfScale, &TVNtsc480IntDf, + &TVEurgb60Hz240Ds, &TVNtsc240Ds, + &TVEurgb60Hz240DsAa, &TVNtsc240DsAa, + &TVEurgb60Hz240Int, &TVNtsc240Int, + &TVEurgb60Hz240IntAa, &TVNtsc240IntAa, + &TVEurgb60Hz480Int, &TVNtsc480Int, + &TVEurgb60Hz480IntDf, &TVNtsc480IntDf, + &TVEurgb60Hz480IntAa, &TVNtsc480IntAa, + &TVEurgb60Hz480Prog, &TVNtsc480Prog, + &TVEurgb60Hz480ProgSoft, &TVNtsc480Prog, + &TVEurgb60Hz480ProgAa, &TVNtsc480Prog, + 0, 0 +}; + +static GXRModeObj* NTSC2PAL[] = { + &TVNtsc240Ds, &TVPal264Ds, + &TVNtsc240DsAa, &TVPal264DsAa, + &TVNtsc240Int, &TVPal264Int, + &TVNtsc240IntAa, &TVPal264IntAa, + &TVNtsc480Int, &TVPal528Int, + &TVNtsc480IntDf, &TVPal528IntDf, + &TVNtsc480IntAa, &TVPal524IntAa, + &TVNtsc480Prog, &TVPal528Prog, + 0, 0 +}; + +static GXRModeObj* NTSC2PAL60[] = { + &TVNtsc240Ds, &TVEurgb60Hz240Ds, + &TVNtsc240DsAa, &TVEurgb60Hz240DsAa, + &TVNtsc240Int, &TVEurgb60Hz240Int, + &TVNtsc240IntAa, &TVEurgb60Hz240IntAa, + &TVNtsc480Int, &TVEurgb60Hz480Int, + &TVNtsc480IntDf, &TVEurgb60Hz480IntDf, + &TVNtsc480IntAa, &TVEurgb60Hz480IntAa, + &TVNtsc480Prog, &TVEurgb60Hz480Prog, + 0, 0 +}; + +static bool compare_videomodes(GXRModeObj* mode1, GXRModeObj* mode2) +{ + if (mode1->viTVMode != mode2->viTVMode || mode1->fbWidth != mode2->fbWidth || mode1->efbHeight != mode2->efbHeight + || mode1->xfbHeight != mode2->xfbHeight || mode1->viXOrigin != mode2->viXOrigin || mode1->viYOrigin + != mode2->viYOrigin || mode1->viWidth != mode2->viWidth || mode1->viHeight != mode2->viHeight + || mode1->xfbMode != mode2->xfbMode || mode1->field_rendering != mode2->field_rendering || mode1->aa + != mode2->aa || mode1->sample_pattern[0][0] != mode2->sample_pattern[0][0] || mode1->sample_pattern[1][0] + != mode2->sample_pattern[1][0] || mode1->sample_pattern[2][0] != mode2->sample_pattern[2][0] + || mode1->sample_pattern[3][0] != mode2->sample_pattern[3][0] || mode1->sample_pattern[4][0] + != mode2->sample_pattern[4][0] || mode1->sample_pattern[5][0] != mode2->sample_pattern[5][0] + || mode1->sample_pattern[6][0] != mode2->sample_pattern[6][0] || mode1->sample_pattern[7][0] + != mode2->sample_pattern[7][0] || mode1->sample_pattern[8][0] != mode2->sample_pattern[8][0] + || mode1->sample_pattern[9][0] != mode2->sample_pattern[9][0] || mode1->sample_pattern[10][0] + != mode2->sample_pattern[10][0] || mode1->sample_pattern[11][0] != mode2->sample_pattern[11][0] + || mode1->sample_pattern[0][1] != mode2->sample_pattern[0][1] || mode1->sample_pattern[1][1] + != mode2->sample_pattern[1][1] || mode1->sample_pattern[2][1] != mode2->sample_pattern[2][1] + || mode1->sample_pattern[3][1] != mode2->sample_pattern[3][1] || mode1->sample_pattern[4][1] + != mode2->sample_pattern[4][1] || mode1->sample_pattern[5][1] != mode2->sample_pattern[5][1] + || mode1->sample_pattern[6][1] != mode2->sample_pattern[6][1] || mode1->sample_pattern[7][1] + != mode2->sample_pattern[7][1] || mode1->sample_pattern[8][1] != mode2->sample_pattern[8][1] + || mode1->sample_pattern[9][1] != mode2->sample_pattern[9][1] || mode1->sample_pattern[10][1] + != mode2->sample_pattern[10][1] || mode1->sample_pattern[11][1] != mode2->sample_pattern[11][1] + || mode1->vfilter[0] != mode2->vfilter[0] || mode1->vfilter[1] != mode2->vfilter[1] || mode1->vfilter[2] + != mode2->vfilter[2] || mode1->vfilter[3] != mode2->vfilter[3] || mode1->vfilter[4] != mode2->vfilter[4] + || mode1->vfilter[5] != mode2->vfilter[5] || mode1->vfilter[6] != mode2->vfilter[6]) + { + return false; + } + else + { + return true; + } +} + +static void patch_videomode(GXRModeObj* mode1, GXRModeObj* mode2) +{ + mode1->viTVMode = mode2->viTVMode; + mode1->fbWidth = mode2->fbWidth; + mode1->efbHeight = mode2->efbHeight; + mode1->xfbHeight = mode2->xfbHeight; + mode1->viXOrigin = mode2->viXOrigin; + mode1->viYOrigin = mode2->viYOrigin; + mode1->viWidth = mode2->viWidth; + mode1->viHeight = mode2->viHeight; + mode1->xfbMode = mode2->xfbMode; + mode1->field_rendering = mode2->field_rendering; + mode1->aa = mode2->aa; + mode1->sample_pattern[0][0] = mode2->sample_pattern[0][0]; + mode1->sample_pattern[1][0] = mode2->sample_pattern[1][0]; + mode1->sample_pattern[2][0] = mode2->sample_pattern[2][0]; + mode1->sample_pattern[3][0] = mode2->sample_pattern[3][0]; + mode1->sample_pattern[4][0] = mode2->sample_pattern[4][0]; + mode1->sample_pattern[5][0] = mode2->sample_pattern[5][0]; + mode1->sample_pattern[6][0] = mode2->sample_pattern[6][0]; + mode1->sample_pattern[7][0] = mode2->sample_pattern[7][0]; + mode1->sample_pattern[8][0] = mode2->sample_pattern[8][0]; + mode1->sample_pattern[9][0] = mode2->sample_pattern[9][0]; + mode1->sample_pattern[10][0] = mode2->sample_pattern[10][0]; + mode1->sample_pattern[11][0] = mode2->sample_pattern[11][0]; + mode1->sample_pattern[0][1] = mode2->sample_pattern[0][1]; + mode1->sample_pattern[1][1] = mode2->sample_pattern[1][1]; + mode1->sample_pattern[2][1] = mode2->sample_pattern[2][1]; + mode1->sample_pattern[3][1] = mode2->sample_pattern[3][1]; + mode1->sample_pattern[4][1] = mode2->sample_pattern[4][1]; + mode1->sample_pattern[5][1] = mode2->sample_pattern[5][1]; + mode1->sample_pattern[6][1] = mode2->sample_pattern[6][1]; + mode1->sample_pattern[7][1] = mode2->sample_pattern[7][1]; + mode1->sample_pattern[8][1] = mode2->sample_pattern[8][1]; + mode1->sample_pattern[9][1] = mode2->sample_pattern[9][1]; + mode1->sample_pattern[10][1] = mode2->sample_pattern[10][1]; + mode1->sample_pattern[11][1] = mode2->sample_pattern[11][1]; + mode1->vfilter[0] = mode2->vfilter[0]; + mode1->vfilter[1] = mode2->vfilter[1]; + mode1->vfilter[2] = mode2->vfilter[2]; + mode1->vfilter[3] = mode2->vfilter[3]; + mode1->vfilter[4] = mode2->vfilter[4]; + mode1->vfilter[5] = mode2->vfilter[5]; + mode1->vfilter[6] = mode2->vfilter[6]; +} + +static bool Search_and_patch_Video_Modes(u8 * Address, u32 Size, GXRModeObj* Table[]) +{ + u8 *Addr = (u8 *) Address; + bool found = 0; + u32 i, j; + + while (Size >= sizeof(GXRModeObj)) + { + for (i = 0; Table[i]; i += 2) + { + if (compare_videomodes(Table[i], (GXRModeObj*) Addr)) + { + u8 current_vmode = 0; + u8 target_vmode = 0; + for(j = 0; j < sizeof(vmodes)/sizeof(vmodes[0]); j++) + { + if(compare_videomodes(Table[i], vmodes[j])) + { + current_vmode = j; + break; + } + } + for(j = 0; j < sizeof(vmodes)/sizeof(vmodes[0]); j++) + { + if(compare_videomodes(Table[i+1], vmodes[j])) + { + target_vmode = j; + break; + } + } + + gprintf("Video mode found in dol: %s, replaced by: %s \n", vmodes_name[current_vmode], vmodes_name[target_vmode]); + found = 1; + patch_videomode((GXRModeObj*) Addr, Table[i + 1]); + Addr += (sizeof(GXRModeObj) - 4); + Size -= (sizeof(GXRModeObj) - 4); + break; + } + } + + Addr += 4; + Size -= 4; + } + + return found; +} + +static bool Search_and_patch_Video_To(void *Address, u32 Size, GXRModeObj* Table[], GXRModeObj* rmode, bool patchAll) +{ + u8 *Addr = (u8 *)Address; + bool found = 0; + u32 i; + + u8 target_vmode = 0; + for(i = 0; i < sizeof(vmodes)/sizeof(vmodes[0]); i++) + { + if(compare_videomodes(Table[i], rmode)) + { + target_vmode = i; + break; + } + } + + while(Size >= sizeof(GXRModeObj)) + { + // Video mode pattern found + if( (((GXRModeObj*)Addr)->fbWidth == 0x0280 && ((GXRModeObj*)Addr)->viWidth == 0x02c4) || // TVEurgb60Hz480Prog + (((GXRModeObj*)Addr)->fbWidth == 0x0280 && ((GXRModeObj*)Addr)->viWidth == 0x0280) ) // All other video modes + { + // display found video mode patterns + GXRModeObj* vidmode = (GXRModeObj*)Addr; + gprintf("Video pattern found \t%08x %04x %04x %04x %04x %04x %04x %04x %08x %04x %04x ", + vidmode->viTVMode, vidmode->fbWidth, vidmode->efbHeight, vidmode->xfbHeight, vidmode->viXOrigin, vidmode->viYOrigin, + vidmode->viWidth, vidmode->viHeight, vidmode->xfbMode, vidmode->field_rendering, vidmode->aa); + gprintf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x ", + vidmode->sample_pattern[0][0], vidmode->sample_pattern[1][0], vidmode->sample_pattern[2][0], vidmode->sample_pattern[3][0], vidmode->sample_pattern[4][0], + vidmode->sample_pattern[5][0], vidmode->sample_pattern[6][0], vidmode->sample_pattern[7][0], vidmode->sample_pattern[8][0], vidmode->sample_pattern[9][0], + vidmode->sample_pattern[10][0], vidmode->sample_pattern[11][0], vidmode->sample_pattern[0][1], vidmode->sample_pattern[1][1], vidmode->sample_pattern[2][1], + vidmode->sample_pattern[3][1], vidmode->sample_pattern[4][1], vidmode->sample_pattern[5][1], vidmode->sample_pattern[6][1], vidmode->sample_pattern[7][1], + vidmode->sample_pattern[8][1], vidmode->sample_pattern[9][1], vidmode->sample_pattern[10][1], vidmode->sample_pattern[11][1]); + gprintf("%02x%02x%02x%02x%02x%02x%02x \n", + vidmode->vfilter[0], vidmode->vfilter[1] , vidmode->vfilter[2], vidmode->vfilter[3] , vidmode->vfilter[4],vidmode->vfilter[5], vidmode->vfilter[6]); + + found = 0; + for(i = 0; i < sizeof(vmodes)/sizeof(vmodes[0]); i++) + { + if(compare_videomodes(Table[i], (GXRModeObj*)Addr)) + { + found = 1; + gprintf("Video mode found in dol: %s, replaced by: %s \n", vmodes_name[i], vmodes_name[target_vmode]); + patch_videomode((GXRModeObj*)Addr, rmode); + Addr += (sizeof(GXRModeObj)-4); + Size -= (sizeof(GXRModeObj)-4); + break; + } + + } + if(patchAll && !found) + { + gprintf("Video mode found in dol: Unknown, replaced by: %s \n", vmodes_name[target_vmode]); + patch_videomode((GXRModeObj*)Addr, rmode); + Addr += (sizeof(GXRModeObj)-4); + Size -= (sizeof(GXRModeObj)-4); + } + } + Addr += 4; + Size -= 4; + } + + return found; +} + +void VideoModePatcher(u8 * dst, int len, u8 videoSelected, u8 VideoPatchDol) +{ + GXRModeObj** table = NULL; + if (videoSelected == VIDEO_MODE_PATCH) // patch enum'd in cfg.h + { + switch (CONF_GetVideo()) + { + case CONF_VIDEO_PAL: + table = CONF_GetEuRGB60() > 0 ? NTSC2PAL60 : NTSC2PAL; + break; + case CONF_VIDEO_MPAL: + table = NTSC2PAL; + break; + default: + table = PAL2NTSC; + break; + } + Search_and_patch_Video_Modes(dst, len, table); + } + else if(VideoPatchDol == VIDEO_PATCH_DOL_REGION ) //&& rmode != NULL) + { + switch(rmode->viTVMode >> 2) + { + case VI_PAL: + case VI_MPAL: + table = NTSC2PAL; + break; + case VI_EURGB60: + table = NTSC2PAL60; + break; + default: + table = PAL2NTSC; + } + Search_and_patch_Video_Modes(dst, len, table); + } + else if (VideoPatchDol == VIDEO_PATCH_DOL_ON && rmode != NULL) + { + Search_and_patch_Video_To(dst, len, vmodes, rmode, false); + } + else if (VideoPatchDol == VIDEO_PATCH_DOL_ALL && rmode != NULL) + { + Search_and_patch_Video_To(dst, len, vmodes, rmode, true); + } +} + +void sneek_video_patch(void *addr, u32 len) +{ + u8 *addr_start = addr; + u8 *addr_end = addr+len; + + while(addr_start < addr_end) + { + if(*(vu32*)(addr_start) == 0x3C608000) + { + if( ((*(vu32*)(addr_start+4) & 0xFC1FFFFF ) == 0x800300CC) && ((*(vu32*)(addr_start+8) >> 24) == 0x54 ) ) + { + *(vu32*)(addr_start+4) = 0x5400F0BE | ((*(vu32*)(addr_start+4) & 0x3E00000) >> 5); + } + } + addr_start += 4; + } +} + +//giantpune's magic super patch to return to channels + +static u32 ad[ 4 ] = { 0, 0, 0, 0 };//these variables are global on the off chance the different parts needed +static u8 found = 0; //to find in the dol are found in different sections of the dol +static u8 returnToPatched = 0; + +bool PatchReturnTo( void *Address, int Size, u32 id ) +{ + if( !id || returnToPatched ) + return 0; + //gprintf("PatchReturnTo( %p, %08x, %08x )\n", Address, Size, id ); + + //new __OSLoadMenu() (SM2.0 and higher) + u8 SearchPattern[ 12 ] = { 0x38, 0x80, 0x00, 0x02, 0x38, 0x60, 0x00, 0x01, 0x38, 0xa0, 0x00, 0x00 }; //li r4,2 + //li r3,1 + //li r5,0 + //old _OSLoadMenu() (used in launch games) + u8 SearchPatternB[ 12 ] = { 0x38, 0xC0, 0x00, 0x02, 0x38, 0xA0, 0x00, 0x01, 0x38, 0xE0, 0x00, 0x00 }; //li r6,2 + //li r5,1 + //li r7,0 + //identifier for the safe place + u8 SearchPattern2[ 12 ] = { 0x4D, 0x65, 0x74, 0x72, 0x6F, 0x77, 0x65, 0x72, 0x6B, 0x73, 0x20, 0x54 }; //"Metrowerks T" + + u8 oldSDK = 0; + found = 0; + + void *Addr = Address; + void *Addr_end = Address+Size; + + while (Addr <= Addr_end - 12 ) + { + //find a safe place or the patch to hang out + if ( ! ad[ 3 ] && memcmp( Addr, SearchPattern2, 12 ) == 0 ) + { + ad[ 3 ] = (u32)Addr + 0x30; + } + //find __OSLaunchMenu() and remember some addresses in it + else if ( memcmp( Addr, SearchPattern, 12 )==0 ) + { + ad[ found++ ] = (u32)Addr; + } + else if ( ad[ 0 ] && memcmp( Addr, SearchPattern, 8 )==0 ) //after the first match is found, only search the first 8 bytes for the other 2 + { + if( !ad[ 1 ] ) ad[ found++ ] = (u32)Addr; + else if( !ad[ 2 ] ) ad[ found++ ] = (u32)Addr; + if( found >= 3 )break; + } + Addr += 4; + } + //check for the older-ass version of the SDK + if( found < 3 && ad[ 3 ] ) + { + Addr = Address; + ad[ 0 ] = 0; + ad[ 1 ] = 0; + ad[ 2 ] = 0; + found = 0; + oldSDK = 1; + + while (Addr <= Addr_end - 12 ) + { + //find __OSLaunchMenu() and remember some addresses in it + if ( memcmp( Addr, SearchPatternB, 12 )==0 ) + { + ad[ found++ ] = (u32)Addr; + } + else if ( ad[ 0 ] && memcmp( Addr, SearchPatternB, 8 ) == 0 ) //after the first match is found, only search the first 8 bytes for the other 2 + { + if( !ad[ 1 ] ) ad[ found++ ] = (u32)Addr; + else if( !ad[ 2 ] ) ad[ found++ ] = (u32)Addr; + if( found >= 3 )break; + } + Addr += 4; + } + } + + //if the function is found + if( found == 3 && ad[ 3 ] ) + { + //gprintf("patch __OSLaunchMenu( 0x00010001, 0x%08x )\n", id); + u32 nop = 0x60000000; + + //the magic that writes the TID to the registers + u8 jump[ 20 ] = { 0x3C, 0x60, 0x00, 0x01, //lis r3,1 + 0x60, 0x63, 0x00, 0x01, //ori r3,r3,1 + 0x3C, 0x80, (u8)( id >> 24 ), (u8)( id >> 16 ), //lis r4,(u16)(tid >> 16) + 0x60, 0x84, (u8)( id >> 8 ), (u8)id, //ori r4,r4,(u16)(tid) + 0x4E, 0x80, 0x00, 0x20 + }; //blr + + if( oldSDK ) + { + jump[ 1 ] = 0xA0; //3CA00001 //lis r5,1 + jump[ 5 ] = 0xA5; //60A50001 //ori r5,r5,1 + jump[ 9 ] = 0xC0; //3CC0AF1B //lis r6,(u16)(tid >> 16) + jump[ 13 ] = 0xC6;//60C6F516 //ori r6,r6,(u16)(tid) + } + + void* addr = (u32*)ad[ 3 ]; + + //write new stuff to in a unused part of the main.dol + memcpy( addr, jump, sizeof( jump ) ); + + //ES_GetTicketViews() + u32 newval = ( ad[ 3 ] - ad[ 0 ] ); + newval &= 0x03FFFFFC; + newval |= 0x48000001; + addr = (u32*)ad[ 0 ]; + memcpy( addr, &newval, sizeof( u32 ) ); //bl ad[ 3 ] + memcpy( addr + 4, &nop, sizeof( u32 ) ); //nop + //gprintf("\t%08x -> %08x\n", addr, newval ); + + //ES_GetTicketViews() again + newval = ( ad[ 3 ] - ad[ 1 ] ); + newval &= 0x03FFFFFC; + newval |= 0x48000001; + addr = (u32*)ad[ 1 ]; + memcpy( addr, &newval, sizeof( u32 ) ); //bl ad[ 3 ] + memcpy( addr + 4, &nop, sizeof( u32 ) ); //nop + //gprintf("\t%08x -> %08x\n", addr, newval ); + + //ES_LaunchTitle() + newval = ( ad[ 3 ] - ad[ 2 ] ); + newval &= 0x03FFFFFC; + newval |= 0x48000001; + addr = (u32*)ad[ 2 ]; + memcpy( addr, &newval, sizeof( u32 ) ); //bl ad[ 3 ] + memcpy( addr + 4, &nop, sizeof( u32 ) ); //nop + //gprintf("\t%08x -> %08x\n", addr, newval ); + + returnToPatched = 1; + } + + if(returnToPatched) + gprintf("Return to %08X patched with old method.\n", (u32) id); + + return returnToPatched; +} + +int PatchNewReturnTo(int es_fd, u64 title) +{ + if(es_fd < 0 || title == 0) + return -1; + + //! this is here for test purpose only and needs be moved later + static u64 sm_title_id ATTRIBUTE_ALIGN(32); + ioctlv *vector = (ioctlv *) memalign(32, sizeof(ioctlv)); + if(!vector) + return -1; + + sm_title_id = title; + vector[0].data = &sm_title_id; + vector[0].len = sizeof(sm_title_id); + + int result = -1; + + if(es_fd >= 0) + result = IOS_Ioctlv(es_fd, 0xA1, 1, 0, vector); + + if(result >= 0) + gprintf("Return to %08X patched with d2x method.\n", (u32) title); + + free(vector); + + return result; +} + +int BlockIOSReload(int es_fd, u8 gameIOS) +{ + if(es_fd < 0) + return -1; + + static int mode ATTRIBUTE_ALIGN(32); + static int ios ATTRIBUTE_ALIGN(32); + ioctlv *vector = (ioctlv *) memalign(32, sizeof(ioctlv) * 2); + if(!vector) + return -1; + + int inlen = 2; + mode = 2; + ios = gameIOS; // ios to be reloaded in place of the requested one + vector[0].data = &mode; + vector[0].len = 4; + vector[1].data = &ios; + vector[1].len = 4; + + int result = -1; + + if(es_fd >= 0) + result = IOS_Ioctlv(es_fd, 0xA0, inlen, 0, vector); + + if(result >= 0) + gprintf("Block IOS Reload patched with d2x method to IOS%i; result: %i\n", gameIOS, result); + + free(vector); + + return result; +} + + +void PatchAspectRatio(void *addr, u32 len, u8 aspect) +{ + if(aspect > 1) + return; + + static const u32 aspect_searchpattern1[5] = { + 0x9421FFF0, 0x7C0802A6, 0x38800001, 0x90010014, 0x38610008 + }; + + static const u32 aspect_searchpattern2[15] = { + 0x2C030000, 0x40820010, 0x38000000, 0x98010008, 0x48000018, + 0x88010008, 0x28000001, 0x4182000C, 0x38000000, 0x98010008, + 0x80010014, 0x88610008, 0x7C0803A6, 0x38210010, 0x4E800020 + }; + + u8 *addr_start = (u8 *) addr; + u8 *addr_end = addr_start + len - sizeof(aspect_searchpattern1) - 4 - sizeof(aspect_searchpattern2); + + while(addr_start < addr_end) + { + if( (memcmp(addr_start, aspect_searchpattern1, sizeof(aspect_searchpattern1)) == 0) + && (memcmp(addr_start + 4 + sizeof(aspect_searchpattern1), aspect_searchpattern2, sizeof(aspect_searchpattern2)) == 0)) + { + *((u32 *)(addr_start+0x44)) = (0x38600000 | aspect); + gprintf("Aspect ratio patched to: %s\n", aspect ? "16:9" : "4:3"); + break; + } + addr_start += 4; + } +} diff --git a/source/patches/gamepatches.h b/source/patches/gamepatches.h new file mode 100644 index 0000000..db09f2d --- /dev/null +++ b/source/patches/gamepatches.h @@ -0,0 +1,32 @@ +#ifndef GAMEPATCHES_H_ +#define GAMEPATCHES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void RegisterDOL(u8 *dst, int len); +void ClearDOLList(); +void gamepatches(u8 videoSelected, u8 videoPatchDol, u8 aspectForce, u8 languageChoice, u8 patchcountrystring, + u8 vipatch, u8 sneekVideoPatch, u8 hooktype, u64 returnTo, u8 privateServer); +bool Anti_002_fix(u8 * Address, int Size); +void PrivateServerPatcher(void *addr, u32 len, u8 privateServer); +void PatchFix480p(); +u32 do_new_wiimmfi(); +void domainpatcher(void *addr, u32 len, const char* domain); +bool NSMBPatch(); +bool PoPPatch(); +void VideoModePatcher(u8 * dst, int len, u8 videoSelected, u8 VideoPatchDol); +void sneek_video_patch(void *addr, u32 len); +bool PatchReturnTo(void *Address, int Size, u32 id); +int PatchNewReturnTo(int es_fd, u64 title); +int BlockIOSReload(int es_fd, u8 gameIOS); +void PatchAspectRatio(void *addr, u32 len, u8 aspect); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/patches/geckomenu.h b/source/patches/geckomenu.h new file mode 100644 index 0000000..d86fd2c --- /dev/null +++ b/source/patches/geckomenu.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008 Nuke (wiinuke@gmail.com) + * + * this file is part of GeckoOS for USB Gecko + * http://www.usbgecko.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __GECKOMENU_H__ +#define __GECKOMENU_H__ + +#define ROOTMENU 0 +#define ABOUTMENU 1 +#define CONFIGMENU 2 +#define REBOOTMENU 3 +#define root_itemcount 7 +#define about_itemcount 4 +#define config_itemcount 9 +#define rebooter_itemcount 6 + +u32 currentmenu; // 0 ROOT +u32 rootmenu_item; +u32 menufreeze; +u32 langselect; +u32 langsaved; +u32 pal60select; +u32 pal50select; +u32 viselect; +u32 ntscselect; +u32 hookselect; +u32 ocarinaselect; +u32 recoveryselect; +u32 regionfreeselect; +u32 nocopyselect; +u32 buttonskipselect; + +u32 doprogress(u32 progstate, u32 noelements); +void drawmenu(u32 menuid); +void drawselected(u32 menuidpos); +void processwpad(); +void clearscreen(u32 *framebuffer, u16 xscreen, u16 yscreen, u16 width, u16 height, u32 color); +void drawicon(u32 *framebuffer, u16 xscreen, u16 yscreen, u16 width, u16 height, u32 gicon); +u32 CvtRGB(u8 r1, u8 g1, u8 b1, u8 r2, u8 g2, u8 b2); + +#endif // __GECKOLOAD_H__ diff --git a/source/patches/kenobiwii.h b/source/patches/kenobiwii.h new file mode 100644 index 0000000..42bb766 --- /dev/null +++ b/source/patches/kenobiwii.h @@ -0,0 +1,235 @@ +/* + This file was autogenerated by raw2c. + Visit http://www.devkitpro.org + */ + +const unsigned char kenobiwii[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x26, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x21, 0xff, 0x58, 0x90, 0x01, 0x00, 0x08, + 0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0xac, 0x7c, 0x00, 0x00, 0x26, 0x90, 0x01, 0x00, 0x0c, 0x7c, 0x09, + 0x02, 0xa6, 0x90, 0x01, 0x00, 0x10, 0x7c, 0x01, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x14, 0xbc, 0x61, 0x00, 0x18, + 0x7f, 0x20, 0x00, 0xa6, 0x63, 0x3a, 0x20, 0x00, 0x73, 0x5a, 0xf9, 0xff, 0x7f, 0x40, 0x01, 0x24, 0xd8, 0x41, + 0x00, 0x98, 0xd8, 0x61, 0x00, 0xa0, 0x3f, 0xe0, 0x80, 0x00, 0x3e, 0x80, 0xcc, 0x00, 0xa3, 0x94, 0x40, 0x10, + 0x63, 0x95, 0x00, 0xff, 0xb2, 0xb4, 0x40, 0x10, 0x48, 0x00, 0x06, 0xb1, 0x3a, 0xa0, 0x00, 0x00, 0x3a, 0xc0, + 0x00, 0x19, 0x3a, 0xe0, 0x00, 0xd0, 0x3f, 0x00, 0xcd, 0x00, 0x63, 0xf2, 0x26, 0xa0, 0x80, 0x01, 0x00, 0xac, + 0x90, 0x12, 0x00, 0x04, 0x92, 0xb8, 0x64, 0x3c, 0x48, 0x00, 0x04, 0x85, 0x41, 0x82, 0x05, 0xfc, 0x2c, 0x1d, + 0x00, 0x04, 0x40, 0x80, 0x00, 0x10, 0x2c, 0x1d, 0x00, 0x01, 0x41, 0x80, 0x05, 0xec, 0x48, 0x00, 0x03, 0xa8, + 0x41, 0x82, 0x05, 0x48, 0x2c, 0x1d, 0x00, 0x06, 0x41, 0x82, 0x00, 0x8c, 0x2c, 0x1d, 0x00, 0x07, 0x41, 0x82, + 0x03, 0x8c, 0x2c, 0x1d, 0x00, 0x08, 0x41, 0x82, 0x05, 0xd8, 0x2c, 0x1d, 0x00, 0x09, 0x41, 0x82, 0x00, 0xa0, + 0x2c, 0x1d, 0x00, 0x10, 0x41, 0x82, 0x00, 0x98, 0x2c, 0x1d, 0x00, 0x2f, 0x41, 0x82, 0x00, 0x70, 0x2c, 0x1d, + 0x00, 0x30, 0x41, 0x82, 0x00, 0x78, 0x2c, 0x1d, 0x00, 0x38, 0x41, 0x82, 0x05, 0x80, 0x2c, 0x1d, 0x00, 0x40, + 0x41, 0x82, 0x03, 0x9c, 0x2c, 0x1d, 0x00, 0x41, 0x41, 0x82, 0x03, 0xb0, 0x2c, 0x1d, 0x00, 0x44, 0x41, 0x82, + 0x00, 0x68, 0x2c, 0x1d, 0x00, 0x50, 0x41, 0x82, 0x00, 0x20, 0x2c, 0x1d, 0x00, 0x60, 0x41, 0x82, 0x00, 0x24, + 0x2c, 0x1d, 0x00, 0x89, 0x41, 0x82, 0x00, 0x50, 0x2c, 0x1d, 0x00, 0x99, 0x41, 0x82, 0x05, 0x64, 0x48, 0x00, + 0x05, 0x68, 0x80, 0x72, 0x00, 0x00, 0x48, 0x00, 0x04, 0x81, 0x48, 0x00, 0x05, 0x5c, 0x48, 0x00, 0x05, 0xe5, + 0x48, 0x00, 0x05, 0x54, 0x38, 0x80, 0x00, 0x01, 0x90, 0x92, 0x00, 0x00, 0x48, 0x00, 0x05, 0x48, 0x48, 0x00, + 0x04, 0x61, 0x3a, 0x00, 0x00, 0xa0, 0x63, 0xec, 0x26, 0xc4, 0x48, 0x00, 0x03, 0x6c, 0x38, 0x60, 0x01, 0x20, + 0x63, 0xec, 0x26, 0xc4, 0x48, 0x00, 0x04, 0x21, 0x48, 0x00, 0x05, 0x28, 0x2f, 0x1d, 0x00, 0x10, 0x2e, 0x9d, + 0x00, 0x44, 0x63, 0xe4, 0x1a, 0xb4, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x03, 0x00, 0x48, 0x00, 0x05, 0x65, + 0x38, 0x63, 0x0a, 0x00, 0x48, 0x00, 0x05, 0x5d, 0x38, 0x63, 0x06, 0x00, 0x48, 0x00, 0x05, 0x55, 0x63, 0xec, + 0x26, 0xb4, 0x92, 0xac, 0x00, 0x00, 0x92, 0xac, 0x00, 0x04, 0x92, 0xac, 0x00, 0x08, 0x63, 0xe4, 0x26, 0xc4, + 0x81, 0x24, 0x00, 0x18, 0x80, 0x72, 0x00, 0x00, 0x2c, 0x03, 0x00, 0x02, 0x40, 0x82, 0x00, 0x0c, 0x41, 0x96, + 0x00, 0x0c, 0x48, 0x00, 0x00, 0x20, 0x38, 0x60, 0x00, 0x00, 0x90, 0x6c, 0x00, 0x0c, 0x40, 0x82, 0x00, 0x14, + 0x40, 0x96, 0x00, 0x10, 0x61, 0x29, 0x04, 0x00, 0x91, 0x24, 0x00, 0x18, 0x48, 0x00, 0x02, 0x70, 0x55, 0x29, + 0x05, 0xa8, 0x91, 0x24, 0x00, 0x18, 0x41, 0x96, 0x04, 0xac, 0x41, 0x9a, 0x00, 0x08, 0x39, 0x8c, 0x00, 0x04, + 0x38, 0x60, 0x00, 0x04, 0x48, 0x00, 0x03, 0x61, 0x40, 0x99, 0x00, 0x10, 0x39, 0x8c, 0x00, 0x04, 0x38, 0x60, + 0x00, 0x04, 0x48, 0x00, 0x03, 0x51, 0x63, 0xe4, 0x26, 0xb4, 0x80, 0x64, 0x00, 0x00, 0x80, 0x84, 0x00, 0x04, + 0x7c, 0x72, 0xfb, 0xa6, 0x7c, 0x95, 0xfb, 0xa6, 0x48, 0x00, 0x04, 0x74, 0x7c, 0x32, 0x43, 0xa6, 0x7c, 0x3a, + 0x02, 0xa6, 0x7c, 0x73, 0x43, 0xa6, 0x7c, 0x7b, 0x02, 0xa6, 0x54, 0x63, 0x05, 0xa8, 0x90, 0x60, 0x26, 0xdc, + 0x54, 0x63, 0x06, 0x20, 0x60, 0x63, 0x20, 0x00, 0x54, 0x63, 0x04, 0x5e, 0x7c, 0x7b, 0x03, 0xa6, 0x3c, 0x60, + 0x80, 0x00, 0x60, 0x63, 0x1a, 0xf4, 0x7c, 0x7a, 0x03, 0xa6, 0x4c, 0x00, 0x01, 0x2c, 0x7c, 0x00, 0x04, 0xac, + 0x4c, 0x00, 0x00, 0x64, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x26, 0xc4, 0x90, 0x23, 0x00, 0x14, 0x7c, 0x61, + 0x1b, 0x78, 0x7c, 0x73, 0x42, 0xa6, 0xbc, 0x41, 0x00, 0x24, 0x7c, 0x24, 0x0b, 0x78, 0x7c, 0x32, 0x42, 0xa6, + 0x90, 0x04, 0x00, 0x1c, 0x90, 0x24, 0x00, 0x20, 0x7c, 0x68, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x9c, 0x7c, 0x60, + 0x00, 0x26, 0x90, 0x64, 0x00, 0x00, 0x7c, 0x61, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x04, 0x7c, 0x69, 0x02, 0xa6, + 0x90, 0x64, 0x00, 0x08, 0x7c, 0x72, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x0c, 0x7c, 0x73, 0x02, 0xa6, 0x90, 0x64, + 0x00, 0x10, 0x39, 0x20, 0x00, 0x00, 0x7d, 0x32, 0xfb, 0xa6, 0x7d, 0x35, 0xfb, 0xa6, 0xd0, 0x04, 0x00, 0xa0, + 0xd0, 0x24, 0x00, 0xa4, 0xd0, 0x44, 0x00, 0xa8, 0xd0, 0x64, 0x00, 0xac, 0xd0, 0x84, 0x00, 0xb0, 0xd0, 0xa4, + 0x00, 0xb4, 0xd0, 0xc4, 0x00, 0xb8, 0xd0, 0xe4, 0x00, 0xbc, 0xd1, 0x04, 0x00, 0xc0, 0xd1, 0x24, 0x00, 0xc4, + 0xd1, 0x44, 0x00, 0xc8, 0xd1, 0x64, 0x00, 0xcc, 0xd1, 0x84, 0x00, 0xd0, 0xd1, 0xa4, 0x00, 0xd4, 0xd1, 0xc4, + 0x00, 0xd8, 0xd1, 0xe4, 0x00, 0xdc, 0xd2, 0x04, 0x00, 0xe0, 0xd2, 0x24, 0x00, 0xe4, 0xd2, 0x44, 0x00, 0xe8, + 0xd2, 0x64, 0x00, 0xec, 0xd2, 0x84, 0x00, 0xf0, 0xd2, 0xa4, 0x00, 0xf4, 0xd2, 0xc4, 0x00, 0xf8, 0xd2, 0xe4, + 0x00, 0xfc, 0xd3, 0x04, 0x01, 0x00, 0xd3, 0x24, 0x01, 0x04, 0xd3, 0x44, 0x01, 0x08, 0xd3, 0x64, 0x01, 0x0c, + 0xd3, 0x84, 0x01, 0x10, 0xd3, 0xa4, 0x01, 0x14, 0xd3, 0xc4, 0x01, 0x18, 0xd3, 0xe4, 0x01, 0x1c, 0x3f, 0xe0, + 0x80, 0x00, 0x63, 0xe5, 0x26, 0xb4, 0x82, 0x05, 0x00, 0x00, 0x82, 0x25, 0x00, 0x04, 0x82, 0x65, 0x00, 0x0c, + 0x2c, 0x13, 0x00, 0x00, 0x41, 0x82, 0x00, 0x74, 0x2c, 0x13, 0x00, 0x02, 0x40, 0x82, 0x00, 0x18, 0x81, 0x24, + 0x00, 0x14, 0x39, 0x33, 0x00, 0x03, 0x91, 0x25, 0x00, 0x00, 0x91, 0x25, 0x00, 0x0c, 0x48, 0x00, 0x00, 0x6c, + 0x7c, 0x10, 0x98, 0x00, 0x41, 0x82, 0x00, 0x38, 0x7c, 0x11, 0x98, 0x00, 0x41, 0x82, 0x00, 0x30, 0x7d, 0x30, + 0x8a, 0x14, 0x91, 0x25, 0x00, 0x0c, 0x82, 0x05, 0x00, 0x08, 0x2c, 0x10, 0x00, 0x00, 0x41, 0x82, 0x00, 0x48, + 0x80, 0x64, 0x00, 0x10, 0x7c, 0x10, 0x18, 0x00, 0x40, 0x82, 0x00, 0x10, 0x3a, 0x00, 0x00, 0x00, 0x92, 0x05, + 0x00, 0x08, 0x48, 0x00, 0x00, 0x30, 0x3a, 0x20, 0x00, 0x00, 0x92, 0x25, 0x00, 0x0c, 0x81, 0x24, 0x00, 0x18, + 0x61, 0x29, 0x04, 0x00, 0x91, 0x24, 0x00, 0x18, 0x48, 0x00, 0x00, 0x30, 0x7e, 0x12, 0xfb, 0xa6, 0x7e, 0x35, + 0xfb, 0xa6, 0x39, 0x20, 0x00, 0x01, 0x91, 0x25, 0x00, 0x0c, 0x48, 0x00, 0x00, 0x1c, 0x38, 0xa0, 0x00, 0x02, + 0x63, 0xe4, 0x26, 0xa0, 0x90, 0xa4, 0x00, 0x00, 0x38, 0x60, 0x00, 0x11, 0x48, 0x00, 0x01, 0xbd, 0x4b, 0xff, + 0xfc, 0x1d, 0x7c, 0x20, 0x00, 0xa6, 0x54, 0x21, 0x07, 0xfa, 0x54, 0x21, 0x04, 0x5e, 0x7c, 0x20, 0x01, 0x24, + 0x63, 0xe1, 0x26, 0xc4, 0x80, 0x61, 0x00, 0x00, 0x7c, 0x6f, 0xf1, 0x20, 0x80, 0x61, 0x00, 0x14, 0x7c, 0x7a, + 0x03, 0xa6, 0x80, 0x61, 0x00, 0x18, 0x7c, 0x7b, 0x03, 0xa6, 0x80, 0x61, 0x00, 0x9c, 0x7c, 0x68, 0x03, 0xa6, + 0xb8, 0x41, 0x00, 0x24, 0x80, 0x01, 0x00, 0x1c, 0x80, 0x21, 0x00, 0x20, 0x4c, 0x00, 0x01, 0x2c, 0x7c, 0x00, + 0x04, 0xac, 0x4c, 0x00, 0x00, 0x64, 0x92, 0xb2, 0x00, 0x00, 0x48, 0x00, 0x02, 0x50, 0x2e, 0x9d, 0x00, 0x02, + 0x38, 0x60, 0x00, 0x08, 0x63, 0xec, 0x26, 0xa8, 0x48, 0x00, 0x00, 0xf9, 0x80, 0xac, 0x00, 0x00, 0x80, 0x6c, + 0x00, 0x04, 0x98, 0x65, 0x00, 0x00, 0x41, 0x94, 0x00, 0x10, 0xb0, 0x65, 0x00, 0x00, 0x41, 0x96, 0x00, 0x08, + 0x90, 0x65, 0x00, 0x00, 0x7c, 0x00, 0x28, 0xac, 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x2f, 0xac, 0x4c, 0x00, + 0x01, 0x2c, 0x48, 0x00, 0x02, 0x04, 0x48, 0x00, 0x01, 0x1d, 0x38, 0x60, 0x00, 0x04, 0x63, 0xec, 0x26, 0xa8, + 0x48, 0x00, 0x00, 0xb9, 0x82, 0x0c, 0x00, 0x00, 0x63, 0xec, 0x27, 0xe8, 0x48, 0x00, 0x00, 0x1c, 0x48, 0x00, + 0x01, 0x01, 0x38, 0x60, 0x00, 0x08, 0x63, 0xec, 0x26, 0xa8, 0x48, 0x00, 0x00, 0x9d, 0x82, 0x0c, 0x00, 0x04, + 0x81, 0x8c, 0x00, 0x00, 0x63, 0xfb, 0x26, 0xb0, 0x3a, 0x20, 0x0f, 0x80, 0x48, 0x00, 0x02, 0x3d, 0x41, 0x82, + 0x00, 0x20, 0x7e, 0x23, 0x8b, 0x78, 0x48, 0x00, 0x00, 0x7d, 0x48, 0x00, 0x00, 0xd1, 0x41, 0x82, 0xff, 0xfc, + 0x7d, 0x8c, 0x72, 0x14, 0x35, 0x6b, 0xff, 0xff, 0x41, 0x81, 0xff, 0xe8, 0x80, 0x7b, 0x00, 0x00, 0x2c, 0x03, + 0x00, 0x00, 0x41, 0x82, 0x00, 0x08, 0x48, 0x00, 0x00, 0x59, 0x7c, 0x00, 0x60, 0xac, 0x7c, 0x00, 0x04, 0xac, + 0x7c, 0x00, 0x67, 0xac, 0x4c, 0x00, 0x01, 0x2c, 0x48, 0x00, 0x01, 0x80, 0x7f, 0xc8, 0x02, 0xa6, 0x3c, 0x60, + 0xa0, 0x00, 0x48, 0x00, 0x00, 0x15, 0x76, 0x03, 0x08, 0x00, 0x56, 0x1d, 0x86, 0x3e, 0x7f, 0xc8, 0x03, 0xa6, + 0x4e, 0x80, 0x00, 0x20, 0x92, 0xf8, 0x68, 0x14, 0x90, 0x78, 0x68, 0x24, 0x92, 0xd8, 0x68, 0x20, 0x80, 0xb8, + 0x68, 0x20, 0x70, 0xa5, 0x00, 0x01, 0x40, 0x82, 0xff, 0xf8, 0x82, 0x18, 0x68, 0x24, 0x90, 0xb8, 0x68, 0x14, + 0x4e, 0x80, 0x00, 0x20, 0x7d, 0x48, 0x02, 0xa6, 0x7c, 0x69, 0x03, 0xa6, 0x39, 0xc0, 0x00, 0x00, 0x48, 0x00, + 0x00, 0x79, 0x48, 0x00, 0x00, 0x75, 0x4b, 0xff, 0xff, 0xad, 0x41, 0x82, 0xff, 0xf4, 0x7f, 0xae, 0x61, 0xae, + 0x39, 0xce, 0x00, 0x01, 0x42, 0x00, 0xff, 0xe8, 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x7d, 0x48, + 0x02, 0xa6, 0x7c, 0x69, 0x03, 0xa6, 0x39, 0xc0, 0x00, 0x00, 0x7c, 0x6c, 0x70, 0xae, 0x48, 0x00, 0x00, 0x1d, + 0x41, 0x82, 0xff, 0xf8, 0x39, 0xce, 0x00, 0x01, 0x42, 0x00, 0xff, 0xf0, 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, + 0x00, 0x20, 0x38, 0x60, 0x00, 0xaa, 0x7f, 0xc8, 0x02, 0xa6, 0x54, 0x63, 0xa0, 0x16, 0x64, 0x63, 0xb0, 0x00, + 0x3a, 0xc0, 0x00, 0x19, 0x3a, 0xe0, 0x00, 0xd0, 0x3f, 0x00, 0xcd, 0x00, 0x4b, 0xff, 0xff, 0x69, 0x56, 0x03, + 0x37, 0xff, 0x7f, 0xc8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x7f, 0xc8, 0x02, 0xa6, 0x3c, 0x60, 0xd0, 0x00, + 0x4b, 0xff, 0xff, 0x51, 0x56, 0x03, 0x37, 0xff, 0x41, 0x82, 0xff, 0xf4, 0x7f, 0xc8, 0x03, 0xa6, 0x4e, 0x80, + 0x00, 0x20, 0x4b, 0xff, 0xff, 0xb9, 0x38, 0x60, 0x00, 0x08, 0x63, 0xec, 0x26, 0xa8, 0x4b, 0xff, 0xff, 0x55, + 0x80, 0xac, 0x00, 0x04, 0x81, 0x8c, 0x00, 0x00, 0x63, 0xfb, 0x26, 0xb0, 0x62, 0xb1, 0xf8, 0x00, 0x7e, 0x0c, + 0x28, 0x50, 0x48, 0x00, 0x00, 0xf1, 0x41, 0x81, 0x00, 0x10, 0x82, 0x3b, 0x00, 0x00, 0x2c, 0x11, 0x00, 0x00, + 0x41, 0x82, 0x00, 0x68, 0x7e, 0x23, 0x8b, 0x78, 0x4b, 0xff, 0xff, 0x55, 0x4b, 0xff, 0xff, 0xa5, 0x4b, 0xff, + 0xff, 0xa1, 0x4b, 0xff, 0xfe, 0xd9, 0x41, 0x82, 0xff, 0xf4, 0x2c, 0x1d, 0x00, 0xcc, 0x41, 0x82, 0x00, 0x48, + 0x2c, 0x1d, 0x00, 0xbb, 0x41, 0x82, 0xff, 0xdc, 0x2c, 0x1d, 0x00, 0xaa, 0x40, 0x82, 0xff, 0xdc, 0x7d, 0x8c, + 0x72, 0x14, 0x35, 0x6b, 0xff, 0xff, 0x41, 0x80, 0x00, 0x2c, 0x4b, 0xff, 0xff, 0xb4, 0x7e, 0xb5, 0xfb, 0xa6, + 0x7e, 0xb2, 0xfb, 0xa6, 0x63, 0xe4, 0x26, 0xc4, 0x81, 0x24, 0x00, 0x18, 0x55, 0x29, 0x05, 0xa8, 0x91, 0x24, + 0x00, 0x18, 0x48, 0x00, 0x00, 0x0c, 0x38, 0x60, 0x00, 0x80, 0x4b, 0xff, 0xff, 0x25, 0x80, 0x92, 0x00, 0x00, + 0x2c, 0x04, 0x00, 0x00, 0x40, 0x82, 0xf9, 0xf8, 0xb3, 0x94, 0x40, 0x10, 0xc8, 0x41, 0x00, 0x98, 0xc8, 0x61, + 0x00, 0xa0, 0x7f, 0x20, 0x00, 0xa6, 0x80, 0x01, 0x00, 0xac, 0x7c, 0x08, 0x03, 0xa6, 0x80, 0x01, 0x00, 0x0c, + 0x7c, 0x0f, 0xf1, 0x20, 0x80, 0x01, 0x00, 0x10, 0x7c, 0x09, 0x03, 0xa6, 0x80, 0x01, 0x00, 0x14, 0x7c, 0x01, + 0x03, 0xa6, 0xb8, 0x61, 0x00, 0x18, 0x80, 0x01, 0x00, 0x08, 0x38, 0x21, 0x00, 0xa8, 0x4c, 0x00, 0x01, 0x2c, + 0x7c, 0x00, 0x04, 0xac, 0x4e, 0x80, 0x00, 0x20, 0x7e, 0x23, 0x20, 0x50, 0x3c, 0xa0, 0x48, 0x00, 0x52, 0x25, + 0x01, 0xba, 0x90, 0xa3, 0x00, 0x00, 0x7c, 0x00, 0x18, 0xac, 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x1f, 0xac, + 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20, 0x7d, 0x70, 0x8b, 0xd7, 0x7d, 0x4b, 0x89, 0xd6, 0x7d, 0x4a, + 0x80, 0x50, 0x91, 0x5b, 0x00, 0x00, 0x4e, 0x80, 0x00, 0x20, 0x7f, 0xa8, 0x02, 0xa6, 0x63, 0xef, 0x27, 0xe8, + 0x63, 0xe7, 0x18, 0x08, 0x3c, 0xc0, 0x80, 0x00, 0x7c, 0xd0, 0x33, 0x78, 0x39, 0x00, 0x00, 0x00, 0x3c, 0x60, + 0x00, 0xd0, 0x60, 0x63, 0xc0, 0xde, 0x80, 0x8f, 0x00, 0x00, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x18, + 0x80, 0x8f, 0x00, 0x04, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x0c, 0x39, 0xef, 0x00, 0x08, 0x48, 0x00, + 0x00, 0x0c, 0x7f, 0xa8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x80, 0x6f, 0x00, 0x00, 0x80, 0x8f, 0x00, 0x04, + 0x39, 0xef, 0x00, 0x08, 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00, 0x39, 0x20, 0x00, 0x00, 0x54, 0x6a, + 0x1f, 0x7e, 0x54, 0x65, 0x3f, 0x7e, 0x74, 0x6b, 0x10, 0x00, 0x54, 0x63, 0x01, 0xfe, 0x40, 0x82, 0x00, 0x0c, + 0x54, 0xcc, 0x00, 0x0c, 0x48, 0x00, 0x00, 0x08, 0x7e, 0x0c, 0x83, 0x78, 0x2e, 0x05, 0x00, 0x00, 0x2c, 0x0a, + 0x00, 0x01, 0x41, 0xa0, 0x00, 0x2c, 0x41, 0xa2, 0x00, 0xe4, 0x2c, 0x0a, 0x00, 0x03, 0x41, 0xa0, 0x01, 0xb0, + 0x41, 0x82, 0x02, 0x54, 0x2c, 0x0a, 0x00, 0x05, 0x41, 0x80, 0x02, 0xdc, 0x41, 0xa2, 0x04, 0xe8, 0x2c, 0x0a, + 0x00, 0x07, 0x41, 0xa0, 0x05, 0x14, 0x48, 0x00, 0x05, 0xf8, 0x7d, 0x8c, 0x1a, 0x14, 0x2c, 0x05, 0x00, 0x03, + 0x41, 0x82, 0x00, 0x48, 0x41, 0x81, 0x00, 0x60, 0x40, 0xbe, 0xff, 0x84, 0x2e, 0x05, 0x00, 0x01, 0x41, 0x91, + 0x00, 0x2c, 0x54, 0x8a, 0x84, 0x3e, 0x41, 0x92, 0x00, 0x10, 0x7c, 0x89, 0x61, 0xae, 0x39, 0x29, 0x00, 0x01, + 0x48, 0x00, 0x00, 0x0c, 0x7c, 0x89, 0x63, 0x2e, 0x39, 0x29, 0x00, 0x02, 0x35, 0x4a, 0xff, 0xff, 0x40, 0xa0, + 0xff, 0xe4, 0x4b, 0xff, 0xff, 0x54, 0x55, 0x8c, 0x00, 0x3a, 0x90, 0x8c, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x48, + 0x7c, 0x89, 0x23, 0x78, 0x40, 0x9e, 0x04, 0xd0, 0x35, 0x29, 0xff, 0xff, 0x41, 0x80, 0x04, 0xc8, 0x7c, 0xa9, + 0x78, 0xae, 0x7c, 0xa9, 0x61, 0xae, 0x4b, 0xff, 0xff, 0xf0, 0x39, 0xef, 0x00, 0x08, 0x40, 0xbe, 0xff, 0x24, + 0x80, 0xaf, 0xff, 0xf8, 0x81, 0x6f, 0xff, 0xfc, 0x54, 0xb1, 0x04, 0x3e, 0x54, 0xaa, 0x85, 0x3e, 0x54, 0xa5, + 0x27, 0x3e, 0x2e, 0x85, 0x00, 0x01, 0x41, 0x96, 0x00, 0x10, 0x41, 0xb5, 0x00, 0x14, 0x7c, 0x89, 0x61, 0xae, + 0x48, 0x00, 0x00, 0x10, 0x7c, 0x89, 0x63, 0x2e, 0x48, 0x00, 0x00, 0x08, 0x7c, 0x89, 0x61, 0x2e, 0x7c, 0x84, + 0x5a, 0x14, 0x7d, 0x29, 0x8a, 0x14, 0x35, 0x4a, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4, 0x4b, 0xff, 0xfe, 0xdc, + 0x54, 0x69, 0x07, 0xff, 0x41, 0x82, 0x00, 0x10, 0x55, 0x08, 0xf8, 0x7e, 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, + 0x00, 0x00, 0x2e, 0x85, 0x00, 0x04, 0x2d, 0x8a, 0x00, 0x05, 0x7d, 0x13, 0x43, 0x78, 0x52, 0x68, 0x08, 0x3c, + 0x40, 0x9e, 0x00, 0x78, 0x41, 0x8d, 0x04, 0xbc, 0x7d, 0x8c, 0x1a, 0x14, 0x41, 0x8c, 0x00, 0x0c, 0x41, 0x94, + 0x00, 0x30, 0x48, 0x00, 0x00, 0x1c, 0x40, 0x94, 0x00, 0x10, 0x55, 0x8c, 0x00, 0x3a, 0x81, 0x6c, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x1c, 0x55, 0x8c, 0x00, 0x3c, 0xa1, 0x6c, 0x00, 0x00, 0x7c, 0x89, 0x20, 0xf8, 0x55, 0x29, + 0x84, 0x3e, 0x7d, 0x6b, 0x48, 0x38, 0x54, 0x84, 0x04, 0x3e, 0x7f, 0x0b, 0x20, 0x40, 0x70, 0xa9, 0x00, 0x03, + 0x41, 0x82, 0x00, 0x18, 0x2c, 0x09, 0x00, 0x02, 0x41, 0x82, 0x00, 0x18, 0x41, 0x81, 0x00, 0x1c, 0x40, 0x9a, + 0x00, 0x20, 0x48, 0x00, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x18, 0x48, 0x00, 0x00, 0x10, 0x41, 0x99, 0x00, 0x10, + 0x48, 0x00, 0x00, 0x08, 0x41, 0x98, 0x00, 0x08, 0x61, 0x08, 0x00, 0x01, 0x40, 0x8e, 0xfe, 0x3c, 0x41, 0x94, + 0xfe, 0x38, 0x81, 0x6f, 0xff, 0xf8, 0x40, 0x9e, 0x00, 0x20, 0x70, 0x6c, 0x00, 0x08, 0x41, 0x82, 0x00, 0x0c, + 0x71, 0x0c, 0x00, 0x01, 0x41, 0x82, 0x00, 0x10, 0x39, 0x8b, 0x00, 0x10, 0x51, 0x8b, 0x03, 0x36, 0x48, 0x00, + 0x00, 0x08, 0x55, 0x6b, 0x07, 0x16, 0x91, 0x6f, 0xff, 0xf8, 0x4b, 0xff, 0xfe, 0x08, 0x40, 0xbe, 0xfe, 0x04, + 0x54, 0x69, 0x16, 0xba, 0x54, 0x6e, 0x87, 0xfe, 0x2d, 0x8e, 0x00, 0x00, 0x2e, 0x05, 0x00, 0x04, 0x70, 0xae, + 0x00, 0x03, 0x2e, 0x8e, 0x00, 0x02, 0x41, 0x94, 0x00, 0x14, 0x41, 0x96, 0x00, 0x50, 0x7c, 0x64, 0x07, 0x34, + 0x7c, 0x84, 0x7a, 0x14, 0x48, 0x00, 0x00, 0x68, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, 0x7d, 0x27, + 0x48, 0x2e, 0x7c, 0x84, 0x4a, 0x14, 0x41, 0x8e, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14, 0x2e, 0x8e, 0x00, 0x01, + 0x41, 0x96, 0x00, 0x08, 0x80, 0x84, 0x00, 0x00, 0x54, 0x63, 0x67, 0xff, 0x41, 0x82, 0x00, 0x3c, 0x40, 0x90, + 0x00, 0x0c, 0x7c, 0x84, 0x32, 0x14, 0x48, 0x00, 0x00, 0x30, 0x7c, 0x84, 0x82, 0x14, 0x48, 0x00, 0x00, 0x28, + 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, 0x7d, 0x27, 0x48, 0x2e, 0x7c, 0x84, 0x4a, 0x14, 0x40, 0x90, + 0x00, 0x0c, 0x7c, 0xcc, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x7c, 0x7e, 0x0c, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x74, + 0x40, 0x90, 0x00, 0x0c, 0x7c, 0x86, 0x23, 0x78, 0x4b, 0xff, 0xfd, 0x68, 0x7c, 0x90, 0x23, 0x78, 0x4b, 0xff, + 0xfd, 0x60, 0x54, 0x89, 0x1e, 0x78, 0x39, 0x29, 0x00, 0x40, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x80, 0x00, 0x4c, + 0x54, 0x6b, 0x67, 0xbf, 0x2c, 0x0b, 0x00, 0x01, 0x41, 0x80, 0x00, 0x14, 0x41, 0x82, 0x00, 0x08, 0x48, 0x00, + 0x00, 0x10, 0x41, 0xbe, 0xfd, 0x38, 0x48, 0x00, 0x00, 0x08, 0x40, 0xbe, 0xfd, 0x30, 0x2c, 0x05, 0x00, 0x03, + 0x41, 0x81, 0x00, 0x10, 0x41, 0xa2, 0x00, 0x10, 0x7d, 0xe7, 0x48, 0x2e, 0x4b, 0xff, 0xfd, 0x1c, 0x7d, 0xe7, + 0x49, 0x2e, 0x7c, 0x64, 0x07, 0x34, 0x54, 0x84, 0x1a, 0x78, 0x7d, 0xef, 0x22, 0x14, 0x4b, 0xff, 0xfd, 0x08, + 0x40, 0xbe, 0xfd, 0x04, 0x7c, 0xa7, 0x4a, 0x14, 0x40, 0x92, 0x00, 0x14, 0x54, 0x64, 0x04, 0x3e, 0x91, 0xe5, + 0x00, 0x00, 0x90, 0x85, 0x00, 0x04, 0x4b, 0xff, 0xfc, 0xec, 0x81, 0x25, 0x00, 0x04, 0x2c, 0x09, 0x00, 0x00, + 0x41, 0xa2, 0xfc, 0xe0, 0x39, 0x29, 0xff, 0xff, 0x91, 0x25, 0x00, 0x04, 0x81, 0xe5, 0x00, 0x00, 0x4b, 0xff, + 0xfc, 0xd0, 0x40, 0xbe, 0xfc, 0xcc, 0x54, 0x6b, 0x16, 0xba, 0x7f, 0x47, 0x5a, 0x14, 0x81, 0x3a, 0x00, 0x00, + 0x54, 0x6e, 0x67, 0xbe, 0x41, 0x92, 0x00, 0x84, 0x2e, 0x05, 0x00, 0x05, 0x40, 0x90, 0x01, 0x74, 0x2e, 0x05, + 0x00, 0x03, 0x40, 0x90, 0x00, 0x90, 0x2e, 0x05, 0x00, 0x01, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, + 0x7c, 0x8c, 0x22, 0x14, 0x2f, 0x0e, 0x00, 0x01, 0x40, 0x92, 0x00, 0x24, 0x41, 0xb9, 0x00, 0x18, 0x41, 0x9a, + 0x00, 0x0c, 0x88, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf8, 0xa0, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf0, + 0x80, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xe8, 0x54, 0x73, 0xe5, 0x3e, 0x41, 0xb9, 0x00, 0x20, 0x41, 0x9a, + 0x00, 0x10, 0x99, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x01, 0x48, 0x00, 0x00, 0x18, 0xb1, 0x24, 0x00, 0x00, + 0x38, 0x84, 0x00, 0x02, 0x48, 0x00, 0x00, 0x0c, 0x91, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x04, 0x36, 0x73, + 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4, 0x4b, 0xff, 0xfc, 0x38, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, + 0x7c, 0x84, 0x62, 0x14, 0x71, 0xc5, 0x00, 0x01, 0x41, 0x82, 0x00, 0x9c, 0x7c, 0x84, 0x4a, 0x14, 0x48, 0x00, + 0x00, 0x94, 0x54, 0x6a, 0x87, 0xbe, 0x54, 0x8e, 0x16, 0xba, 0x7e, 0x67, 0x72, 0x14, 0x40, 0x92, 0x00, 0x08, + 0x3a, 0x6f, 0xff, 0xfc, 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00, 0x71, 0x4b, 0x00, 0x01, 0x41, 0x82, + 0x00, 0x08, 0x7c, 0x9a, 0x23, 0x78, 0x71, 0x4b, 0x00, 0x02, 0x41, 0x82, 0x00, 0x10, 0x7d, 0x33, 0x4b, 0x78, + 0x40, 0xb2, 0x00, 0x08, 0x7e, 0x6c, 0x9a, 0x14, 0x54, 0x65, 0x67, 0x3f, 0x2c, 0x05, 0x00, 0x09, 0x40, 0x80, + 0x00, 0x54, 0x48, 0x00, 0x00, 0x79, 0x7c, 0x89, 0x22, 0x14, 0x48, 0x00, 0x00, 0x40, 0x7c, 0x89, 0x21, 0xd6, + 0x48, 0x00, 0x00, 0x38, 0x7d, 0x24, 0x23, 0x78, 0x48, 0x00, 0x00, 0x30, 0x7d, 0x24, 0x20, 0x38, 0x48, 0x00, + 0x00, 0x28, 0x7d, 0x24, 0x22, 0x78, 0x48, 0x00, 0x00, 0x20, 0x7d, 0x24, 0x20, 0x30, 0x48, 0x00, 0x00, 0x18, + 0x7d, 0x24, 0x24, 0x30, 0x48, 0x00, 0x00, 0x10, 0x5d, 0x24, 0x20, 0x3e, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x24, + 0x26, 0x30, 0x90, 0x9a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x84, 0x2c, 0x05, 0x00, 0x0a, 0x41, 0x81, 0xfb, 0x7c, + 0xc0, 0x5a, 0x00, 0x00, 0xc0, 0x73, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0c, 0xec, 0x43, 0x10, 0x2a, 0x48, 0x00, + 0x00, 0x08, 0xec, 0x43, 0x00, 0xb2, 0xd0, 0x5a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x5c, 0x7d, 0x48, 0x02, 0xa6, + 0x54, 0xa5, 0x1e, 0x78, 0x7d, 0x4a, 0x2a, 0x14, 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00, 0x7d, 0x48, + 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x40, 0xbe, 0xfb, 0x3c, 0x54, 0x69, 0xc0, 0x3e, 0x7d, 0x8e, 0x63, 0x78, + 0x48, 0x00, 0x00, 0x35, 0x41, 0x92, 0x00, 0x0c, 0x7e, 0x31, 0x22, 0x14, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x29, + 0x22, 0x14, 0x54, 0x64, 0xc4, 0x3f, 0x38, 0xa0, 0x00, 0x00, 0x41, 0x82, 0xfb, 0x14, 0x7d, 0x45, 0x88, 0xae, + 0x7d, 0x45, 0x49, 0xae, 0x38, 0xa5, 0x00, 0x01, 0x7c, 0x05, 0x20, 0x00, 0x4b, 0xff, 0xff, 0xec, 0x2e, 0x8a, + 0x00, 0x04, 0x55, 0x31, 0x36, 0xba, 0x2c, 0x11, 0x00, 0x3c, 0x7e, 0x27, 0x88, 0x2e, 0x40, 0x82, 0x00, 0x08, + 0x7d, 0xd1, 0x73, 0x78, 0x41, 0x96, 0x00, 0x08, 0xa2, 0x31, 0x00, 0x00, 0x55, 0x29, 0x56, 0xba, 0x2c, 0x09, + 0x00, 0x3c, 0x7d, 0x27, 0x48, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xc9, 0x73, 0x78, 0x41, 0x96, 0x00, 0x08, + 0xa1, 0x29, 0x00, 0x00, 0x4e, 0x80, 0x00, 0x20, 0x2c, 0x05, 0x00, 0x04, 0x40, 0x80, 0x00, 0x28, 0x7c, 0x89, + 0x23, 0x78, 0x7d, 0xc3, 0x62, 0x14, 0x55, 0xce, 0x00, 0x3c, 0x4b, 0xff, 0xff, 0xad, 0x7c, 0x84, 0x20, 0xf8, + 0x54, 0x84, 0x04, 0x3e, 0x7d, 0x2b, 0x20, 0x38, 0x7e, 0x24, 0x20, 0x38, 0x4b, 0xff, 0xfb, 0xbc, 0x54, 0x6b, + 0xe4, 0x3e, 0x4b, 0xff, 0xfb, 0xb4, 0x7c, 0x9a, 0x23, 0x78, 0x54, 0x84, 0x18, 0x38, 0x40, 0x92, 0x00, 0x20, + 0x40, 0x9e, 0x00, 0x0c, 0x7d, 0xe8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x21, 0x7d, 0xe4, 0x7a, 0x14, 0x39, 0xef, + 0x00, 0x07, 0x55, 0xef, 0x00, 0x38, 0x4b, 0xff, 0xfa, 0x64, 0x2e, 0x05, 0x00, 0x03, 0x41, 0x91, 0x00, 0x5c, + 0x3c, 0xa0, 0x48, 0x00, 0x7d, 0x83, 0x62, 0x14, 0x55, 0x8c, 0x00, 0x3a, 0x40, 0x92, 0x00, 0x20, 0x40, 0xbe, + 0xfa, 0x48, 0x57, 0x44, 0x00, 0x3a, 0x7c, 0x8c, 0x20, 0x50, 0x50, 0x85, 0x01, 0xba, 0x50, 0x65, 0x07, 0xfe, + 0x90, 0xac, 0x00, 0x00, 0x4b, 0xff, 0xfa, 0x30, 0x40, 0xbe, 0xff, 0xbc, 0x7d, 0x2c, 0x78, 0x50, 0x51, 0x25, + 0x01, 0xba, 0x90, 0xac, 0x00, 0x00, 0x39, 0x8c, 0x00, 0x04, 0x7d, 0x6f, 0x22, 0x14, 0x39, 0x6b, 0xff, 0xfc, + 0x7d, 0x2b, 0x60, 0x50, 0x51, 0x25, 0x01, 0xba, 0x90, 0xab, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x94, 0x2e, 0x05, + 0x00, 0x06, 0x41, 0x92, 0x00, 0x28, 0x4b, 0xff, 0xfb, 0x20, 0x55, 0x8c, 0x84, 0x3e, 0x57, 0x44, 0x84, 0x3e, + 0x57, 0x5a, 0x04, 0x3e, 0x7c, 0x0c, 0x20, 0x00, 0x41, 0x80, 0xfb, 0xa4, 0x7c, 0x0c, 0xd0, 0x00, 0x40, 0x80, + 0xfb, 0x9c, 0x4b, 0xff, 0xf9, 0xd8, 0x57, 0x45, 0xff, 0xfe, 0x68, 0xa5, 0x00, 0x01, 0x71, 0x03, 0x00, 0x01, + 0x7c, 0x05, 0x18, 0x00, 0x41, 0x82, 0x00, 0x1c, 0x51, 0x1a, 0x0f, 0xbc, 0x6b, 0x5a, 0x00, 0x02, 0x57, 0x45, + 0xff, 0xff, 0x41, 0x82, 0x00, 0x08, 0x6b, 0x5a, 0x00, 0x01, 0x93, 0x4f, 0xff, 0xfc, 0x53, 0x48, 0x07, 0xfe, + 0x4b, 0xff, 0xf9, 0xa4, 0x2c, 0x0b, 0x00, 0x00, 0x40, 0x82, 0xf9, 0x94, 0x40, 0x92, 0x00, 0x0c, 0x39, 0x00, + 0x00, 0x00, 0x48, 0x00, 0x00, 0x14, 0x54, 0x69, 0x06, 0xff, 0x40, 0x82, 0x00, 0x08, 0x40, 0x9e, 0x00, 0x10, + 0x54, 0x65, 0x67, 0xfe, 0x7d, 0x08, 0x4c, 0x30, 0x7d, 0x08, 0x2a, 0x78, 0x54, 0x85, 0x00, 0x1f, 0x41, 0x82, + 0x00, 0x08, 0x7c, 0xa6, 0x2b, 0x78, 0x54, 0x85, 0x80, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xb0, 0x2b, 0x78, + 0x4b, 0xff, 0xf9, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +}; +const int kenobiwii_size = sizeof(kenobiwii); diff --git a/source/patches/multidol.c b/source/patches/multidol.c new file mode 100644 index 0000000..a3e5639 --- /dev/null +++ b/source/patches/multidol.c @@ -0,0 +1,36 @@ +/* + This file was autogenerated by raw2c. +Visit http://www.devkitpro.org +*/ + +const unsigned char multidol[] = { + 0x7f, 0xe8, 0x03, 0xa6, 0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0xac, 0x7c, 0x00, 0x00, 0x26, + 0x90, 0x01, 0x00, 0x0c, 0x7c, 0x09, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x10, 0x7c, 0x01, 0x02, 0xa6, + 0x90, 0x01, 0x00, 0x14, 0xbc, 0x61, 0x00, 0x18, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x18, 0xa8, + 0x3c, 0xe0, 0x80, 0x00, 0x60, 0xe7, 0x11, 0x98, 0x3e, 0x60, 0x80, 0x00, 0x62, 0x73, 0x11, 0x88, + 0x3e, 0x40, 0x4e, 0x80, 0x62, 0x52, 0x00, 0x20, 0x81, 0xc7, 0x00, 0x04, 0x81, 0xe7, 0x00, 0x08, + 0x82, 0x07, 0x00, 0x0c, 0x82, 0x27, 0x00, 0x00, 0x3c, 0x80, 0x80, 0x00, 0x3c, 0xa0, 0x81, 0x33, + 0x38, 0x84, 0xff, 0xfc, 0x84, 0xc4, 0x00, 0x04, 0x7c, 0x04, 0x28, 0x00, 0x40, 0x80, 0x00, 0x4c, + 0x7c, 0x06, 0x70, 0x00, 0x40, 0x82, 0xff, 0xf0, 0x84, 0xc4, 0x00, 0x04, 0x7c, 0x06, 0x78, 0x00, + 0x40, 0x82, 0xff, 0xe0, 0x84, 0xc4, 0x00, 0x04, 0x7c, 0x06, 0x80, 0x00, 0x40, 0x82, 0xff, 0xd4, + 0x84, 0xc4, 0x00, 0x04, 0x7c, 0x06, 0x88, 0x00, 0x40, 0x82, 0xff, 0xc8, 0x84, 0xc4, 0x00, 0x04, + 0x7c, 0x04, 0x28, 0x00, 0x40, 0x80, 0x00, 0x14, 0x7c, 0x06, 0x90, 0x00, 0x40, 0x82, 0xff, 0xf0, + 0x48, 0x00, 0x00, 0xad, 0x4b, 0xff, 0xff, 0xb0, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x10, 0x00, + 0x3e, 0x60, 0x80, 0x00, 0x62, 0x73, 0x11, 0x90, 0x3c, 0xe0, 0x80, 0x00, 0x60, 0xe7, 0x11, 0xa8, + 0x81, 0xc7, 0x00, 0x04, 0x81, 0xe7, 0x00, 0x08, 0x82, 0x07, 0x00, 0x0c, 0x82, 0x27, 0x00, 0x00, + 0x3c, 0x80, 0x80, 0x00, 0x3c, 0xa0, 0x81, 0x40, 0x38, 0x84, 0xff, 0xfc, 0x84, 0xc4, 0x00, 0x04, + 0x7c, 0x04, 0x28, 0x00, 0x40, 0x80, 0x00, 0x38, 0x7c, 0x06, 0x70, 0x00, 0x40, 0x82, 0xff, 0xf0, + 0x84, 0xc4, 0x00, 0x04, 0x7c, 0x06, 0x78, 0x00, 0x40, 0x82, 0xff, 0xe0, 0x84, 0xc4, 0x00, 0x04, + 0x7c, 0x06, 0x80, 0x00, 0x40, 0x82, 0xff, 0xd4, 0x84, 0xc4, 0x00, 0x04, 0x7c, 0x06, 0x88, 0x00, + 0x40, 0x82, 0xff, 0xc8, 0x48, 0x00, 0x00, 0x39, 0x4b, 0xff, 0xff, 0xc4, 0x80, 0x01, 0x00, 0xac, + 0x7c, 0x08, 0x03, 0xa6, 0x80, 0x01, 0x00, 0x0c, 0x7c, 0x0f, 0xf1, 0x20, 0x80, 0x01, 0x00, 0x10, + 0x7c, 0x09, 0x03, 0xa6, 0x80, 0x01, 0x00, 0x14, 0x7c, 0x01, 0x03, 0xa6, 0xb8, 0x61, 0x00, 0x18, + 0x80, 0x01, 0x00, 0x08, 0x38, 0x21, 0x00, 0xa8, 0x48, 0x00, 0x07, 0x50, 0x7e, 0x44, 0x18, 0x50, + 0x3c, 0xc0, 0x48, 0x00, 0x52, 0x46, 0x01, 0xba, 0x90, 0xc4, 0x00, 0x00, 0x90, 0xd3, 0x00, 0x00, + 0x90, 0x93, 0x00, 0x04, 0x7c, 0x00, 0x20, 0xac, 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x27, 0xac, + 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xc7, 0x00, 0x4c, 0x7c, 0xe3, 0x3b, 0x78, + 0x38, 0x87, 0x00, 0x34, 0x38, 0xa7, 0x00, 0x38, 0x4e, 0x80, 0x04, 0x20, 0x7c, 0x00, 0x04, 0xac, + 0x4c, 0x00, 0x01, 0x2c, 0x7f, 0xe9, 0x03, 0xa6 +}; +const int multidol_size = sizeof(multidol); diff --git a/source/patches/multidol.h b/source/patches/multidol.h new file mode 100644 index 0000000..6984bc3 --- /dev/null +++ b/source/patches/multidol.h @@ -0,0 +1,14 @@ +/* + This file was autogenerated by raw2c. +Visit http://www.devkitpro.org +*/ + +//--------------------------------------------------------------------------------- +#ifndef _multidol_h_ +#define _multidol_h_ +//--------------------------------------------------------------------------------- +extern const unsigned char multidol[]; +extern const int multidol_size; +//--------------------------------------------------------------------------------- +#endif //_multidol_h_ +//--------------------------------------------------------------------------------- diff --git a/source/patches/patchcode.c b/source/patches/patchcode.c new file mode 100644 index 0000000..1df16b5 --- /dev/null +++ b/source/patches/patchcode.c @@ -0,0 +1,850 @@ +/* + * Copyright (C) 2008 Nuke (wiinuke@gmail.com) + * + * this file is part of GeckoOS for USB Gecko + * http://www.usbgecko.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include "codehandler.h" +#include "codehandleronly.h" +#include "codehandlerslota.h" +#include "multidol.h" +#include "defaultgameconfig.h" +#include "usbloader/apploader.h" +#include "patchcode.h" +#include "settings/SettingsEnums.h" +#include "FileOperations/fileops.h" +#include "memory/mem2.h" +#include "memory/memory.h" +#include "gecko.h" + +static u8 *codelistend = (u8 *) 0x80003000; +static u8 *codelist = (u8 *) 0x800022A8; + +static u8 *code_buf = NULL; +static u32 code_size = 0; + +static u32 gameconfsize = 0; +static u32 *gameconf = NULL; +static u32 tempgameconfsize = 0; +static u8 *tempgameconf = NULL; + +extern void patchhook(u32 address, u32 len); + +extern void multidolhook(u32 address); +extern void langvipatch(u32 address, u32 len, u8 langbyte); +extern void vipatch(u32 address, u32 len); + +//static const u32 multidolpatch1[2] = { +// 0x3C03FFB4,0x28004F43 +//}; + +//static const u32 healthcheckhook[2] = { +// 0x41810010,0x881D007D +//}; + +//static const u32 updatecheckhook[3] = { +// 0x80650050,0x80850054,0xA0A50058 +//}; + +//static const u32 multidolpatch2[2] = { +// 0x3F608000, 0x807B0018 +//}; + +//static const u32 recoveryhooks[3] = { +// 0xA00100AC,0x5400073E,0x2C00000F +//}; + +//static const u32 nocopyflag1[3] = { +// 0x540007FF, 0x4182001C, 0x80630068 +//}; + +//static const u32 nocopyflag2[3] = { +// 0x540007FF, 0x41820024, 0x387E12E2 +//}; + +// this one is for the GH3 and VC saves +//static const u32 nocopyflag3[5] = { +// 0x2C030000, 0x40820010, 0x88010020, 0x28000002, 0x41820234 +//}; + +//static const u32 nocopyflag3[5] = { +// 0x2C030000, 0x41820200,0x48000058,0x38610100 +//}; +// this removes the display warning for no copy VC and GH3 saves +//static const u32 nocopyflag4[4] = { +// 0x80010008, 0x2C000000, 0x4182000C, 0x3BE00001 +//}; + +//static const u32 nocopyflag5[3] = { +// 0x801D0024,0x540007FF,0x41820024 +//}; + +//static const u32 movedvdpatch[3] = { +// 0x2C040000, 0x41820120, 0x3C608109 +//}; + +//static const u32 regionfreehooks[5] = { +// 0x7C600774, 0x2C000001, 0x41820030,0x40800010,0x2C000000 +//}; + +//static const u32 cIOScode[16] = { +// 0x7f06c378, 0x7f25cb78, 0x387e02c0, 0x4cc63182 +//}; + +//static const u32 cIOSblock[16] = { +// 0x2C1800F9, 0x40820008, 0x3B000024 +//}; + +//static const u32 fwritepatch[8] = { +// 0x9421FFD0,0x7C0802A6,0x90010034,0xBF210014,0x7C9B2378,0x7CDC3378,0x7C7A1B78,0x7CB92B78 // bushing fwrite +//}; + +static const u32 vipatchcode[3] = { +0x4182000C,0x4180001C,0x48000018 +}; + +static const u32 viwiihooks[4] = { + 0x7CE33B78,0x38870034,0x38A70038,0x38C7004C +}; + +static const u32 kpadhooks[4] = { + 0x9A3F005E,0x38AE0080,0x389FFFFC,0x7E0903A6 +}; + +static const u32 kpadoldhooks[6] = { + 0x801D0060, 0x901E0060, 0x801D0064, 0x901E0064, 0x801D0068, 0x901E0068 +}; + +static const u32 joypadhooks[4] = { + 0x3AB50001, 0x3A73000C, 0x2C150004, 0x3B18000C +}; + +static const u32 gxdrawhooks[4] = { + 0x3CA0CC01, 0x38000061, 0x3C804500, 0x98058000 +}; + +static const u32 gxflushhooks[4] = { + 0x90010014, 0x800305FC, 0x2C000000, 0x41820008 +}; + +static const u32 ossleepthreadhooks[4] = { + 0x90A402E0, 0x806502E4, 0x908502E4, 0x2C030000 +}; + +static const u32 axnextframehooks[4] = { + 0x3800000E, 0x7FE3FB78, 0xB0050000, 0x38800080 +}; + +static const u32 wpadbuttonsdownhooks[4] = { + 0x7D6B4A14, 0x816B0010, 0x7D635B78, 0x4E800020 +}; + +static const u32 wpadbuttonsdown2hooks[4] = { + 0x7D6B4A14, 0x800B0010, 0x7C030378, 0x4E800020 +}; + +static const u32 multidolhooks[4] = { + 0x7C0004AC, 0x4C00012C, 0x7FE903A6, 0x4E800420 +}; + +static const u32 multidolchanhooks[4] = { + 0x4200FFF4, 0x48000004, 0x38800000, 0x4E800020 +}; + +static const u32 langpatch[3] = { + 0x7C600775, 0x40820010, 0x38000000 +}; + +//static const u32 oldpatch002[3] = { +// 0x2C000000, 0x40820214, 0x3C608000 +//}; +// +//static const u32 newpatch002[3] = { +// 0x2C000000, 0x48000214, 0x3C608000 +//}; +// +//static const u32 dczeropatch[4] = { +// 0x7C001FEC, 0x38630020, 0x4200FFF8, 0x4E800020 +//}; + +//--------------------------------------------------------------------------------- +void dogamehooks(u32 hooktype, void *addr, u32 len) +//--------------------------------------------------------------------------------- +{ + if(hooktype == 0x00) + return; + + bool isChannel = (*((char *) 0x80000005) == 0) && (*((char *) 0x80000006) == 0); + void *addr_start = addr; + void *addr_end = addr+len; + + while(addr_start < addr_end) + { + switch(hooktype) + { + default: + case 0x00: + + break; + + case 0x01: + if(memcmp(addr_start, viwiihooks, sizeof(viwiihooks))==0){ + patchhook((u32)addr_start, len); + } + break; + + case 0x02: + + if(memcmp(addr_start, kpadhooks, sizeof(kpadhooks))==0){ + patchhook((u32)addr_start, len); + } + + if(memcmp(addr_start, kpadoldhooks, sizeof(kpadoldhooks))==0){ + patchhook((u32)addr_start, len); + } + break; + + case 0x03: + + if(memcmp(addr_start, joypadhooks, sizeof(joypadhooks))==0){ + patchhook((u32)addr_start, len); + } + break; + + case 0x04: + + if(memcmp(addr_start, gxdrawhooks, sizeof(gxdrawhooks))==0){ + patchhook((u32)addr_start, len); + } + break; + + case 0x05: + + if(memcmp(addr_start, gxflushhooks, sizeof(gxflushhooks))==0){ + patchhook((u32)addr_start, len); + } + break; + + case 0x06: + + if(memcmp(addr_start, ossleepthreadhooks, sizeof(ossleepthreadhooks))==0){ + patchhook((u32)addr_start, len); + } + break; + + case 0x07: + + if(memcmp(addr_start, axnextframehooks, sizeof(axnextframehooks))==0){ + patchhook((u32)addr_start, len); + } + break; + /* + case 0x08: + + if(memcmp(addr_start, customhook, customhooksize)==0){ + patchhook((u32)addr_start, len); + } + if(memcmp(addr_start, multidolhooks, sizeof(multidolhooks))==0){ + multidolhook((u32)addr_start+sizeof(multidolhooks)-4); + } + break; + */ + } + + if(memcmp(addr_start, multidolhooks, sizeof(multidolhooks))==0) + { + multidolhook((u32)addr_start+sizeof(multidolhooks)-4); + } + + if(isChannel && memcmp(addr_start, multidolchanhooks, sizeof(multidolchanhooks)) == 0) + { + *(((u32*)addr_start)+1) = 0x7FE802A6; + DCFlushRange(((u32*)addr_start)+1, 4); + ICInvalidateRange(((u32*)addr_start)+1, 4); + multidolhook((u32)addr_start+sizeof(multidolchanhooks)-4); + } + + addr_start += 4; + } +} + +//--------------------------------------------------------------------------------- +void app_pokevalues() +//--------------------------------------------------------------------------------- +{ + u32 i, *codeaddr, *codeaddr2, *addrfound = NULL; + + if (gameconfsize != 0) + { + for (i = 0; i < gameconfsize / 4; i++) + { + if (*(gameconf + i) == 0) + { + if (((u32 *) (*(gameconf + i + 1))) == NULL || *((u32 *) (*(gameconf + i + 1))) == *(gameconf + i + 2)) + { + *((u32 *) (*(gameconf + i + 3))) = *(gameconf + i + 4); + DCFlushRange((void *) *(gameconf + i + 3), 4); + } + i += 4; + } + else + { + codeaddr = (u32 *) *(gameconf + i + *(gameconf + i) + 1); + codeaddr2 = (u32 *) *(gameconf + i + *(gameconf + i) + 2); + if (codeaddr == 0 && addrfound != NULL) + codeaddr = addrfound; + else if (codeaddr == 0 && codeaddr2 != 0) + codeaddr = (u32 *) ((((u32) codeaddr2) >> 28) << 28); + else if (codeaddr == 0 && codeaddr2 == 0) + { + i += *(gameconf + i) + 4; + continue; + } + if (codeaddr2 == 0) + codeaddr2 = codeaddr + *(gameconf + i); + addrfound = NULL; + while (codeaddr <= (codeaddr2 - *(gameconf + i))) + { + if (memcmp(codeaddr, gameconf + i + 1, (*(gameconf + i)) * 4) == 0) + { + *(codeaddr + ((*(gameconf + i + *(gameconf + i) + 3)) / 4)) = *(gameconf + i + *(gameconf + i) + 4); + if (addrfound == NULL) + addrfound = codeaddr; + } + codeaddr++; + } + i += *(gameconf + i) + 4; + } + } + } +} + +//--------------------------------------------------------------------------------- +static void app_loadgameconfig() +//--------------------------------------------------------------------------------- +{ + if (gameconf == NULL) + { + gameconf = (u32*) MEM2_alloc(65536); + if (gameconf == NULL) + return; + } + const char *discid = (const char *) Disc_ID; + if(!tempgameconf) + { + tempgameconf = (u8 *) defaultgameconfig; + tempgameconfsize = defaultgameconfig_size; + } + + u32 ret; + s32 gameidmatch, maxgameidmatch = -1, maxgameidmatch2 = -1; + u32 i, numnonascii, parsebufpos; + u32 codeaddr, codeval, codeaddr2, codeval2, codeoffset; + u32 temp, tempoffset = 0; + char parsebuffer[18]; + + // Remove non-ASCII characters + numnonascii = 0; + for (i = 0; i < tempgameconfsize; i++) + { + if (tempgameconf[i] < 9 || tempgameconf[i] > 126) + numnonascii++; + else + tempgameconf[i - numnonascii] = tempgameconf[i]; + } + tempgameconfsize -= numnonascii; + + *(tempgameconf + tempgameconfsize) = 0; + //gameconf = (tempgameconf + tempgameconfsize) + (4 - (((u32) (tempgameconf + tempgameconfsize)) % 4)); + + for (maxgameidmatch = 0; maxgameidmatch <= 6; maxgameidmatch++) + { + i = 0; + while (i < tempgameconfsize) + { + maxgameidmatch2 = -1; + while (maxgameidmatch != maxgameidmatch2) + { + while (i != tempgameconfsize && tempgameconf[i] != ':') + i++; + if (i == tempgameconfsize) break; + while ((tempgameconf[i] != 10 && tempgameconf[i] != 13) && (i != 0)) + i--; + if (i != 0) i++; + parsebufpos = 0; + gameidmatch = 0; + while (tempgameconf[i] != ':') + { + if (tempgameconf[i] == '?') + { + parsebuffer[parsebufpos] = discid[parsebufpos]; + parsebufpos++; + gameidmatch--; + i++; + } + else if (tempgameconf[i] != 0 && tempgameconf[i] != ' ') + parsebuffer[parsebufpos++] = tempgameconf[i++]; + else if (tempgameconf[i] == ' ') + break; + else i++; + if (parsebufpos == 8) + break; + } + parsebuffer[parsebufpos] = 0; + if (strncasecmp("DEFAULT", parsebuffer, strlen(parsebuffer)) == 0 && strlen(parsebuffer) == 7) + { + gameidmatch = 0; + goto idmatch; + } + if (strncasecmp(discid, parsebuffer, strlen(parsebuffer)) == 0) + { + gameidmatch += strlen(parsebuffer); + idmatch: if (gameidmatch > maxgameidmatch2) + { + maxgameidmatch2 = gameidmatch; + } + } + while ((i != tempgameconfsize) && (tempgameconf[i] != 10 && tempgameconf[i] != 13)) + i++; + } + while (i != tempgameconfsize && tempgameconf[i] != ':') + { + parsebufpos = 0; + while ((i != tempgameconfsize) && (tempgameconf[i] != 10 && tempgameconf[i] != 13)) + { + if (tempgameconf[i] != 0 && tempgameconf[i] != ' ' && tempgameconf[i] != '(' && tempgameconf[i] != ':') + parsebuffer[parsebufpos++] = tempgameconf[i++]; + else if (tempgameconf[i] == ' ' || tempgameconf[i] == '(' || tempgameconf[i] == ':') + break; + else i++; + if (parsebufpos == 17) + break; + } + parsebuffer[parsebufpos] = 0; + //if (!autobootcheck) + { + if (strncasecmp("codeliststart", parsebuffer, strlen(parsebuffer)) == 0 && strlen(parsebuffer) == 13) + { + sscanf((char *) (tempgameconf + i), " = %x", (unsigned int *) &codelist); + } + if (strncasecmp("codelistend", parsebuffer, strlen(parsebuffer)) == 0 && strlen(parsebuffer) == 11) + { + sscanf((char *) (tempgameconf + i), " = %x", (unsigned int *) &codelistend); + } + if (strncasecmp("poke", parsebuffer, strlen(parsebuffer)) == 0 && strlen(parsebuffer) == 4) + { + ret = sscanf((char *) tempgameconf + i, "( %x , %x", (unsigned int *)&codeaddr, (unsigned int *)&codeval); + if (ret == 2) + { + *(gameconf + (gameconfsize / 4)) = 0; + gameconfsize += 4; + *(gameconf + (gameconfsize / 4)) = 0; + gameconfsize += 8; + *(gameconf + (gameconfsize / 4)) = codeaddr; + gameconfsize += 4; + *(gameconf + (gameconfsize / 4)) = codeval; + gameconfsize += 4; + DCFlushRange((void *) (gameconf + (gameconfsize / 4) - 5), 20); + } + } + if (strncasecmp("pokeifequal", parsebuffer, strlen(parsebuffer)) == 0 && strlen(parsebuffer) == 11) + { + ret = sscanf((char *) (tempgameconf + i), "( %x , %x , %x , %x", (unsigned int *)&codeaddr, (unsigned int *)&codeval, (unsigned int *)&codeaddr2, (unsigned int *)&codeval2); + if (ret == 4) + { + *(gameconf + (gameconfsize / 4)) = 0; + gameconfsize += 4; + *(gameconf + (gameconfsize / 4)) = codeaddr; + gameconfsize += 4; + *(gameconf + (gameconfsize / 4)) = codeval; + gameconfsize += 4; + *(gameconf + (gameconfsize / 4)) = codeaddr2; + gameconfsize += 4; + *(gameconf + (gameconfsize / 4)) = codeval2; + gameconfsize += 4; + DCFlushRange((void *) (gameconf + (gameconfsize / 4) - 5), 20); + } + } + if (strncasecmp("searchandpoke", parsebuffer, strlen(parsebuffer)) == 0 && strlen(parsebuffer) == 13) + { + ret = sscanf((char *) (tempgameconf + i), "( %x%n", (unsigned int *)&codeval, (int *)&tempoffset); + if (ret == 1) + { + gameconfsize += 4; + temp = 0; + while (ret == 1) + { + *(gameconf + (gameconfsize / 4)) = codeval; + gameconfsize += 4; + temp++; + i += tempoffset; + ret = sscanf((char *) (tempgameconf + i), " %x%n", (unsigned int *)&codeval, (int *)&tempoffset); + } + *(gameconf + (gameconfsize / 4) - temp - 1) = temp; + ret = sscanf((char *) (tempgameconf + i), " , %x , %x , %x , %x", (unsigned int *)&codeaddr, (unsigned int *)&codeaddr2, (unsigned int *)&codeoffset, (unsigned int *)&codeval2); + if (ret == 4) + { + *(gameconf + (gameconfsize / 4)) = codeaddr; + gameconfsize += 4; + *(gameconf + (gameconfsize / 4)) = codeaddr2; + gameconfsize += 4; + *(gameconf + (gameconfsize / 4)) = codeoffset; + gameconfsize += 4; + *(gameconf + (gameconfsize / 4)) = codeval2; + gameconfsize += 4; + DCFlushRange((void *) (gameconf + (gameconfsize / 4) - temp - 5), temp * 4 + 20); + } + else gameconfsize -= temp * 4 + 4; + } + + } + } + if (tempgameconf[i] != ':') + { + while ((i != tempgameconfsize) && (tempgameconf[i] != 10 && tempgameconf[i] != 13)) + i++; + if (i != tempgameconfsize) + i++; + } + } + if (i != tempgameconfsize) + while ((tempgameconf[i] != 10 && tempgameconf[i] != 13) && (i != 0)) + i--; + } + } + + if(tempgameconf != defaultgameconfig) + free(tempgameconf); + + if (code_size > (u32) codelistend - (u32) codelist) + { + gprintf("Ocarina: Too many codes found: filesize %i, maxsize: %i\n", code_size, (u32) codelistend - (u32) codelist); + MEM2_free(code_buf); + code_buf = NULL; + code_size = 0; + } +} + +//--------------------------------------------------------------------------------- +void load_handler(u32 hooktype, u32 debugger, u32 pauseAtStart) +//--------------------------------------------------------------------------------- +{ + if (hooktype != 0x00) + { + if (debugger == 0x01) + codelist = (u8 *) 0x800028B8; + codelistend = (u8 *) 0x80003000; + app_loadgameconfig(); + + if (debugger == 0x01) + { + //! Prefer Slot B + if(usb_isgeckoalive(EXI_CHANNEL_1)) + { + // slot B + memset((void*)0x80001800,0,codehandler_size); + memcpy((void*)0x80001800,codehandler,codehandler_size); + if (pauseAtStart == 0x01) + *(u32*)0x80002774 = 1; + memcpy((void*)0x80001CDE, &codelist, 2); + memcpy((void*)0x80001CE2, ((u8*) &codelist) + 2, 2); + memcpy((void*)0x80001F5A, &codelist, 2); + memcpy((void*)0x80001F5E, ((u8*) &codelist) + 2, 2); + DCFlushRange((void*)0x80001800,codehandler_size); + } + else + { + // Slot A + memset((void*)0x80001800,0,codehandlerslota_size); + memcpy((void*)0x80001800,codehandlerslota,codehandlerslota_size); + if (pauseAtStart == 0x01) + *(u32*)0x80002774 = 1; + memcpy((void*)0x80001CDE, &codelist, 2); + memcpy((void*)0x80001CE2, ((u8*) &codelist) + 2, 2); + memcpy((void*)0x80001F5A, &codelist, 2); + memcpy((void*)0x80001F5E, ((u8*) &codelist) + 2, 2); + DCFlushRange((void*)0x80001800,codehandlerslota_size); + } + } + else + { + memset((void*)0x80001800,0,codehandleronly_size); + memcpy((void*)0x80001800,codehandleronly,codehandleronly_size); + memcpy((void*)0x80001906, &codelist, 2); + memcpy((void*)0x8000190A, ((u8*) &codelist) + 2, 2); + DCFlushRange((void*)0x80001800,codehandleronly_size); + } + // Load multidol handler + memset((void*)0x80001000,0,multidol_size); + memcpy((void*)0x80001000,multidol,multidol_size); + DCFlushRange((void*)0x80001000,multidol_size); + switch(hooktype) + { + default: + break; + case 0x01: + memcpy((void*)0x8000119C,viwiihooks,12); + memcpy((void*)0x80001198,viwiihooks+3,4); + break; + case 0x02: + memcpy((void*)0x8000119C,kpadhooks,12); + memcpy((void*)0x80001198,kpadhooks+3,4); + break; + case 0x03: + memcpy((void*)0x8000119C,joypadhooks,12); + memcpy((void*)0x80001198,joypadhooks+3,4); + break; + case 0x04: + memcpy((void*)0x8000119C,gxdrawhooks,12); + memcpy((void*)0x80001198,gxdrawhooks+3,4); + break; + case 0x05: + memcpy((void*)0x8000119C,gxflushhooks,12); + memcpy((void*)0x80001198,gxflushhooks+3,4); + break; + case 0x06: + memcpy((void*)0x8000119C,ossleepthreadhooks,12); + memcpy((void*)0x80001198,ossleepthreadhooks+3,4); + break; + case 0x07: + memcpy((void*)0x8000119C,axnextframehooks,12); + memcpy((void*)0x80001198,axnextframehooks+3,4); + break; + /* + case 0x08: + if (customhooksize == 16) + { + memcpy((void*)0x8000119C,customhook,12); + memcpy((void*)0x80001198,customhook+3,4); + } + break; + */ + case 0x09: + memcpy((void*)0x8000119C,wpadbuttonsdownhooks,12); + memcpy((void*)0x80001198,wpadbuttonsdownhooks+3,4); + break; + case 0x0A: + memcpy((void*)0x8000119C,wpadbuttonsdown2hooks,12); + memcpy((void*)0x80001198,wpadbuttonsdown2hooks+3,4); + break; + } + DCFlushRange((void*)0x80001198,16); + + memcpy((void *) 0x80001800, (void*) Disc_ID, 6); // For Wiird + DCFlushRange((void *) 0x80001800, 6); + } + + //Copy the codes + if (code_buf && code_size > 0) + { + memset(codelist, 0, (u32) codelistend - (u32) codelist); + memcpy(codelist, code_buf, code_size); + DCFlushRange(codelist, (u32) codelistend - (u32) codelist); + free(code_buf); + code_buf = NULL; + gprintf("Ocarina codes applied to %p size: %i\n", codelist, (u32) codelistend - (u32) codelist); + } + + if(hooktype != 0x00) + { + //This needs to be done after loading the .dol into memory + app_pokevalues(); + } +} + +int LoadGameConfig(const char *CheatFilepath) +{ + int filesize = 0; + tempgameconf = (u8 *) defaultgameconfig; + tempgameconfsize = defaultgameconfig_size; + gameconfsize = 0; + + FILE* fp; + char filepath[200]; + snprintf(filepath, sizeof(filepath), "%s/gameconfig.txt", CheatFilepath); + + fp = fopen(filepath, "rb"); + + if (!fp) + { + snprintf(filepath, sizeof(filepath), "sd:/gameconfig.txt"); + fp = fopen(filepath, "rb"); + int i; + for(i = 1; i <= 8; ++i) + { + if(fp) break; + + snprintf(filepath, sizeof(filepath), "usb%i:/gameconfig.txt", i); + fp = fopen(filepath, "rb"); + } + } + + if (!fp) + return 0; + + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + fseek(fp, 0, SEEK_SET); + + tempgameconf = (u8*) MEM2_alloc(filesize); + if (tempgameconf == NULL) { + tempgameconf = (u8 *) defaultgameconfig; + fclose(fp); + return -1; + } + + int ret = fread((void*) tempgameconf, 1, filesize, fp); + + fclose(fp); + + if (ret != filesize) + { + MEM2_free(tempgameconf); + tempgameconf = (u8 *) defaultgameconfig; + return -1; + } + tempgameconfsize = filesize; + + return 0; +} + +int ocarina_load_code(const char *CheatFilepath, u8 *gameid) +{ + char filepath[150]; + char id[7]; + + memset(id, 0, sizeof(id)); + memcpy(id, gameid, 6); + snprintf(filepath, sizeof(filepath), "%s%s.gct", CheatFilepath, id); + + gprintf("Ocarina: Searching codes...%s\n", filepath); + + FILE * fp = fopen(filepath, "rb"); + if (!fp) + { + gprintf("Ocarina: No codes found"); + printf("\n"); + return 0; + } + + fseek(fp, 0, SEEK_END); + u32 filesize = ftell(fp); + rewind(fp); + + code_buf = (u8*) MEM2_alloc(filesize); + if (!code_buf) + { + gprintf("Ocarina: Not enough memory\n"); + fclose(fp); + return 0; + } + + code_size = fread(code_buf, 1, filesize, fp); + + fclose(fp); + + if (code_size == 0) + { + gprintf("Ocarina: could not read file.\n"); + MEM2_free(code_buf); + code_buf = NULL; + code_size = 0; + return 0; + } + + gprintf("Ocarina: Codes found.\n"); + + //LoadGameConfig(CheatFilepath); + + return code_size; +} + +void langpatcher(void *addr, u32 len, u8 languageChoice) +{ + u8 ocarinaLangPatchByte = 1; + switch (languageChoice) + { + case JAPANESE: + ocarinaLangPatchByte = 0x00; + break; + case ENGLISH: + ocarinaLangPatchByte = 0x01; + break; + case GERMAN: + ocarinaLangPatchByte = 0x02; + break; + case FRENCH: + ocarinaLangPatchByte = 0x03; + break; + case SPANISH: + ocarinaLangPatchByte = 0x04; + break; + case ITALIAN: + ocarinaLangPatchByte = 0x05; + break; + case DUTCH: + ocarinaLangPatchByte = 0x06; + break; + case S_CHINESE: + ocarinaLangPatchByte = 0x07; + break; + case T_CHINESE: + ocarinaLangPatchByte = 0x08; + break; + case KOREAN: + ocarinaLangPatchByte = 0x09; + break; + default: + return; + } + + u8 * addr_start = addr; + u8 * addr_end = addr + len; + + while (addr_start < addr_end) + { + + if (memcmp(addr_start, langpatch, sizeof(langpatch)) == 0) + { + langvipatch((u32) addr_start, len, ocarinaLangPatchByte); + } + addr_start += 4; + } +} + +void vidolpatcher(void *addr, u32 len) +{ + + void *addr_start = addr; + void *addr_end = addr + len; + + while (addr_start < addr_end) + { + if (memcmp(addr_start, vipatchcode, sizeof(vipatchcode)) == 0) + { + vipatch((u32) addr_start, len); + } + addr_start += 4; + } +} + diff --git a/source/patches/patchcode.h b/source/patches/patchcode.h new file mode 100644 index 0000000..5e867d4 --- /dev/null +++ b/source/patches/patchcode.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008 Nuke (wiinuke@gmail.com) + * + * this file is part of GeckoOS for USB Gecko + * http://www.usbgecko.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PATCHCODE_H__ +#define __PATCHCODE_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define MAX_GCT_SIZE 2056 + +// Function prototypes +void dogamehooks(u32 hooktype, void *addr, u32 len); +void load_handler(u32 hooktype, u32 debugger, u32 pauseAtStart); +void langpatcher(void *addr, u32 len, u8 languageChoice); +void vidolpatcher(void *addr, u32 len); +void patchdebug(void *addr, u32 len); +int LoadGameConfig(const char *CheatFilepath); +int ocarina_load_code(const char *CheatFilepath, u8 *gameid); + +#ifdef __cplusplus +} +#endif + +#endif // __PATCHCODE_H__ diff --git a/source/patches/patchhook.S b/source/patches/patchhook.S new file mode 100644 index 0000000..a64315e --- /dev/null +++ b/source/patches/patchhook.S @@ -0,0 +1,505 @@ +.text +.set r0,0; .set sp,1; .set r2,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 + + +.globl patchhook # r3 address +patchhook: + mtctr r4 + lis r6, 0x4E80 + ori r6, r6, 0x0020 # blr +findblr: + lwz r5, 0(r3) + cmpw r6, r5 + beq writebranch + addi r3, r3, 4 # next word + bdnz findblr # loop length + b exit # stop unhooked game hanging + +writebranch: + lis r4, 0x8000 # 800018A0 hook location (source) + ori r4, r4, 0x18A8 + subf r4, r3, r4 # subtract r3 from r4 and place in r4 + lis r5, 0x3FF + ori r5, r5, 0xFFFF # 0x3FFFFFF + and r4, r4, r5 + lis r5, 0x4800 # 0x48000000 + or r4, r4, r5 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exit: + blr # return + + .globl patchhook2 # r3 address +patchhook2: + mtctr r4 + lis r6, 0x4E80 + ori r6, r6, 0x0020 # blr +findblr2: + lwz r5, 0(r3) + cmpw r6, r5 + beq writebranch2 + addi r3, r3, 4 # next word + bdnz findblr2 # loop length + b exit2 # stop unhooked game hanging + +writebranch2: + lis r4, 0x8000 # 81700000 our temp patcher + ori r4, r4, 0x18a8 + subf r4, r3, r4 # subtract r3 from r4 and place in r4 + lis r5, 0x3FF + ori r5, r5, 0xFFFF # 0x3FFFFFF + and r4, r4, r5 + lis r5, 0x4800 # 0x48000000 + or r4, r4, r5 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exit2: + blr # return + +.globl patchhook3 # r3 address +patchhook3: + mtctr r4 + lis r6, 0x4BFF + ori r6, r6, 0xE955 # blr +findbne: + lwz r5, 0(r3) + cmpw r6, r5 + beq writebl + addi r3, r3, 4 # next word + bdnz findbne # loop length + b exit3 # stop unhooked game hanging + +writebl: + lis r4, 0x4BFF # 81700000 our temp patcher + ori r4, r4, 0xEA91 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exit3: + blr # return + +.globl multidolpatchone # r3 address +multidolpatchone: + mtctr r4 + lis r6, 0x3800 + ori r6, r6, 0x0001 # (li r0,1) +findmulti: + lwz r5, 0(r3) + cmpw r6, r5 + beq writemulti + subi r3, r3, 4 # go back + bdnz findmulti # loop length + b exit5 # stop unhooked game hanging + +writemulti: + lis r4, 0x8170 # 81700000 + ori r4, r4, 0x0020 + subf r18, r3, r4 # subf r18,(source),(dest) + lis r6, 0x4800 + ori r6,r6,1 + rlwimi r6,r18,0,6,29 + stw r6,0(r3) + stw r6,0(r19) + stw r3,4(r19) + dcbf r0, r3 + sync + icbi r0, r3 + isync +exit5: + blr # return + +.globl multidolpatchtwo # r3 address +multidolpatchtwo: + mtctr r4 + lis r6, 0x3F60 + ori r6, r6, 0x8000 # (lis r27,-32768) +findmulti2: + lwz r5, 0(r3) + cmpw r6, r5 + beq writemulti2 + addi r3, r3, 4 # go forward + bdnz findmulti2 # loop length + b exit6 # stop unhooked game hanging + +writemulti2: + lis r4, 0x8170 # 81700020 + ori r4, r4, 0x0000 + subf r18, r3, r4 # subf r18,(source),(dest) + lis r6, 0x4800 + ori r6,r6,1 + rlwimi r6,r18,0,6,29 + stw r6,0(r3) + stw r6,0(r19) + stw r3,4(r19) + dcbf r0, r3 + sync + icbi r0, r3 + isync +exit6: + blr # return + +.globl multidolhook # r3 address +multidolhook: + lis r4, 0x8000 # 80001000 hook location (source) + ori r4, r4, 0x1000 + subf r4, r3, r4 # subtract r3 from r4 and place in r4 + lis r5, 0x3FF + ori r5, r5, 0xFFFF # 0x3FFFFFF + and r4, r4, r5 + lis r5, 0x4800 # 0x48000000 + or r4, r4, r5 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 + blr # return + + +.globl langvipatch # r3 address, r4 len, r5 lang byte +langvipatch: + mtctr r4 + lis r6, 0x8861 + ori r6, r6, 0x0008 # lbz r3, 8(sp) +findlang: + lwz r7, 0(r3) + cmpw r6, r7 + beq patchlang + addi r3, r3, 4 # next word + bdnz findlang # loop length + b exitlang # stop unhooked game hanging + +patchlang: + + lis r4, 0x3860 # 0x38600001 li %r3, 1 # eng + add r4, r4, r5 +gofinal: + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exitlang: + blr # return + +.globl vipatch # r3 address +vipatch: + mtctr r4 + lis r6, 0x5400 + ori r6, r6, 0xFFFE +findvi: + lwz r5, 0(r3) + cmpw r6, r5 + beq patchvi + addi r3, r3, 4 # next word + bdnz findvi # loop length + b exitvi # stop unhooked game hanging + +patchvi: + lis r4, 0x8000 + ori r4, r4, 0x0003 + lbz r5, 0(r4) + cmpwi r5, 0x45 # USA + beq patchusa + cmpwi r5, 0x4A + beq patchjap2 # JAP + b exitvi +patchjap2: + lis r4, 0x3800 + ori r4, r4, 0x0001 + b gofinal2 +patchusa: + lis r4, 0x3800 + ori r4, r4, 0x0000 +gofinal2: + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exitvi: + blr # return + +.globl regionfreejap # r3 address +regionfreejap: + mtctr r4 + lis r6, 0x2C1B + ori r6, r6, 0x0000 # blr +findjap: + lwz r5, 0(r3) + cmpw r6, r5 + beq writenop + addi r3, r3, 4 # next word + bdnz findjap # loop length + b exitjap # stop unhooked game hanging + +writenop: + addi r3, r3, 4 # next word + lis r4, 0x6000 # nop + ori r4, r4, 0x0000 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exitjap: + blr # return + +.globl regionfreeusa # r3 address +regionfreeusa: + mtctr r4 + lis r6, 0x281B + ori r6, r6, 0x0001 # blr +findusa: + lwz r5, 0(r3) + cmpw r6, r5 + beq writenop1 + addi r3, r3, 4 # next word + bdnz findusa # loop length + b exitusa # stop unhooked game hanging + +writenop1: + addi r3, r3, 4 # next word + lis r4, 0x6000 # nop + ori r4, r4, 0x0000 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exitusa: + blr # return + +.globl regionfreepal # r3 address +regionfreepal: + mtctr r4 + lis r6, 0x281B + ori r6, r6, 0x0002 # blr +findpal: + lwz r5, 0(r3) + cmpw r6, r5 + beq writenop2 + addi r3, r3, 4 # next word + bdnz findpal # loop length + b exitpal # stop unhooked game hanging + +writenop2: + addi r3, r3, 4 # next word + lis r4, 0x6000 # nop + ori r4, r4, 0x0000 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 + + lis r6, 0x4082 + ori r6, r6, 0x001C # bne loc_81377A2C +findextra: #this is just the bne to b patch + lwz r5, 0(r3) + cmpw r6, r5 + beq writeb + addi r3, r3, 4 # next word + bdnz findextra # loop length + b exitpal # stop unhooked game hanging + +writeb: + addi r3, r3, 4 # next word + lis r4, 0x4800 + ori r4, r4, 0x001c # b loc_81377A2C + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exitpal: + blr # return + +.globl removehealthcheck # r3 address +removehealthcheck: + mtctr r4 + lis r6, 0x4182 + ori r6, r6, 0x004C # blr +findhe: + lwz r5, 0(r3) + cmpw r6, r5 + beq writebhe + addi r3, r3, 4 # next word + bdnz findhe # loop length + b exithe # stop unhooked game hanging + +writebhe: + lis r4, 0x6000 + ori r4, r4, 0x0000 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exithe: + blr # return + + + +.globl patchupdatecheck # r3 address +patchupdatecheck: + mtctr r4 + lis r6, 0x4082 + ori r6, r6, 0x0020 # blr +finduc: + lwz r5, 0(r3) + cmpw r6, r5 + beq writenopuc + addi r3, r3, 4 # next word + bdnz finduc # loop length + b exituc # stop unhooked game hanging + +writenopuc: + lis r4, 0x6000 + ori r4, r4, 0x0000 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exituc: + blr # return + + + + +.globl copyflagcheck1 # r3 address +copyflagcheck1: + mtctr r4 + lis r6, 0x5400 + ori r6, r6, 0x07FF +findncf1: + lwz r5, 0(r3) + cmpw r6, r5 + beq writencf1 + subi r3, r3, 4 # next word + bdnz findncf1 # loop length + b exitncf1 # stop unhooked game hanging + +writencf1: + lis r4, 0x7C00 + ori r4, r4, 0x0000 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exitncf1: + blr # return + +.globl copyflagcheck2 # r3 address +copyflagcheck2: + mtctr r4 + lis r6, 0x5400 + ori r6, r6, 0x07FF +findncf2: + lwz r5, 0(r3) + cmpw r6, r5 + beq writencf2 + subi r3, r3, 4 # next word + bdnz findncf2 # loop length + b exitncf2 # stop unhooked game hanging + +writencf2: + lis r4, 0x7C00 + ori r4, r4, 0x0000 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exitncf2: + blr # return + + +.globl copyflagcheck3 # r3 address +copyflagcheck3: +findncf3: + addi r3, r3, 20 # go back one dword (4 bytes) + lwz r5, 0(r3) +writencf3: + lis r4, 0x3860 + ori r4, r4, 0x0001 # li r3,1 + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exitncf3: + blr # return + + +.globl copyflagcheck4 # r3 address +copyflagcheck4: + mtctr r4 + lis r6, 0x3BE0 + ori r6, r6, 0x0001 # li r31,1 +findncf4: + lwz r5, 0(r3) + cmpw r6, r5 + beq writencf4 + addi r3, r3, 4 # next word + bdnz findncf4 # loop length + b exitncf4 # stop unhooked game hanging + +writencf4: + lis r4, 0x3BE0 + ori r4, r4, 0x0000 # change this to 3BE00000 (li r31,0) + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exitncf4: + blr # return + +.globl copyflagcheck5 # r3 address +copyflagcheck5: + mtctr r4 + lis r6, 0x4182 + ori r6, r6, 0x0024 # beq loc_8134AA60 +findncf5: + lwz r5, 0(r3) + cmpw r6, r5 + beq writencf5 + addi r3, r3, 4 # next word + bdnz findncf5 # loop length + b exitncf5 # stop unhooked game hanging + +writencf5: + #addi r3, r3, 8 # skip 2 + + lis r4, 0x801D + ori r4, r4, 0x0024 # change to 801D0024 (lwz r0,36(r29)) + stw r4, 0(r3) + dcbf r0, r3 + icbi r0, r3 + + addi r3, r3, 4 # next word + + lis r4, 0x5400 + ori r4, r4, 0x003C # change to 5400003C (rlwinm r0,r0,0,0,30) + stw r4, 0(r3) + dcbf r0, r3 + icbi r0, r3 + + addi r3, r3, 4 # next word + + lis r4, 0x901D + ori r4, r4, 0x0024 # change to 901D0024 (stw r0,36(r29)) + stw r4, 0(r3) + dcbf r0, r3 + icbi r0, r3 + + addi r3, r3, 4 # next word + + lis r4, 0x4800 + ori r4, r4, 0x0018 # change to 48000018 (b 0x8134aa60) + stw r4, 0(r3) + dcbf r0, r3 + icbi r0, r3 +exitncf5: + blr # return + +.globl movedvdhooks # r3 address +movedvdhooks: + lis r6, 0x4182 + ori r6, r6, 0x0120 # beq loc_813A7938 +findmd1: + addi r3, r3, 4 # next word + lwz r5, 0(r3) +writemd1: + lis r4, 0x6000 + ori r4, r4, 0x0000 # nop + stw r4, 0(r3) # result in r3 + dcbf r0, r3 # data cache block flush + icbi r0, r3 +exitmd1: + blr # return diff --git a/source/patches/ppc.h b/source/patches/ppc.h new file mode 100644 index 0000000..000df8d --- /dev/null +++ b/source/patches/ppc.h @@ -0,0 +1,81 @@ + +/* Condition Register Bit Fields */ + +#define cr0 0 +#define cr1 1 +#define cr2 2 +#define cr3 3 +#define cr4 4 +#define cr5 5 +#define cr6 6 +#define cr7 7 + +/* General Purpose Registers */ + +#define r0 0 +#define r1 1 +#define r2 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 + +/* Define Floating Point Registers */ + +#define f0 0 +#define f1 1 +#define f2 2 +#define f3 3 +#define f4 4 +#define f5 5 +#define f6 6 +#define f7 7 +#define f8 8 +#define f9 9 +#define f10 10 +#define f11 11 +#define f12 12 +#define f13 13 +#define f14 14 +#define f15 15 +#define f16 16 +#define f17 17 +#define f18 18 +#define f19 19 +#define f20 20 +#define f21 21 +#define f22 22 +#define f23 23 +#define f24 24 +#define f25 25 +#define f26 26 +#define f27 27 +#define f28 28 +#define f29 29 +#define f30 30 +#define f31 31 diff --git a/source/patches/wip.cpp b/source/patches/wip.cpp new file mode 100644 index 0000000..e72af3d --- /dev/null +++ b/source/patches/wip.cpp @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include "gecko.h" + +#include "settings/CSettings.h" +#include "memory/mem2.h" +#include "wip.h" + +static WIP_Code * CodeList = NULL; +static u32 CodesCount = 0; +static u32 ProcessedLength = 0; +static u32 Counter = 0; + +extern "C" void do_wip_code(u8 * dst, u32 len) +{ + if (!CodeList) return; + + if (Counter < 3) + { + Counter++; + return; + } + + u32 i = 0; + int n = 0; + int offset = 0; + + for (i = 0; i < CodesCount; i++) + { + for (n = 0; n < 4; n++) + { + offset = CodeList[i].offset + n - ProcessedLength; + + if (offset < 0 || offset >= (int) len) continue; + + if (dst[offset] == ((u8 *) &CodeList[i].srcaddress)[n]) + { + dst[offset] = ((u8 *) &CodeList[i].dstaddress)[n]; + gprintf("WIP: %08X Address Patched.\n", CodeList[i].offset + n); + } + else + { + gprintf("WIP: %08X Address does not match with WIP entrie.\n", CodeList[i].offset + n); + gprintf("Destination: %02X | Should be: %02X.\n", dst[offset], ((u8 *) &CodeList[i].srcaddress)[n]); + } + } + } + ProcessedLength += len; + Counter++; +} + +//! for internal patches only +//! .wip files override internal patches +//! the codelist has to be freed if the set fails +//! if set was successful the codelist will be freed when it's done +extern "C" bool set_wip_list(WIP_Code * list, int size) +{ + if (!CodeList && size > 0) + { + CodeList = list; + CodesCount = size; + return true; + } + + return false; +} + +extern "C" void wip_reset_counter() +{ + ProcessedLength = 0; + //alternative dols don't need a skip. only main.dol. + Counter = 3; +} + +extern "C" void free_wip() +{ + if (CodeList) + MEM2_free(CodeList); + CodeList = NULL; + CodesCount = 0; + Counter = 0; + ProcessedLength = 0; +} + +extern "C" int load_wip_code(u8 *gameid) +{ + char filepath[150]; + char GameID[8]; + memset(GameID, 0, sizeof(GameID)); + memcpy(GameID, gameid, 6); + snprintf(filepath, sizeof(filepath), "%s%s.wip", Settings.WipCodepath, GameID); + + FILE * fp = fopen(filepath, "rb"); + if (!fp) + { + memset(GameID, 0, sizeof(GameID)); + memcpy(GameID, gameid, 4); + snprintf(filepath, sizeof(filepath), "%s%s.wip", Settings.WipCodepath, GameID); + fp = fopen(filepath, "rb"); + } + if (!fp) + { + memset(GameID, 0, sizeof(GameID)); + memcpy(GameID, gameid, 3); + snprintf(filepath, sizeof(filepath), "%s%s.wip", Settings.WipCodepath, GameID); + fp = fopen(filepath, "rb"); + } + + if (!fp) return -1; + + free_wip(); + + char line[255]; + gprintf("\nLoading WIP code from %s.\n", filepath); + + while (fgets(line, sizeof(line), fp)) + { + if (line[0] == '#') continue; + if (line[0] == ';') continue; + if (line[0] == ':') continue; + + if (strlen(line) < 26) continue; + + u32 offset = (u32) strtoul(line, NULL, 16); + u32 srcaddress = (u32) strtoul(line + 9, NULL, 16); + u32 dstaddress = (u32) strtoul(line + 18, NULL, 16); + + if (!CodeList) CodeList = (WIP_Code *) MEM2_alloc(sizeof(WIP_Code)); + + WIP_Code * tmp = (WIP_Code *) MEM2_realloc(CodeList, (CodesCount + 1) * sizeof(WIP_Code)); + if (!tmp) + { + fclose(fp); + free_wip(); + return -1; + } + + CodeList = tmp; + + CodeList[CodesCount].offset = offset; + CodeList[CodesCount].srcaddress = srcaddress; + CodeList[CodesCount].dstaddress = dstaddress; + CodesCount++; + } + fclose(fp); + gprintf("\n"); + + return 0; +} diff --git a/source/patches/wip.h b/source/patches/wip.h new file mode 100644 index 0000000..0182ba2 --- /dev/null +++ b/source/patches/wip.h @@ -0,0 +1,27 @@ +#ifndef __WIP_H__ +#define __WIP_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct + { + u32 offset; + u32 srcaddress; + u32 dstaddress; + } WIP_Code; + + int load_wip_code(u8 *gameid); + void do_wip_code(u8 * dst, u32 len); + bool set_wip_list(WIP_Code * list, int size); + void wip_reset_counter(); + void free_wip(); + +#ifdef __cplusplus +} +#endif + +#endif //__WIP_H__ diff --git a/source/prompts/BannerWindow.cpp b/source/prompts/BannerWindow.cpp new file mode 100644 index 0000000..702b800 --- /dev/null +++ b/source/prompts/BannerWindow.cpp @@ -0,0 +1,726 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 "BannerWindow.hpp" +#include "GUI/GuiBannerGrid.h" +#include "banner/BannerAsync.h" +#include "banner/CustomBanner.h" +#include "banner/OpeningBNR.hpp" +#include "settings/CSettings.h" +#include "settings/CGameStatistics.h" +#include "settings/menus/GameSettingsMenu.hpp" +#include "SystemMenu/SystemMenuResources.h" +#include "prompts/GameWindow.hpp" +#include "themes/CTheme.h" +#include "language/gettext.h" +#include "menu/menus.h" +#include "utils/tools.h" + +// Load only once +BannerFrame BannerWindow::bannerFrame; + +BannerWindow::BannerWindow(GameBrowseMenu *m, struct discHdr *header) + : GuiWindow(screenwidth, screenheight) + , browserMenu(m) + , MaxAnimSteps(Settings.BannerZoomDuration) +{ + ScreenProps.x = screenwidth; + ScreenProps.y = screenheight; + + f32 xOffset = Settings.BannerProjectionOffsetX; + f32 yOffset = Settings.BannerProjectionOffsetY; + + guMtxIdentity(modelview); + guMtxTransApply (modelview, modelview, xOffset, yOffset, 0.0F); + + memcpy(&originalProjection, &FSProjection2D, sizeof(Mtx44)); + + returnVal = -1; + gameSelected = 0; + gameSound = NULL; + dvdheader = NULL; + reducedVol = false; + + if(!bannerFrame.IsLoaded()) + bannerFrame.Load(U8Archive(SystemMenuResources::Instance()->GetChanTtlAsh(), + SystemMenuResources::Instance()->GetChanTtlAshSize())); + + AnimStep = 0; + AnimPosX = 0.5f * (ScreenProps.x - fIconWidth); + AnimPosY = 0.5f * (ScreenProps.y - fIconHeight); + AnimZoomIn = true; + AnimationRunning = false; + + int gameIdx; + + //! get the game index to this header + for(gameIdx = 0; gameIdx < gameList.size(); ++gameIdx) + { + if(gameList[gameIdx] == header) + { + gameSelected = gameIdx; + break; + } + } + + //! Set dvd header if the header does not match any of the list games + if(gameIdx == gameList.size()) + dvdheader = header; + + GuiBannerGrid *bannerBrowser = dynamic_cast(browserMenu->GetGameBrowser()); + if(bannerBrowser) + bannerBrowser->GetIconCoordinates(gameSelected, &AnimPosX, &AnimPosY); + + gameBanner = new Banner; + + imgFavorite = Resources::GetImageData("favorite.png"); + imgNotFavorite = Resources::GetImageData("not_favorite.png"); + imgLeft = Resources::GetImageData("startgame_arrow_left.png"); + imgRight = Resources::GetImageData("startgame_arrow_right.png"); + + trigA = new GuiTrigger; + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigB = new GuiTrigger; + trigB->SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + trigL = new GuiTrigger; + trigL->SetButtonOnlyTrigger(-1, WPAD_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_LEFT, PAD_BUTTON_LEFT); + trigR = new GuiTrigger; + trigR->SetButtonOnlyTrigger(-1, WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT, PAD_BUTTON_RIGHT); + trigPlus = new GuiTrigger; + trigPlus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_PLUS | WPAD_CLASSIC_BUTTON_PLUS, PAD_TRIGGER_R); + trigMinus = new GuiTrigger; + trigMinus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, PAD_TRIGGER_L); + + playcntTxt = new GuiText((char*) NULL, 18, thColor("r=0 g=0 b=0 a=255 - banner window playcount text color")); + playcntTxt->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + playcntTxt->SetPosition(thInt("0 - banner window play count pos x"), + thInt("215 - banner window play count pos y") - Settings.AdjustOverscanY / 2); + + settingsBtn = new GuiButton(215, 75); + settingsBtn->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + settingsBtn->SetSoundOver(btnSoundOver); + settingsBtn->SetSoundClick(btnSoundClick2); + settingsBtn->SetPosition(-120, 175); + settingsBtn->SetTrigger(trigA); + + startBtn = new GuiButton(215, 75); + startBtn->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + startBtn->SetSoundOver(btnSoundOver); + startBtn->SetSoundClick(btnSoundClick2); + startBtn->SetPosition(110, 175); + startBtn->SetTrigger(trigA); + + backBtn = new GuiButton(215, 75); + backBtn->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + backBtn->SetSoundOver(btnSoundOver); + backBtn->SetSoundClick(btnSoundClick2); + backBtn->SetPosition(-screenwidth, -screenheight); // set out of screen + backBtn->SetTrigger(0, trigA); + backBtn->SetTrigger(1, trigB); + + // Set favorite button position + int xPos = -198-(3*27)-14; + if(Settings.bannerFavIcon == BANNER_FAVICON_SINGLE_LINEA) // push more to the screen border + xPos += -14; + int yPos = 175-27; + float angle = 3*M_PI/2; + for(int i = 0; i < FAVORITE_STARS; ++i) + { + + if(Settings.bannerFavIcon == BANNER_FAVICON_CIRC) + { + /* + Arrangement: + 0 + 1 + 2 + 3 + 4 + */ + + if (i==0 || i == 4){ + xPos = (-180-70 - 40*cos(angle)); //litte adjustment, image looks too far + } + else{ + xPos = (-180-65 - 40*cos(angle)); + } + yPos = (169 + 40*sin(angle)); + angle += M_PI/4; + + /* + if (i == 0){ + xPos += 27+14; + }else if (i < 3){ + xPos += -14; + yPos += 27; + } else if (i >= 3){ + xPos += 14; + yPos += 27; + } + */ + } + else if(Settings.bannerFavIcon == BANNER_FAVICON_SIN) + { + /* + Arrangement: + 0 2 4 + 1 3 + */ + + xPos += 27; + xPos += -14; + if ((i&1)==0) + { + yPos += 27; + } + else + { + yPos -= 27; + } + } + else if(Settings.bannerFavIcon == BANNER_FAVICON_MULTI_LINE) + { + /* + Sequential arrangement, 3 on top, 2 at bottom: + 1 2 3 + 4 5 + */ + + xPos += 27; + if (i==2){ + xPos += -27-27-14; + yPos += 27; + } + + } + else if(Settings.bannerFavIcon == BANNER_FAVICON_SINGLE_LINEA) + { + /* Arrangement : inline above the settings */ + xPos += 27; + yPos = 95; + } + else if(Settings.bannerFavIcon == BANNER_FAVICON_SINGLE_LINEB) + { + /* Arrangement : inline below the settings */ + xPos += 27; + yPos = 210; + } + + FavoriteBtnImg[i] = new GuiImage; + FavoriteBtnImg[i]->SetWidescreen(Settings.widescreen); + FavoriteBtn[i] = new GuiButton(imgFavorite->GetWidth(), imgFavorite->GetHeight()); + FavoriteBtn[i]->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + FavoriteBtn[i]->SetPosition(xPos, yPos); + FavoriteBtn[i]->SetImage(FavoriteBtnImg[i]); + FavoriteBtn[i]->SetSoundOver(btnSoundOver); + FavoriteBtn[i]->SetSoundClick(btnSoundClick2); + FavoriteBtn[i]->SetTrigger(trigA); + FavoriteBtn[i]->SetEffectGrow(); + } + + btnLeftImg = new GuiImage(imgLeft); + if (Settings.wsprompt) btnLeftImg->SetWidescreen(Settings.widescreen); + btnLeft = new GuiButton(btnLeftImg, btnLeftImg, ALIGN_LEFT, ALIGN_MIDDLE, 20, -50, trigA, btnSoundOver, btnSoundClick2, 1); + btnLeft->SetTrigger(trigL); + btnLeft->SetTrigger(trigMinus); + + btnRightImg = new GuiImage(imgRight); + if (Settings.wsprompt) btnRightImg->SetWidescreen(Settings.widescreen); + btnRight = new GuiButton(btnRightImg, btnRightImg, ALIGN_RIGHT, ALIGN_MIDDLE, -20, -50, trigA, btnSoundOver, btnSoundClick2, 1); + btnRight->SetTrigger(trigR); + btnRight->SetTrigger(trigPlus); + + if (Settings.ShowPlayCount) + Append(playcntTxt); + Append(backBtn); + + if (!dvdheader) //stuff we don't show if it is a DVD mounted + { + Append(btnLeft); + Append(btnRight); + } + + bannerFrame.SetButtonBText(tr("Start")); + + //check if unlocked + if (Settings.godmode || !(Settings.ParentalBlocks & BLOCK_GAME_SETTINGS)) + { + bannerFrame.SetButtonAText(tr("Settings")); + Append(settingsBtn); + if(Settings.bannerFavIcon != BANNER_FAVICON_OFF) + for(int i = 0; i < FAVORITE_STARS; ++i) + Append(FavoriteBtn[i]); + } + else + { + bannerFrame.SetButtonAText(tr("Back")); + backBtn->SetPosition(-120, 175); + } + + Append(startBtn); //! Appending the disc on top of all + + ChangeGame(false); +} + +BannerWindow::~BannerWindow() +{ + if(parentElement) + ((GuiWindow * ) parentElement)->Remove(this); + + RemoveAll(); + + delete trigA; + delete trigB; + delete trigL; + delete trigR; + delete trigPlus; + delete trigMinus; + + delete imgFavorite; + delete imgNotFavorite; + delete imgLeft; + delete imgRight; + + delete btnLeftImg; + delete btnRightImg; + + delete playcntTxt; + + delete startBtn; + delete backBtn; + delete settingsBtn; + delete btnLeft; + delete btnRight; + + for(int i = 0; i < FAVORITE_STARS; ++i) + { + delete FavoriteBtnImg[i]; + delete FavoriteBtn[i]; + } + + if(gameSound) gameSound->Stop(); + delete gameSound; + bgMusic->SetVolume(Settings.volume); + + delete gameBanner; + + memcpy(&FSProjection2D, &originalProjection, sizeof(Mtx44)); + ResumeGui(); +} + +void BannerWindow::ChangeGame(bool playsound) +{ + struct discHdr * header = (dvdheader ? dvdheader : gameList[gameSelected]); + + //! Stop thread because all the extract functions are not thread safe + //! Let it finish the current loading though + BannerAsync::HaltThread(); + + Banner *newBanner = NULL; + // continue playing sound during loading process + if((header->type == TYPE_GAME_GC_IMG) || (header->type == TYPE_GAME_GC_DISC) || (header->type == TYPE_GAME_GC_EXTRACTED)) + { + //! try cache file first and if that fails create the default one + if(BNRInstance::Instance()->Load(header) && BNRInstance::Instance()->Get() != NULL) + newBanner = new Banner; + else + newBanner = BNRInstance::Instance()->CreateGCBanner(header); + } + else { + BNRInstance::Instance()->Load(header); + newBanner = new Banner; + } + + //! remove game sound + if (gameSound) + { + gameSound->Stop(); + delete gameSound; + gameSound = NULL; + } + + playcntTxt->SetTextf("%s: %i", tr( "Play Count" ), GameStatistics.GetPlayCount(header)); + + HaltGui(); + + // set the new banner + delete gameBanner; + gameBanner = newBanner; + + // Do not load stuff on game cube games + if(BNRInstance::Instance()->Get() != NULL) + gameBanner->LoadBanner(BNRInstance::Instance()->Get(), BNRInstance::Instance()->GetSize()); + + if (Settings.gamesoundvolume != 0) + { + if( (BNRInstance::Instance()->Get() != NULL) + && gameBanner->LoadSound(BNRInstance::Instance()->Get(), BNRInstance::Instance()->GetSize()) + && gameBanner->getSound()) + { + gameSound = new GuiSound(gameBanner->getSound(), gameBanner->getSoundSize(), Settings.gamesoundvolume); + } + else if((header->type == TYPE_GAME_GC_IMG) || (header->type == TYPE_GAME_GC_DISC) || (header->type == TYPE_GAME_GC_EXTRACTED)) + { + //! on game cube load the default sound + gameSound = new GuiSound(Resources::GetFile("gc_banner.ogg"), Resources::GetFileSize("gc_banner.ogg"), Settings.gamesoundvolume); + } + if(gameSound) + { + bgMusic->SetVolume(0); + if (Settings.gamesound == 2) + gameSound->SetLoop(1); + // If the game is changed within window play sound here directly + if(playsound) + gameSound->Play(); + } + } + + int favoritevar = GameStatistics.GetFavoriteRank(header->id); + for(int i = 0; i < FAVORITE_STARS; ++i) + FavoriteBtnImg[i]->SetImage(favoritevar >= i+1 ? imgFavorite : imgNotFavorite); + + //! Resume all threads + BannerAsync::ResumeThread(); + ResumeGui(); +} + +int BannerWindow::Run() +{ + int choice = -1; + + while(choice == -1) + { + usleep(50000); + + if (shutdown) //for power button + Sys_Shutdown(); + else if (reset) //for reset button + Sys_Reboot(); + + choice = MainLoop(); + } + + return choice; +} + +int BannerWindow::MainLoop() +{ + if (startBtn->GetState() == STATE_CLICKED) + { + // If this function was left then the game start was canceled + GameWindow::BootGame(dvdheader ? dvdheader : gameList[gameSelected]); + // If it returns from that function reload the list + gameList.FilterList(); + startBtn->ResetState(); + } + + else if (backBtn->GetState() == STATE_CLICKED) //back + { + GuiBannerGrid *bannerBrowser = dynamic_cast(browserMenu->GetGameBrowser()); + if(bannerBrowser) + { + bannerBrowser->GetIconCoordinates(gameSelected, &AnimPosX, &AnimPosY); + bannerBrowser->SetPage(gameSelected / 12); + } + // activate rendering again + browserMenu->GetGameBrowser()->SetVisible(true); + + // finish on going animations first + while(AnimStep < MaxAnimSteps) + usleep(1000); + + // set new animation for zoom out + AnimZoomIn = false; + AnimStep = 0; + + // finish animation + while(AnimStep < MaxAnimSteps) + usleep(1000); + + mainWindow->SetState(STATE_DEFAULT); + returnVal = 0; + } + + else if(settingsBtn->GetState() == STATE_CLICKED) //settings + { + this->SetState(STATE_DISABLED); + + wiilight(0); + int settret = GameSettingsMenu::Execute(browserMenu, dvdheader ? dvdheader : gameList[gameSelected]); + + this->SetState(STATE_DEFAULT); + settingsBtn->ResetState(); + + // Show the window again or return to browser on uninstall + if (settret == MENU_DISCLIST) + returnVal = 1; + } + + else if (btnRight->GetState() == STATE_CLICKED) //next game + { + if(Settings.xflip == XFLIP_YES) + { + gameSelected = (gameSelected - 1 + gameList.size()) % gameList.size(); + ChangeGame(true); + } + else if(Settings.xflip == XFLIP_SYSMENU) + { + gameSelected = (gameSelected + 1) % gameList.size(); + ChangeGame(true); + } + else if(Settings.xflip == XFLIP_WTF) + { + gameSelected = (gameSelected - 1 + gameList.size()) % gameList.size(); + ChangeGame(true); + } + else + { + gameSelected = (gameSelected + 1) % gameList.size(); + ChangeGame(true); + } + + btnRight->ResetState(); + } + + else if (btnLeft->GetState() == STATE_CLICKED) //previous game + { + if(Settings.xflip == XFLIP_YES) + { + gameSelected = (gameSelected + 1) % gameList.size(); + ChangeGame(true); + } + else if(Settings.xflip == XFLIP_SYSMENU) + { + gameSelected = (gameSelected - 1 + gameList.size()) % gameList.size(); + ChangeGame(true); + } + else if(Settings.xflip == XFLIP_WTF) + { + gameSelected = (gameSelected + 1) % gameList.size(); + ChangeGame(true); + } + else + { + gameSelected = (gameSelected - 1 + gameList.size()) % gameList.size(); + ChangeGame(true); + } + + btnLeft->ResetState(); + } + + if (reducedVol) + { + if (gameSound) + { + if (Settings.gamesound == 1 && !gameSound->IsPlaying()) + { + bgMusic->SetVolume(Settings.volume); + reducedVol = false; + } + } + else + { + bgMusic->SetVolume(Settings.volume); + reducedVol = false; + } + } + + for(int i = 0; i < FAVORITE_STARS; ++i) + { + if(FavoriteBtn[i]->GetState() == STATE_CLICKED) + { + // This button can only be clicked when this is not a dvd header + struct discHdr * header = gameList[gameSelected]; + int FavoriteRank = (i+1 == GameStatistics.GetFavoriteRank(header->id)) ? 0 : i+1; // Press the current rank to reset the rank + + GameStatistics.SetFavoriteRank(header->id, FavoriteRank); + GameStatistics.Save(); + for(int j = 0; j < FAVORITE_STARS; ++j) + FavoriteBtnImg[j]->SetImage(FavoriteRank >= j+1 ? imgFavorite : imgNotFavorite); + + FavoriteBtn[i]->ResetState(); + } + } + + return returnVal; +} + +void BannerWindow::Animate(void) +{ + // animation is on going + if(AnimStep < MaxAnimSteps) + { + AnimationRunning = true; + AnimStep++; + + // zoom in animation + if(AnimZoomIn) { + BGAlpha = std::min(255.f * AnimStep * 2.f / MaxAnimSteps, 255.f); + if(AnimStep < 0.4f * MaxAnimSteps) + BannerAlpha = 0; + else + BannerAlpha = std::min(255.f * (AnimStep - 0.4f * MaxAnimSteps) / (0.6f * MaxAnimSteps), 255.f); + } + // zoom out animation + else { + BGAlpha = std::min(255.f * (MaxAnimSteps-AnimStep) * 2.f / MaxAnimSteps, 255.f); + if((MaxAnimSteps - AnimStep) < 0.4f * MaxAnimSteps) + BannerAlpha = 0; + else + BannerAlpha = std::min(255.f * ((MaxAnimSteps - AnimStep) - 0.4f * MaxAnimSteps) / (0.6f * MaxAnimSteps), 255.f); + } + + float curAnimStep = AnimZoomIn ? ((float)(MaxAnimSteps - AnimStep)/(float)MaxAnimSteps) : ((float)AnimStep/(float)MaxAnimSteps); + + float stepx1 = Settings.AdjustOverscanX - AnimPosX; + float stepy1 = Settings.AdjustOverscanY - AnimPosY; + float stepx2 = (screenwidth - 1 - Settings.AdjustOverscanX) - (AnimPosX + fIconWidth); + float stepy2 = (screenheight - 1 - Settings.AdjustOverscanY) - (AnimPosY + fIconHeight); + + float top = AnimPosY + stepy1 * curAnimStep; + float bottom = AnimPosY + fIconHeight + stepy2 * curAnimStep; + float left = AnimPosX + stepx1 * curAnimStep; + float right = AnimPosX + fIconWidth + stepx2 * curAnimStep; + + // set main projection of all GUI stuff if we are using the banner browser + if(dynamic_cast(browserMenu->GetGameBrowser()) != NULL) + guOrtho(FSProjection2D, top, bottom, left, right, 0, 10000); + + float xDiff = 0.5f * Settings.BannerProjectionWidth; + float yDiff = 0.5f * Settings.BannerProjectionHeight; + + // this just looks better for banner/icon ratio + float iconWidth = fIconWidth - 20; + float iconHeight = fIconHeight - 20; + + f32 ratioX = xDiff * 2.f / iconWidth; + f32 ratioY = yDiff * 2.f / iconHeight; + stepx1 = ((ScreenProps.x * 0.5f - xDiff) - (AnimPosX + 0.5f * fIconWidth - 0.5f * iconWidth)) * ratioX; + stepx2 = ((ScreenProps.x * 0.5f + xDiff) - (AnimPosX + 0.5f * fIconWidth + 0.5f * iconWidth)) * ratioX; + stepy1 = ((ScreenProps.y * 0.5f - yDiff) - (AnimPosY + 0.5f * fIconHeight - 0.5f * iconHeight)) * ratioY; + stepy2 = ((ScreenProps.y * 0.5f + yDiff) - (AnimPosY + 0.5f * fIconHeight + 0.5f * iconHeight)) * ratioY; + + //! This works good for banners + top = (ScreenProps.y * 0.5f - yDiff) + stepy1 * curAnimStep; + bottom = (ScreenProps.y * 0.5f + yDiff) + stepy2 * curAnimStep; + left = (ScreenProps.x * 0.5f - xDiff) + stepx1 * curAnimStep; + right = (ScreenProps.x * 0.5f + xDiff) + stepx2 * curAnimStep; + + // set banner projection + guOrtho(projection,top, bottom, left, right,-100,10000); + } + // last animation step + else if(AnimationRunning) + { + // set back original projection and stop animation/render of the browser (save some CPU ;P) + memcpy(&FSProjection2D, &originalProjection, sizeof(Mtx44)); + browserMenu->GetGameBrowser()->SetVisible(false); + AnimationRunning = false; + } +} + +void BannerWindow::Draw(void) +{ + bool btnAGrow = (settingsBtn->GetState() == STATE_SELECTED || backBtn->GetState() == STATE_SELECTED); + bannerFrame.SetButtonAGrow(btnAGrow); + bannerFrame.SetButtonBGrow(startBtn->GetState() == STATE_SELECTED); + + //! Start playing banner sound after last animation frame if animation after zoom is enabled + //! or on first frame if during zoom is enable + if( AnimZoomIn && gameSound && (((Settings.BannerAnimStart == BANNER_START_ON_ZOOM) && AnimStep == 0) + || ((Settings.BannerAnimStart == BANNER_START_AFTER_ZOOM) && ((AnimStep + 1) == MaxAnimSteps)))) + { + reducedVol = true; + gameSound->Play(); + } + + // Run window animation + Animate(); + + // draw a black background image first + Menu_DrawRectangle(0.0f, 0.0f, ScreenProps.x, ScreenProps.y, (GXColor) {0, 0, 0, BGAlpha}, true); + + // no banner alpha means its the start of the animation + if(BannerAlpha == 0) + return; + + // cut the unneeded crap + Mtx mv1, mv2, mv3; + guMtxIdentity (mv2); + guMtxIdentity (mv3); + guMtxScaleApply(modelview,mv1, 1.f, -1.f, 1.f); + guMtxTransApply(mv1,mv1, 0.5f * ScreenProps.x, 0.5f * ScreenProps.y, 0.f); + guMtxTransApply(mv2,mv2, -0.5f * fBannerWidth, 0.5f * fBannerHeight, 0.f); + guMtxTransApply(mv3,mv3, 0.5f * fBannerWidth, -0.5f * fBannerHeight, 0.f); + guMtxConcat (mv1, mv2, mv2); + guMtxConcat (mv1, mv3, mv3); + + f32 viewportv[6]; + f32 projectionv[7]; + + GX_GetViewportv(viewportv, vmode); + GX_GetProjectionv(projectionv, projection, GX_ORTHOGRAPHIC); + + guVector vecTL; + guVector vecBR; + GX_Project(0.0f, 0.0f, 0.0f, mv2, projectionv, viewportv, &vecTL.x, &vecTL.y, &vecTL.z); + GX_Project(0.0f, 0.0f, 0.0f, mv3, projectionv, viewportv, &vecBR.x, &vecBR.y, &vecBR.z); + + // round up scissor box offset and round down the size + u32 scissorX = (u32)(0.5f + std::max(vecTL.x, 0.0f)); + u32 scissorY = (u32)(0.5f + std::max(vecTL.y, 0.0f)); + u32 scissorW = (u32)std::max(vecBR.x - vecTL.x, 0.0f); + u32 scissorH = (u32)std::max(vecBR.y - vecTL.y, 0.0f); + + GX_SetScissor( scissorX, scissorY, scissorW, scissorH ); + + // load projection matrix + GX_LoadProjectionMtx(projection, GX_ORTHOGRAPHIC); + + if(gameBanner->getBanner()) + { + gameBanner->getBanner()->Render(modelview, ScreenProps, Settings.widescreen, BannerAlpha); + + // advance only when animation isnt running on certain options + if(Settings.BannerAnimStart != BANNER_START_AFTER_ZOOM || !AnimationRunning) + { + gameBanner->getBanner()->AdvanceFrame(); + + // skip every 6th frame on PAL50 since all banners are 60 Hz + if(Settings.PAL50 && (frameCount % 6 == 0)) { + gameBanner->getBanner()->AdvanceFrame(); + } + } + } + + // render big frame and animate button over effects + bannerFrame.Render(modelview, ScreenProps, Settings.widescreen, BannerAlpha); + bannerFrame.AdvanceFrame(); + + // Setup GX + ReSetup_GX(); + + if(AnimationRunning) { + // remove scissors again as we draw the background layout too + GX_SetScissor(0, 0, vmode->fbWidth, vmode->efbHeight); + + // only render gui stuff when animation is done + return; + } + + GuiWindow::Draw(); +} diff --git a/source/prompts/BannerWindow.hpp b/source/prompts/BannerWindow.hpp new file mode 100644 index 0000000..ba77bd3 --- /dev/null +++ b/source/prompts/BannerWindow.hpp @@ -0,0 +1,103 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 BANNERWINDOW_HPP_ +#define BANNERWINDOW_HPP_ + +#include "GUI/gui.h" +#include "GUI/gui_diskcover.h" +#include "menu/GameBrowseMenu.hpp" +#include "usbloader/disc.h" +#include "SystemMenu/SystemMenuResources.h" +#include "banner/Banner.h" + +#define FAVORITE_STARS 5 + +class BannerWindow : public GuiWindow +{ + public: + BannerWindow(GameBrowseMenu *m, struct discHdr *header); + virtual ~BannerWindow(); + int Run(); + int GetSelectedGame() { return gameSelected; } + void Draw(void); + void Test(); + protected: + int MainLoop(); + void Animate(void); + void ChangeGame(bool playsound); + + static constexpr float fBannerWidth = 608.f; + static constexpr float fBannerHeight = 448.f; + static constexpr float fIconWidth = 128.f; + static constexpr float fIconHeight = 96.f; + + static BannerFrame bannerFrame; + + bool reducedVol; + int returnVal; + int gameSelected; + GameBrowseMenu *browserMenu; + struct discHdr *dvdheader; + + const int MaxAnimSteps; + + int AnimStep; + float AnimPosX, AnimPosY; + float fAnimScale; + bool AnimZoomIn; + bool AnimationRunning; + bool oldAnimationRunning; + + u8 BGAlpha; + u8 BannerAlpha; + + Mtx modelview; + Mtx44 projection; + Mtx44 originalProjection; + Vec2f ScreenProps; + + Banner *gameBanner; + + GuiTrigger * trigA; + GuiTrigger * trigB; + GuiTrigger * trigL; + GuiTrigger * trigR; + GuiTrigger * trigPlus; + GuiTrigger * trigMinus; + + GuiImageData * imgFavorite; + GuiImageData * imgNotFavorite; + GuiImageData * imgLeft; + GuiImageData * imgRight; + + GuiImage * btnLeftImg; + GuiImage * btnRightImg; + GuiImage * FavoriteBtnImg[FAVORITE_STARS]; + + GuiText * playcntTxt; + + GuiButton * startBtn; + GuiButton * backBtn; + GuiButton * settingsBtn; + GuiButton * btnLeft; + GuiButton * btnRight; + GuiButton * FavoriteBtn[FAVORITE_STARS]; + + GuiSound * gameSound; +}; + +#endif diff --git a/source/prompts/CategoryPrompt.cpp b/source/prompts/CategoryPrompt.cpp new file mode 100644 index 0000000..77418d6 --- /dev/null +++ b/source/prompts/CategoryPrompt.cpp @@ -0,0 +1,325 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "CategoryPrompt.hpp" +#include "settings/CGameCategories.hpp" +#include "settings/CSettings.h" +#include "language/gettext.h" +#include "themes/gettheme.h" +#include "themes/Resources.h" +#include "menu/menus.h" + +CategoryPrompt::CategoryPrompt(const string &title) + : GuiWindow(0, 0) +{ + changed = false; + + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigB.SetSimpleTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + trigHome.SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, PAD_BUTTON_START); + trigPlus.SetButtonOnlyTrigger(-1, WPAD_BUTTON_PLUS | WPAD_CLASSIC_BUTTON_PLUS, PAD_TRIGGER_R); + trigMinus.SetButtonOnlyTrigger(-1, WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, PAD_TRIGGER_L); + trig1.SetButtonOnlyTrigger(-1, WPAD_BUTTON_1 | WPAD_CLASSIC_BUTTON_Y, PAD_TRIGGER_Z); + + btnOutline = Resources::GetImageData("button_dialogue_box.png"); + bgImgData = Resources::GetImageData("categoryPrompt.png"); + browserImgData = Resources::GetImageData("bg_options.png"); + addImgData = Resources::GetImageData("add.png"); + deleteImgData = Resources::GetImageData("remove.png"); + editImgData = Resources::GetImageData("one.png"); + + bgImg = new GuiImage(bgImgData); + Append(bgImg); + + width = bgImg->GetWidth(); + height = bgImg->GetHeight()+btnOutline->GetHeight()*0.9f; + + titleTxt = new GuiText(title.c_str(), 30, thColor("r=0 g=0 b=0 a=255 - category prompt title text color")); + titleTxt->SetAlignment(thAlign("center - category prompt title text align hor"), thAlign("top - category prompt title text align ver")); + titleTxt->SetPosition(thInt("0 - category prompt title text pos x"), thInt("10 - category prompt title text pos y")); + Append(titleTxt); + + browserImg = new GuiImage(browserImgData); + browser = new GuiCheckboxBrowser(browserImg->GetWidth(), browserImg->GetHeight()); + browser->SetImage(browserImg); + browser->SetAlignment(thAlign("center - category prompt browser align hor"), thAlign("top - category prompt browser align ver")); + browser->SetPosition(thInt("0 - category prompt browser pos x"), thInt("45 - category prompt browser pos y")); + Append(browser); + + homeButton = new GuiButton(0, 0); + homeButton->SetTrigger(&trigHome); + Append(homeButton); + + addImg = new GuiImage(addImgData); + addTxt = new GuiText(tr("Add category"), 24, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + addTxt->SetMaxWidth(180, DOTTED); + addTxt->SetAlignment(thAlign("left - category prompt add button text align hor"), thAlign("top - category prompt add button text align ver")); + addTxt->SetPosition(thInt("10 - category prompt add button text pos x")+addImg->GetWidth(), thInt("6 - category prompt add button text pos y")); + + addButton = new GuiButton(addImg->GetWidth()+10+addTxt->GetTextWidth(), addImg->GetHeight()); + addButton->SetImage(addImg); + addButton->SetLabel(addTxt); + addButton->SetAlignment(thAlign("left - category prompt add button align hor"), thAlign("top - category prompt add button align ver")); + addButton->SetPosition(width/2-thInt("180 - category prompt add button pos x")-addImg->GetWidth()/2, thInt("330 - category prompt add button pos y")); + addButton->SetSoundOver(btnSoundOver); + addButton->SetSoundClick(btnSoundClick); + addButton->SetTrigger(&trigA); + addButton->SetTrigger(&trigPlus); + addButton->SetEffectGrow(); + Append(addButton); + + deleteImg = new GuiImage(deleteImgData); + deleteTxt = new GuiText(tr("Delete category"), 24, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + deleteTxt->SetMaxWidth(180, DOTTED); + deleteTxt->SetAlignment(thAlign("left - category prompt delete button text align hor"), thAlign("top - category prompt delete button text align ver")); + deleteTxt->SetPosition(thInt("10 - category prompt delete button text pos x")+deleteImg->GetWidth(), thInt("6 - category prompt delete button text pos y")); + + deleteButton = new GuiButton(deleteImg->GetWidth()+10+deleteTxt->GetTextWidth(), deleteImg->GetHeight()); + deleteButton->SetImage(deleteImg); + deleteButton->SetLabel(deleteTxt); + deleteButton->SetAlignment(thAlign("left - category prompt delete button align hor"), thAlign("top - category prompt delete button align ver")); + deleteButton->SetPosition(width/2+thInt("5 - category prompt delete button pos x"), thInt("330 - category prompt delete button pos y")); + deleteButton->SetSoundOver(btnSoundOver); + deleteButton->SetSoundClick(btnSoundClick); + deleteButton->SetTrigger(&trigA); + deleteButton->SetTrigger(&trigMinus); + deleteButton->SetEffectGrow(); + Append(deleteButton); + + editImg = new GuiImage(editImgData); + editTxt = new GuiText(tr("Rename category"), 24, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + editTxt->SetAlignment(thAlign("left - category prompt edit button text align hor"), thAlign("top - category prompt edit button text align ver")); + editTxt->SetPosition(thInt("10 - category prompt edit button text pos x")+editImg->GetWidth(), thInt("6 - category prompt edit button text pos y")); + editTxt->SetMaxWidth(180, DOTTED); + + editButton = new GuiButton(editImg->GetWidth()+10+editTxt->GetTextWidth(), editImg->GetHeight()); + editButton->SetImage(editImg); + editButton->SetLabel(editTxt); + editButton->SetAlignment(thAlign("left - category prompt edit button align hor"), thAlign("top - category prompt edit button align ver")); + editButton->SetPosition(width/2-thInt("180 - category prompt edit button pos x")-addImg->GetWidth()/2, thInt("362 - category prompt edit button pos y")); + editButton->SetSoundOver(btnSoundOver); + editButton->SetSoundClick(btnSoundClick); + editButton->SetTrigger(&trigA); + editButton->SetTrigger(&trig1); + editButton->SetEffectGrow(); + Append(editButton); + + saveImg = new GuiImage(btnOutline); + saveImg->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + saveImg->SetScale(0.9f); + saveTxt = new GuiText(tr("Save"), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + saveButton = new GuiButton(saveImg->GetWidth()*0.9f, saveImg->GetHeight()*0.9f); + saveButton->SetImage(saveImg); + saveButton->SetLabel(saveTxt); + saveButton->SetAlignment(thAlign("center - category prompt save button align hor"), thAlign("bottom - category prompt save button align ver")); + saveButton->SetPosition(thInt("-110 - category prompt save button pos x"), thInt("0 - category prompt save button pos y")); + saveButton->SetSoundOver(btnSoundOver); + saveButton->SetSoundClick(btnSoundClick); + saveButton->SetTrigger(&trigA); + saveButton->SetEffectGrow(); + Append(saveButton); + + backImg = new GuiImage(btnOutline); + backImg->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + backImg->SetScale(0.9f); + backTxt = new GuiText(tr("Back"), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + backBtn = new GuiButton(backImg->GetWidth()*0.9f, backImg->GetHeight()*0.9f); + backBtn->SetImage(backImg); + backBtn->SetLabel(backTxt); + backBtn->SetAlignment(thAlign("center - category prompt back button align hor"), thAlign("bottom - category prompt back button align ver")); + backBtn->SetPosition(thInt("110 - category prompt back button pos x"), thInt("0 - category prompt back button pos y")); + backBtn->SetSoundOver(btnSoundOver); + backBtn->SetSoundClick(btnSoundClick); + backBtn->SetTrigger(&trigA); + backBtn->SetEffectGrow(); + Append(backBtn); + + browserRefresh(); +} + +CategoryPrompt::~CategoryPrompt() +{ + RemoveAll(); + delete browser; + + delete btnOutline; + delete bgImgData; + delete bgImg; + delete browserImgData; + delete browserImg; + delete addImgData; + delete addImg; + delete deleteImgData; + delete deleteImg; + delete editImgData; + delete editImg; + delete backImg; + delete saveImg; + + delete backBtn; + delete homeButton; + delete addButton; + delete deleteButton; + delete editButton; + delete saveButton; + + delete titleTxt; + delete addTxt; + delete deleteTxt; + delete editTxt; + delete backTxt; + delete saveTxt; +} + +int CategoryPrompt::Show() +{ + while(backBtn->GetState() != STATE_CLICKED) + { + usleep(10000); + + if (shutdown) + Sys_Shutdown(); + else if (reset) + Sys_Reboot(); + + else if (homeButton->GetState() == STATE_CLICKED) + { + gprintf("\thomeButton clicked\n"); + WindowExitPrompt(); + mainWindow->SetState(STATE_DISABLED); + SetState(STATE_DEFAULT); + homeButton->ResetState(); + } + + else if(saveButton->GetState() == STATE_CLICKED) + { + if(categoriesChanged()) + GameCategories.Save(); + return 1; + } + + else if(addButton->GetState() == STATE_CLICKED) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_CATEGORIES_MOD)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked to be able to use this." ), tr( "OK" )); + mainWindow->SetState(STATE_DISABLED); + SetState(STATE_DEFAULT); + addButton->ResetState(); + continue; + } + + char entered[512] = ""; + + int result = OnScreenKeyboard(entered, sizeof(entered), 0); + if(result) + { + GameCategories.CategoryList.AddCategory(entered); + browserRefresh(); + markChanged(); + } + + mainWindow->SetState(STATE_DISABLED); + SetState(STATE_DEFAULT); + addButton->ResetState(); + } + + else if(deleteButton->GetState() == STATE_CLICKED) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_CATEGORIES_MOD)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked to be able to use this." ), tr( "OK" )); + mainWindow->SetState(STATE_DISABLED); + SetState(STATE_DEFAULT); + deleteButton->ResetState(); + continue; + } + + if(browser->GetSelected() == 0) + { + WindowPrompt(tr("Error"), tr("You cannot delete this category."), tr("OK")); + mainWindow->SetState(STATE_DISABLED); + SetState(STATE_DEFAULT); + deleteButton->ResetState(); + continue; + } + + int choice = WindowPrompt(tr("Warning"), tr("Are you sure you want to delete this category?"), tr("Yes"), tr("Cancel")); + if(choice) + { + GameCategories.CategoryList.goToFirst(); + for(int i = 0; i < browser->GetSelected(); ++i) + GameCategories.CategoryList.goToNext(); + int categoryID = GameCategories.CategoryList.getCurrentID(); + GameCategories.CategoryList.RemoveCategory(categoryID); + GameCategories.RemoveCategory(categoryID); + + browserRefresh(); + markChanged(); + } + + mainWindow->SetState(STATE_DISABLED); + SetState(STATE_DEFAULT); + deleteButton->ResetState(); + } + + else if(editButton->GetState() == STATE_CLICKED) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_CATEGORIES_MOD)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked to be able to use this." ), tr( "OK" )); + mainWindow->SetState(STATE_DISABLED); + SetState(STATE_DEFAULT); + continue; + } + + GameCategories.CategoryList.goToFirst(); + for(int i = 0; i < browser->GetSelected(); ++i) + GameCategories.CategoryList.goToNext(); + + char entered[512]; + snprintf(entered, sizeof(entered), tr(GameCategories.CategoryList.getCurrentName().c_str())); + + int result = OnScreenKeyboard(entered, sizeof(entered), 0); + if(result) + { + GameCategories.CategoryList.SetCategory(GameCategories.CategoryList.getCurrentID(), entered); + browserRefresh(); + markChanged(); + } + + mainWindow->SetState(STATE_DISABLED); + SetState(STATE_DEFAULT); + editButton->ResetState(); + } + } + + //! Reset to old file in case of cancel + if(categoriesChanged()) + resetChanges(); + + return 0; +} + + diff --git a/source/prompts/CategoryPrompt.hpp b/source/prompts/CategoryPrompt.hpp new file mode 100644 index 0000000..05f7de8 --- /dev/null +++ b/source/prompts/CategoryPrompt.hpp @@ -0,0 +1,81 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef CATEGORY_PROMPT_HPP_ +#define CATEGORY_PROMPT_HPP_ + +#include "GUI/gui_checkboxbrowser.hpp" + +class CategoryPrompt : public GuiWindow, public sigslot::has_slots<> +{ + public: + CategoryPrompt(const string &title); + virtual ~CategoryPrompt(); + int Show(); + bool categoriesChanged() const { return changed; } + protected: + void markChanged() { changed = true; } + sigslot::signal0<> browserRefresh; + sigslot::signal0<> resetChanges; + GuiCheckboxBrowser *browser; + private: + bool changed; + + GuiImageData *bgImgData; + GuiImageData *browserImgData; + GuiImageData *btnOutline; + GuiImageData *addImgData; + GuiImageData *deleteImgData; + GuiImageData *editImgData; + + GuiImage *browserImg; + GuiImage *bgImg; + GuiImage *addImg; + GuiImage *deleteImg; + GuiImage *editImg; + GuiImage *backImg; + GuiImage *saveImg; + + GuiButton *backBtn; + GuiButton *homeButton; + GuiButton *addButton; + GuiButton *deleteButton; + GuiButton *editButton; + GuiButton *saveButton; + + GuiText *titleTxt; + GuiText *addTxt; + GuiText *deleteTxt; + GuiText *editTxt; + GuiText *backTxt; + GuiText *saveTxt; + + GuiTrigger trigA; + GuiTrigger trigB; + GuiTrigger trigHome; + GuiTrigger trigPlus; + GuiTrigger trigMinus; + GuiTrigger trig1; +}; + +#endif diff --git a/source/prompts/CategorySelectPrompt.cpp b/source/prompts/CategorySelectPrompt.cpp new file mode 100644 index 0000000..fb8a205 --- /dev/null +++ b/source/prompts/CategorySelectPrompt.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "CategorySelectPrompt.hpp" +#include "settings/CGameCategories.hpp" +#include "settings/CSettings.h" +#include "language/gettext.h" +#include "utils/StringTools.h" +#include "gecko.h" + +CategorySelectPrompt::CategorySelectPrompt(struct discHdr * header) + : CategoryPrompt(fmt("%s - %s", (char *) header->id, tr("Categories"))), + gameHeader(header) +{ + browser->checkBoxClicked.connect(this, &CategorySelectPrompt::OnCheckboxClick); + browserRefresh.connect(this, &CategorySelectPrompt::onBrowserRefresh); + resetChanges.connect(this, &CategorySelectPrompt::onResetChanges); + + browserRefresh(); +} + +void CategorySelectPrompt::onResetChanges() +{ + GameCategories.Load(Settings.ConfigPath); +} + +void CategorySelectPrompt::onBrowserRefresh() +{ + browser->Clear(); + GameCategories.CategoryList.goToFirst(); + do + { + bool checked = false; + const vector gameCat = GameCategories[gameHeader->id]; + + for(u32 i = 0; i < gameCat.size(); ++i) + { + if(gameCat[i] == GameCategories.CategoryList.getCurrentID()) + { + checked = true; + break; + } + } + + browser->AddEntrie(tr(GameCategories.CategoryList.getCurrentName().c_str()), checked); + } + while(GameCategories.CategoryList.goToNext()); + + GameCategories.CategoryList.goToFirst(); + browser->RefreshList(); +} + +void CategorySelectPrompt::OnCheckboxClick(GuiCheckbox *checkBox, int index) +{ + GameCategories.CategoryList.goToFirst(); + for(int i = 0; i < index; ++i) + GameCategories.CategoryList.goToNext(); + + if(GameCategories.CategoryList.getCurrentID() == 0) + { + checkBox->SetChecked(true); + return; + } + + const vector gameCat = GameCategories[gameHeader->id]; + + u32 i; + for(i = 0; i < gameCat.size(); ++i) + { + if(gameCat[i] == GameCategories.CategoryList.getCurrentID()) + { + if(!checkBox->IsChecked()) + { + GameCategories.RemoveCategory((const char *) gameHeader->id, gameCat[i]); + markChanged(); + } + break; + } + } + + if(i == gameCat.size() && checkBox->IsChecked()) + { + GameCategories.SetCategory(gameHeader->id, GameCategories.CategoryList.getCurrentID()); + markChanged(); + } +} diff --git a/source/prompts/CategorySelectPrompt.hpp b/source/prompts/CategorySelectPrompt.hpp new file mode 100644 index 0000000..8cab4f9 --- /dev/null +++ b/source/prompts/CategorySelectPrompt.hpp @@ -0,0 +1,42 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef CATEGORYSELECT_PROMPT_HPP_ +#define CATEGORYSELECT_PROMPT_HPP_ + +#include "CategoryPrompt.hpp" +#include "usbloader/disc.h" + +class CategorySelectPrompt : public CategoryPrompt +{ + public: + CategorySelectPrompt(struct discHdr * header); + private: + void OnCheckboxClick(GuiCheckbox *checkBox, int index); + void onBrowserRefresh(); + void onResetChanges(); + + struct discHdr * gameHeader; +}; + +#endif diff --git a/source/prompts/CategorySwitchPrompt.cpp b/source/prompts/CategorySwitchPrompt.cpp new file mode 100644 index 0000000..eae679a --- /dev/null +++ b/source/prompts/CategorySwitchPrompt.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "CategorySwitchPrompt.hpp" +#include "settings/CGameCategories.hpp" +#include "settings/CSettings.h" +#include "language/gettext.h" + +CategorySwitchPrompt::CategorySwitchPrompt() + : CategoryPrompt(tr("Show Categories")), oldSettingEnabled(Settings.EnabledCategories), + oldSettingRequired(Settings.RequiredCategories), oldSettingForbidden(Settings.ForbiddenCategories) +{ + browser->checkBoxClicked.connect(this, &CategorySwitchPrompt::OnCheckboxClick); + browserRefresh.connect(this, &CategorySwitchPrompt::onBrowserRefresh); + resetChanges.connect(this, &CategorySwitchPrompt::onResetChanges); + + browserRefresh(); +} + +void CategorySwitchPrompt::onResetChanges() +{ + Settings.EnabledCategories = oldSettingEnabled; + Settings.RequiredCategories = oldSettingRequired; + Settings.ForbiddenCategories = oldSettingForbidden; + GameCategories.Load(Settings.ConfigPath); +} + +void CategorySwitchPrompt::onBrowserRefresh() +{ + browser->Clear(); + GameCategories.CategoryList.goToFirst(); + do + { + bool checked = false; + int style = GuiCheckbox::CHECKSIGN; + + // Verify the Enabled Categories [v] + for(u32 i = 0; i < Settings.EnabledCategories.size(); ++i) + { + if(Settings.EnabledCategories[i] == GameCategories.CategoryList.getCurrentID()) + { + checked = true; + break; + } + } + + // Verify the Forbidden Categories [X] + if(!checked) + { + for(u32 i = 0; i < Settings.ForbiddenCategories.size(); ++i) + { + if(Settings.ForbiddenCategories[i] == GameCategories.CategoryList.getCurrentID()) + { + checked = true; + style = GuiCheckbox::CROSS; + break; + } + } + } + + // Verify the Required Categories [+] + if(!checked) + { + for(u32 i = 0; i < Settings.RequiredCategories.size(); ++i) + { + if(Settings.RequiredCategories[i] == GameCategories.CategoryList.getCurrentID()) + { + checked = true; + style = GuiCheckbox::PLUS; + break; + } + } + } + + browser->AddEntrie(tr(GameCategories.CategoryList.getCurrentName().c_str()), checked, style, true); + } + while(GameCategories.CategoryList.goToNext()); + + GameCategories.CategoryList.goToFirst(); + browser->RefreshList(); +} + +void CategorySwitchPrompt::OnCheckboxClick(GuiCheckbox *checkBox, int index) +{ + GameCategories.CategoryList.goToFirst(); + for(int i = 0; i < index; ++i) + GameCategories.CategoryList.goToNext(); + + u32 i; + if(!checkBox->IsChecked()) + { + // Remove from Required + for(i = 0; i < Settings.RequiredCategories.size(); ++i) + { + if(Settings.RequiredCategories[i] == GameCategories.CategoryList.getCurrentID()) + { + Settings.RequiredCategories.erase(Settings.RequiredCategories.begin()+i); + markChanged(); + break; + } + } + } + else if(checkBox->GetStyle() == GuiCheckbox::CHECKSIGN) + { + // Add to Enabled + Settings.EnabledCategories.push_back(GameCategories.CategoryList.getCurrentID()); + markChanged(); + } + else if(checkBox->GetStyle() == GuiCheckbox::CROSS) + { + // Remove from Enabled + for(i = 0; i < Settings.EnabledCategories.size(); ++i) + { + if(Settings.EnabledCategories[i] == GameCategories.CategoryList.getCurrentID()) + { + Settings.EnabledCategories.erase(Settings.EnabledCategories.begin()+i); + break; + } + } + // Add to Forbidden + Settings.ForbiddenCategories.push_back(GameCategories.CategoryList.getCurrentID()); + markChanged(); + } + else if(checkBox->GetStyle() == GuiCheckbox::PLUS && index > 0) + { + // Remove from Forbidden + for(i = 0; i < Settings.ForbiddenCategories.size(); ++i) + { + if(Settings.ForbiddenCategories[i] == GameCategories.CategoryList.getCurrentID()) + { + Settings.ForbiddenCategories.erase(Settings.ForbiddenCategories.begin()+i); + break; + } + } + // Add to Required + Settings.RequiredCategories.push_back(GameCategories.CategoryList.getCurrentID()); + markChanged(); + } + + // Override Style cycling for category "All" + if(index == 0 && checkBox->GetStyle() == GuiCheckbox::PLUS) + { + checkBox->SetStyle(GuiCheckbox::CHECKSIGN); + checkBox->SetChecked(false); + for(i = 0; i < Settings.ForbiddenCategories.size(); ++i) + { + if(Settings.ForbiddenCategories[i] == GameCategories.CategoryList.getCurrentID()) + { + Settings.ForbiddenCategories.erase(Settings.ForbiddenCategories.begin()+i); + markChanged(); + break; + } + } + } +} diff --git a/source/prompts/CategorySwitchPrompt.hpp b/source/prompts/CategorySwitchPrompt.hpp new file mode 100644 index 0000000..b5ed484 --- /dev/null +++ b/source/prompts/CategorySwitchPrompt.hpp @@ -0,0 +1,43 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef CATEGORYSWITCH_PROMPT_HPP_ +#define CATEGORYSWITCH_PROMPT_HPP_ + +#include "CategoryPrompt.hpp" + +class CategorySwitchPrompt : public CategoryPrompt +{ + public: + CategorySwitchPrompt(); + private: + void OnCheckboxClick(GuiCheckbox *checkBox, int index); + void onBrowserRefresh(); + void onResetChanges(); + + const std::vector oldSettingEnabled; + const std::vector oldSettingRequired; + const std::vector oldSettingForbidden; +}; + +#endif diff --git a/source/prompts/CheckboxBrowserMenu.cpp b/source/prompts/CheckboxBrowserMenu.cpp new file mode 100644 index 0000000..66f4866 --- /dev/null +++ b/source/prompts/CheckboxBrowserMenu.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 "CheckboxBrowserMenu.h" +#include "GameCube/GCGames.h" +#include "settings/CSettings.h" +#include "settings/GameTitles.h" +#include "language/gettext.h" +#include "themes/gettheme.h" +#include "themes/Resources.h" +#include "menu/menus.h" + +CheckboxBrowserMenu::CheckboxBrowserMenu(void) + : GuiWindow(0, 0) +{ + changed = false; + + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + trigHome.SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, PAD_BUTTON_START); + + btnOutline = Resources::GetImageData("button_dialogue_box.png"); + bgImgData = Resources::GetImageData("categoryprompt.png"); + browserImgData = Resources::GetImageData("bg_options.png"); + + bgImg = new GuiImage(bgImgData); + Append(bgImg); + + width = bgImg->GetWidth(); + height = bgImg->GetHeight()+btnOutline->GetHeight()*0.9f; + + titleTxt = new GuiText("", 30, thColor("r=0 g=0 b=0 a=255 - check box browser prompt title text color")); + titleTxt->SetAlignment(thAlign("center - check box browser prompt title text align hor"), thAlign("top - check box browser prompt title text align ver")); + titleTxt->SetPosition(thInt("0 - check box browser prompt title text pos x"), thInt("10 - check box browser prompt title text pos y")); + Append(titleTxt); + + browserImg = new GuiImage(browserImgData); + browser = new GuiCheckboxBrowser(browserImg->GetWidth(), browserImg->GetHeight()); + browser->SetImage(browserImg); + browser->SetAlignment(thAlign("center - check box browser prompt browser align hor"), thAlign("top - check box browser prompt browser align ver")); + browser->SetPosition(thInt("0 - check box browser prompt browser pos x"), thInt("45 - check box browser prompt browser pos y")); + browser->checkBoxClicked.connect(this, &CheckboxBrowserMenu::OnCheckboxClick); + Append(browser); + + homeButton = new GuiButton(0, 0); + homeButton->SetTrigger(&trigHome); + Append(homeButton); + + button1Img = new GuiImage(btnOutline); + button1Img->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + button1Img->SetScale(0.9f); + button1Txt = new GuiText(tr("Install"), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + button1 = new GuiButton(button1Img->GetWidth()*0.9f, button1Img->GetHeight()*0.9f); + button1->SetImage(button1Img); + button1->SetLabel(button1Txt); + button1->SetAlignment(thAlign("center - check box browser prompt install button align hor"), thAlign("bottom - check box browser prompt install button align ver")); + button1->SetPosition(thInt("-110 - check box browser prompt install button pos x"), thInt("0 - check box browser prompt install button pos y")); + button1->SetSoundOver(btnSoundOver); + button1->SetSoundClick(btnSoundClick); + button1->SetTrigger(&trigA); + button1->SetEffectGrow(); + Append(button1); + + backImg = new GuiImage(btnOutline); + backImg->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + backImg->SetScale(0.9f); + backTxt = new GuiText(tr("Back"), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + backBtn = new GuiButton(backImg->GetWidth()*0.9f, backImg->GetHeight()*0.9f); + backBtn->SetImage(backImg); + backBtn->SetLabel(backTxt); + backBtn->SetAlignment(thAlign("center - check box browser prompt back button align hor"), thAlign("bottom - check box browser prompt back button align ver")); + backBtn->SetPosition(thInt("110 - check box browser prompt back button pos x"), thInt("0 - check box browser prompt back button pos y")); + backBtn->SetSoundOver(btnSoundOver); + backBtn->SetSoundClick(btnSoundClick); + backBtn->SetTrigger(&trigA); + backBtn->SetTrigger(&trigB); + backBtn->SetEffectGrow(); + Append(backBtn); +} + +CheckboxBrowserMenu::~CheckboxBrowserMenu() +{ + RemoveAll(); + delete browser; + + delete btnOutline; + delete bgImgData; + delete bgImg; + delete browserImgData; + delete browserImg; + delete backImg; + delete button1Img; + + delete backBtn; + delete homeButton; + delete button1; + + delete titleTxt; + delete backTxt; + delete button1Txt; +} + diff --git a/source/prompts/CheckboxBrowserMenu.h b/source/prompts/CheckboxBrowserMenu.h new file mode 100644 index 0000000..6287b99 --- /dev/null +++ b/source/prompts/CheckboxBrowserMenu.h @@ -0,0 +1,57 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 CHECKBOXBROWSERMENU_H +#define CHECKBOXBROWSERMENU_H + +#include "GUI/gui_checkboxbrowser.hpp" + +class CheckboxBrowserMenu : public GuiWindow, public sigslot::has_slots<> +{ + public: + CheckboxBrowserMenu(); + virtual ~CheckboxBrowserMenu(); + private: + void markChanged() { changed = true; } + void OnCheckboxClick(GuiCheckbox *, int) { markChanged(); } + protected: + bool changed; + + GuiCheckboxBrowser *browser; + + GuiImageData *bgImgData; + GuiImageData *browserImgData; + GuiImageData *btnOutline; + + GuiImage *browserImg; + GuiImage *bgImg; + GuiImage *backImg; + GuiImage *button1Img; + + GuiButton *backBtn; + GuiButton *homeButton; + GuiButton *button1; + + GuiText *titleTxt; + GuiText *backTxt; + GuiText *button1Txt; + + GuiTrigger trigA; + GuiTrigger trigB; + GuiTrigger trigHome; +}; + +#endif diff --git a/source/prompts/CheckboxPrompt.cpp b/source/prompts/CheckboxPrompt.cpp new file mode 100644 index 0000000..969868f --- /dev/null +++ b/source/prompts/CheckboxPrompt.cpp @@ -0,0 +1,242 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "CheckboxPrompt.hpp" +#include "themes/CTheme.h" +#include "menu/menus.h" +#include "language/gettext.h" + +CheckboxPrompt::CheckboxPrompt(const char * title, const char *msg) + : PromptWindow(title, msg) +{ + PromptWindow::AddButton(tr("OK")); + PromptWindow::AddButton(tr("Cancel")); +} + +CheckboxPrompt::~CheckboxPrompt() +{ + ResumeGui(); + + SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while(parentElement && this->GetEffect() > 0) usleep(100); + + HaltGui(); + if(parentElement) + ((GuiWindow *) parentElement)->Remove(this); + parentElement = NULL; + + RemoveAll(); + + for(u32 i = 0; i < Checkbox.size(); ++i) + { + delete CheckboxTxt[i]; + delete Checkbox[i]; + } + +} + +void CheckboxPrompt::OnCheckBoxClick(GuiButton *sender, int chan, const POINT &pointer) +{ + sender->ResetState(); +} + +void CheckboxPrompt::AddCheckBox(const char *text) +{ + int size = Checkbox.size(); + if(size > 5) + return; + + CheckboxTxt.resize(size+1); + Checkbox.resize(size+1); + + CheckboxTxt[size] = new GuiText(text, 20, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + CheckboxTxt[size]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + CheckboxTxt[size]->SetPosition(30, 0); + + Checkbox[size] = new GuiCheckbox(24, 24); + Checkbox[size]->SetLabel(CheckboxTxt[size]); + Checkbox[size]->SetSoundClick(btnSoundClick); + Checkbox[size]->SetSoundOver(btnSoundOver); + Checkbox[size]->SetTrigger(trigA); + Checkbox[size]->Clicked.connect(this, &CheckboxPrompt::OnCheckBoxClick); + Append(Checkbox[size]); + + if (Settings.wsprompt && Settings.widescreen) + { + if(size == 0) + { + Checkbox[size]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(80, -190); + } + else if(size == 1) + { + Checkbox[size]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(80, -150); + } + else if(size == 2) + { + Checkbox[size]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(80, -110); + } + else if(size == 3) + { + Checkbox[size]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(-210, -190); + } + else if(size == 4) + { + Checkbox[size]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(-210, -150); + } + else if(size == 5) + { + Checkbox[size]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(-210, -110); + } + } + else + { + if(size == 0) + { + Checkbox[size]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(40, -190); + } + else if(size == 1) + { + Checkbox[size]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(40, -150); + } + else if(size == 2) + { + Checkbox[size]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(40, -110); + } + else if(size == 3) + { + Checkbox[size]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(-210, -190); + } + else if(size == 4) + { + Checkbox[size]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(-210, -150); + } + else if(size == 5) + { + Checkbox[size]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Checkbox[size]->SetPosition(-210, -110); + } + } +} + +int CheckboxPrompt::GetChoice() +{ + int choice = PromptWindow::GetChoice(); + if(choice == 0) + return CheckedNone; + + else if(choice == 1) + { + int ret = 0; + + for(u32 i = 0; i < Checkbox.size(); ++i) + { + if(Checkbox[i]->IsChecked()) + ret |= 1 << i; + } + + return ret; + } + + return -2; +} + +void CheckboxPrompt::SetChecked(int box, bool checked) +{ + if(box < 0 || box >= (int) Checkbox.size()) + return; + + Checkbox[box]->SetChecked(checked); +} + +int CheckboxPrompt::Show(const char *title, const char *msg, + const char *chbx1, const char *chbx2, + const char *chbx3, const char *chbx4, + const char *chbx5, const char *chbx6, + int initChecks) +{ + CheckboxPrompt * Window = new CheckboxPrompt(title, msg); + if(chbx1) + { + Window->AddCheckBox(chbx1); + Window->SetChecked(0, initChecks & CheckedBox1); + } + if(chbx2) + { + Window->AddCheckBox(chbx2); + Window->SetChecked(1, initChecks & CheckedBox2); + } + if(chbx3) + { + Window->AddCheckBox(chbx3); + Window->SetChecked(2, initChecks & CheckedBox3); + } + if(chbx4) + { + Window->AddCheckBox(chbx4); + Window->SetChecked(3, initChecks & CheckedBox4); + } + if(chbx5) + { + Window->AddCheckBox(chbx5); + Window->SetChecked(4, initChecks & CheckedBox5); + } + if(chbx6) + { + Window->AddCheckBox(chbx6); + Window->SetChecked(5, initChecks & CheckedBox6); + } + + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(Window); + + int choice = -2; + + while (choice == -2) + { + usleep(100); + + if (shutdown) + Sys_Shutdown(); + if (reset) + Sys_Reboot(); + + choice = Window->GetChoice(); + } + + delete Window; + mainWindow->SetState(STATE_DEFAULT); + + return choice; +} diff --git a/source/prompts/CheckboxPrompt.hpp b/source/prompts/CheckboxPrompt.hpp new file mode 100644 index 0000000..d980b1f --- /dev/null +++ b/source/prompts/CheckboxPrompt.hpp @@ -0,0 +1,68 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _CHECKBOXPROMPT_HPP_ +#define _CHECKBOXPROMPT_HPP_ + +#include "GUI/gui_checkbox.hpp" +#include "PromptWindow.hpp" + +enum +{ + CheckedNone = -0x01, + CheckedBox1 = 0x01, + CheckedBox2 = 0x02, + CheckedBox3 = 0x04, + CheckedBox4 = 0x08, + CheckedBox5 = 0x10, + CheckedBox6 = 0x20, +}; + +class CheckboxPrompt : private PromptWindow, public sigslot::has_slots<> +{ + public: + //! Constructor + CheckboxPrompt(const char * title = 0, const char *msg = 0); + //! Destructor + virtual ~CheckboxPrompt(); + //! Add new checkbox + void AddCheckBox(const char *text); + //! Default function to get the button pressed + int GetChoice(); + //! Set a checkbox checked/unchecked + void SetChecked(int box, bool checked); + //! Show window and wait for the user to press OK/Cancel + static int Show(const char *title = 0, const char *msg = 0, + const char *chbx1 = 0, const char *chbx2 = 0, + const char *chbx3 = 0, const char *chbx4 = 0, + const char *chbx5 = 0, const char *chbx6 = 0, + int initChecks = 0); + protected: + void OnCheckBoxClick(GuiButton *sender, int chan, const POINT &pointer); + std::vector CheckboxTxt; + std::vector Checkbox; +}; + +#define CheckboxWindow CheckboxPrompt::Show + +#endif diff --git a/source/prompts/DiscBrowser.cpp b/source/prompts/DiscBrowser.cpp new file mode 100644 index 0000000..e33d070 --- /dev/null +++ b/source/prompts/DiscBrowser.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** + * DiscBrowser + * USB Loader GX 2009 + * + * DiscBrowser.h + ***************************************************************************/ +#include +#include "language/gettext.h" +#include "GUI/gui.h" +#include "GUI/gui_optionbrowser.h" +#include "prompts/PromptWindows.h" +#include "menu/menus.h" +#include "usbloader/disc.h" +#include "usbloader/fstfile.h" +#include "usbloader/wdvd.h" +#include "usbloader/wbfs.h" +#include "patches/dvd_broadway.h" +#include "libs/libwbfs/libwbfs.h" +#include "libs/libwbfs/wiidisc.h" +#include "main.h" +#include "sys.h" +#include "settings/GameTitles.h" +#include "themes/CTheme.h" +#include "memory/memory.h" +#include "gecko.h" + +/******************************************************************************** + *Disk Browser + *********************************************************************************/ +int DiscBrowse(const char * GameID, char * alternatedname, int alternatedname_size) +{ + gprintf("\nDiscBrowser() started"); + bool exit = false; + int ret = -1, choice; + + HaltGui(); + + gprintf("WBFS_OpenDisc\n"); + wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) GameID); + if (!disc) + { + ResumeGui(); + WindowPrompt(tr( "ERROR:" ), tr( "Could not open Disc" ), tr( "OK" )); + return ret; + } + gprintf("wd_open_disc\n"); + wiidisc_t *wdisc = wd_open_disc((s32(*)(void *, u32, u32, void *)) wbfs_disc_read, disc); + if (!wdisc) + { + ResumeGui(); + WindowPrompt(tr( "ERROR:" ), tr( "Could not open Disc" ), tr( "OK" )); + return ret; + } + + gprintf("wd_get_fst\n"); + FST_ENTRY * fstbuffer = (FST_ENTRY *) wd_extract_file(wdisc, ONLY_GAME_PARTITION, (char *) "FST"); + if (!fstbuffer) + { + ResumeGui(); + WindowPrompt(tr( "ERROR:" ), tr( "Not enough free memory." ), tr( "OK" )); + return -1; + } + + gprintf("wd_close_disc\n"); + wd_close_disc(wdisc); + gprintf("WBFS_CloseDisc\n"); + WBFS_CloseDisc(disc); + + gprintf("options\n"); + OptionList options; + + for (u32 i = 0, position = 0; i < fstbuffer[0].filelen; i++) + { + //don't add files that aren't .dol to the list + const char * filename = fstfiles(fstbuffer, i); + const char * fileext = NULL; + + if(filename) + fileext = strrchr(filename, '.'); + + if (fileext && strcasecmp(fileext, ".dol") == 0) + { + options.SetName(position, "%s %03i", tr("Offset"), (int)i); + options.SetValue(position, filename); + position++; + } + } + + free(fstbuffer); + + gprintf("\n%i alt dols found", options.GetLength()+1); + if (options.GetLength() <= 0) + { + WindowPrompt(tr( "ERROR" ), tr( "No DOL file found on disc." ), tr( "OK" )); + return ret; + } + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData settingsbg(Resources::GetFile("settings_background.png"), Resources::GetFileSize("settings_background.png")); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigHome; + trigHome.SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, 0); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + GuiText titleTxt(GameTitles.GetTitle(GameID), 28, ( GXColor ) {0, 0, 0, 255}); + titleTxt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt.SetPosition(12, 40); + titleTxt.SetMaxWidth(356, SCROLL_HORIZONTAL); + + GuiImage settingsbackground(&settingsbg); + GuiButton settingsbackgroundbtn(settingsbackground.GetWidth(), settingsbackground.GetHeight()); + settingsbackgroundbtn.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + settingsbackgroundbtn.SetPosition(0, 0); + settingsbackgroundbtn.SetImage(&settingsbackground); + + GuiText cancelBtnTxt(tr( "Back" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + cancelBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30); + GuiImage cancelBtnImg(&btnOutline); + if (Settings.wsprompt == ON) + { + cancelBtnTxt.SetWidescreen(Settings.widescreen); + cancelBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton cancelBtn(&cancelBtnImg, &cancelBtnImg, 2, 3, 180, 400, &trigA, btnSoundOver, btnSoundClick2, 1); + cancelBtn.SetScale(0.9); + cancelBtn.SetLabel(&cancelBtnTxt); + cancelBtn.SetTrigger(&trigB); + + GuiOptionBrowser optionBrowser3(396, 280, &options, "bg_options_settings.png"); + optionBrowser3.SetPosition(0, 90); + optionBrowser3.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + + HaltGui(); + GuiWindow w(screenwidth, screenheight); + w.Append(&settingsbackgroundbtn); + w.Append(&titleTxt); + w.Append(&cancelBtn); + w.Append(&optionBrowser3); + + mainWindow->Append(&w); + + ResumeGui(); + while (!exit) + { + usleep(100); + + if (shutdown) + Sys_Shutdown(); + if (reset) + Sys_Reboot(); + + ret = optionBrowser3.GetClickedOption(); + + if (ret >= 0) + { + choice = WindowPrompt(options.GetValue(ret), tr( "Load this DOL as alternate DOL?" ), tr( "OK" ), tr( "Cancel" )); + if (choice) + { + snprintf(alternatedname, alternatedname_size, options.GetValue(ret)); + const char * offset = options.GetName(ret); + if(offset) + ret = atoi(offset+strlen("Offset ")); //doloffset + else + ret = -1; // weird problem + exit = true; + } + } + + if (cancelBtn.GetState() == STATE_CLICKED) + { + exit = true; + } + } + + HaltGui(); + mainWindow->Remove(&w); + ResumeGui(); + + return ret; +} diff --git a/source/prompts/DiscBrowser.h b/source/prompts/DiscBrowser.h new file mode 100644 index 0000000..4eefc8f --- /dev/null +++ b/source/prompts/DiscBrowser.h @@ -0,0 +1,16 @@ +/**************************************************************************** + * DiscBrowser + * USB Loader GX 2009 + * + * DiscBrowser.h + ***************************************************************************/ + +#ifndef _DISCBROWSER_H_ +#define _DISCBROWSER_H_ + +#include +#include "usbloader/disc.h" + +int DiscBrowse(const char * GameID, char * dolname, int dolname_size); + +#endif diff --git a/source/prompts/GCDeleteMenu.cpp b/source/prompts/GCDeleteMenu.cpp new file mode 100644 index 0000000..9e21fcd --- /dev/null +++ b/source/prompts/GCDeleteMenu.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 "GCDeleteMenu.h" +#include "GameCube/GCGames.h" +#include "settings/CSettings.h" +#include "settings/GameTitles.h" +#include "language/gettext.h" +#include "themes/gettheme.h" +#include "themes/Resources.h" +#include "menu/menus.h" + +GCDeleteMenu::GCDeleteMenu(void) +{ + titleTxt->SetText(tr("Game Cube Games Delete")); + button1Txt->SetText(tr("Delete")); + browserRefresh(); +} + +GCDeleteMenu::~GCDeleteMenu() +{ + for(u32 i = 0; i < sizeTxtList.size(); ++i) + delete sizeTxtList[i]; +} + +void GCDeleteMenu::browserRefresh(void) +{ + browser->Clear(); + browser->SetMaxTextWidth(200); + + for(u32 i = 0; i < sizeTxtList.size(); ++i) + delete sizeTxtList[i]; + + sizeTxtList.resize(GCGames::Instance()->GetSDHeaders().size()); + + for(u32 i = 0; i < GCGames::Instance()->GetSDHeaders().size(); ++i) + { + const struct discHdr *gcDiscHdr = &GCGames::Instance()->GetSDHeaders().at(i); + float fSize = GCGames::Instance()->GetGameSize((char*)gcDiscHdr->id); + + browser->AddEntrie(GameTitles.GetTitle(gcDiscHdr)); + + char size_text[20]; + snprintf(size_text, sizeof(size_text), "(%.2fGB)", fSize); + + sizeTxtList[i] = new GuiText(size_text, 18, thColor("r=0 g=0 b=0 a=255 - checkbox browser text color")); + sizeTxtList[i]->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); + sizeTxtList[i]->SetPosition(-40, 5); + browser->GetCheckbox(i)->SetLabel(sizeTxtList[i]); + } +} + +int GCDeleteMenu::Show() +{ + while(true) + { + usleep(10000); + + if (shutdown) + Sys_Shutdown(); + else if (reset) + Sys_Reboot(); + + else if(backBtn->GetState() == STATE_CLICKED) + { + if(!changed || WindowPrompt(tr("Do you want to discard changes?"), 0, tr("Yes"), tr("No"))) + break; + + backBtn->ResetState(); + } + + else if (homeButton->GetState() == STATE_CLICKED) + { + gprintf("\thomeButton clicked\n"); + WindowExitPrompt(); + mainWindow->SetState(STATE_DISABLED); + SetState(STATE_DEFAULT); + homeButton->ResetState(); + } + + else if(button1->GetState() == STATE_CLICKED) + { + if(!changed) + { + WindowPrompt(tr("Error:"), tr("Nothing selected to delete."), tr("OK")); + } + else if(WindowPrompt(tr("Attention!"), tr("Are you really sure you want to delete all selected games from the SD card?"), tr("Yes"), tr("Cancel"))) + { + DeleteSelectedGames(); + break; + } + + button1->ResetState(); + } + } + + return 0; +} + +void GCDeleteMenu::DeleteSelectedGames(void) +{ + for(u32 i = 0; i < GCGames::Instance()->GetSDHeaders().size(); ++i) + { + if(browser->IsChecked(i)) + { + GCGames::Instance()->RemoveSDGame((char*)GCGames::Instance()->GetSDHeaders().at(i).id); + } + } + GCGames::Instance()->LoadAllGames(); +} diff --git a/source/prompts/GCDeleteMenu.h b/source/prompts/GCDeleteMenu.h new file mode 100644 index 0000000..ee80ceb --- /dev/null +++ b/source/prompts/GCDeleteMenu.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 GCDELETEMENU_H +#define GCDELETEMENU_H + +#include "CheckboxBrowserMenu.h" + +class GCDeleteMenu : public CheckboxBrowserMenu +{ + public: + GCDeleteMenu(); + virtual ~GCDeleteMenu(); + int Show(); + private: + void DeleteSelectedGames(void); + void browserRefresh(); + std::vector sizeTxtList; +}; + +#endif // GCDELETEMENU_H diff --git a/source/prompts/GCMultiDiscMenu.cpp b/source/prompts/GCMultiDiscMenu.cpp new file mode 100644 index 0000000..45b2ae1 --- /dev/null +++ b/source/prompts/GCMultiDiscMenu.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 "GCMultiDiscMenu.h" +#include "GameCube/GCGames.h" +#include "settings/CSettings.h" +#include "settings/GameTitles.h" +#include "language/gettext.h" +#include "themes/gettheme.h" +#include "themes/Resources.h" +#include "menu/menus.h" + +GCMultiDiscMenu::GCMultiDiscMenu(const std::vector &List) + : gcGameList(List) +{ + titleTxt->SetText(tr("Game Cube Install Menu")); + button1Txt->SetText(tr("Install")); + browserRefresh(); +} + +void GCMultiDiscMenu::browserRefresh(void) +{ + browser->Clear(); + + for(u32 i = 0; i < gcGameList.size(); ++i) + { + browser->AddEntrie(gcGameList[i].title); + } +} + +int GCMultiDiscMenu::ShowSelection() +{ + while(true) + { + usleep(10000); + + if (shutdown) + Sys_Shutdown(); + else if (reset) + Sys_Reboot(); + + else if(backBtn->GetState() == STATE_CLICKED) + { + if(!changed || WindowPrompt(tr("Do you want to discard changes?"), 0, tr("Yes"), tr("No"))) + break; + + backBtn->ResetState(); + } + + else if (homeButton->GetState() == STATE_CLICKED) + { + gprintf("\thomeButton clicked\n"); + WindowExitPrompt(); + mainWindow->SetState(STATE_DISABLED); + SetState(STATE_DEFAULT); + homeButton->ResetState(); + } + + else if(button1->GetState() == STATE_CLICKED) + { + if(!changed) + { + WindowPrompt(tr("Error:"), tr("Nothing selected to install."), tr("OK")); + } + else if(WindowPrompt(tr("Do you want to install selected games?"), 0, tr("Yes"), tr("Cancel"))) + { + return 1; + } + + button1->ResetState(); + } + } + + return 0; +} + +std::vector GCMultiDiscMenu::GetSelectedGames(void) +{ + std::vector selectedGames; + + for(u32 i = 0; i < gcGameList.size(); ++i) + { + if(browser->IsChecked(i)) + { + selectedGames.push_back(i); + } + } + return selectedGames; +} diff --git a/source/prompts/GCMultiDiscMenu.h b/source/prompts/GCMultiDiscMenu.h new file mode 100644 index 0000000..f001e2c --- /dev/null +++ b/source/prompts/GCMultiDiscMenu.h @@ -0,0 +1,33 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 GCMULTIDISCMENU_H +#define GCMULTIDISCMENU_H + +#include "CheckboxBrowserMenu.h" + +class GCMultiDiscMenu : public CheckboxBrowserMenu +{ + public: + GCMultiDiscMenu(const std::vector &List); + int ShowSelection(); + std::vector GetSelectedGames(void); + private: + void browserRefresh(); + const std::vector &gcGameList; +}; + +#endif diff --git a/source/prompts/GameWindow.cpp b/source/prompts/GameWindow.cpp new file mode 100644 index 0000000..15f49ed --- /dev/null +++ b/source/prompts/GameWindow.cpp @@ -0,0 +1,813 @@ +#include +#include "GameWindow.hpp" +#include "usbloader/disc.h" +#include "usbloader/wbfs.h" +#include "usbloader/GameList.h" +#include "usbloader/GameBooter.hpp" +#include "usbloader/AlternateDOLOffsets.h" +#include "GameCube/GCGames.h" +#include "themes/CTheme.h" +#include "FileOperations/fileops.h" +#include "settings/menus/GameSettingsMenu.hpp" +#include "settings/CSettings.h" +#include "settings/CGameSettings.h" +#include "settings/CGameStatistics.h" +#include "settings/GameTitles.h" +#include "prompts/PromptWindows.h" +#include "prompts/gameinfo.h" +#include "language/gettext.h" +#include "system/IosLoader.h" +#include "menu/menus.h" +#include "menu/WDMMenu.hpp" +#include "banner/OpeningBNR.hpp" +#include "utils/ShowError.h" +#include "utils/tools.h" + +#define NONE 0 +#define LEFT 1 +#define RIGHT 2 +#define IN 3 +#define OUT 4 + +GameWindow::GameWindow(GameBrowseMenu *m, struct discHdr *header) + : GuiWindow(472, 320) + , browserMenu(m) +{ + returnVal = -1; + gameSelected = 0; + dvdheader = NULL; + gameSound = NULL; + diskImgData = NULL; + diskImgData2 = NULL; + hidden = false; + reducedVol = false; + SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + SetPosition(0, -10); + + int gameIdx; + + //! get the game index to this header + for(gameIdx = 0; gameIdx < gameList.size(); ++gameIdx) + { + if(gameList[gameIdx] == header) + { + gameSelected = gameIdx; + break; + } + } + + //! Set dvd header if the header does not match any of the list games + if(gameIdx == gameList.size()) + dvdheader = header; + + dialogBox = Resources::GetImageData(Settings.widescreen ? "wdialogue_box_startgame.png" : "dialogue_box_startgame.png"); + btnOutline = Resources::GetImageData("button_dialogue_box.png"); + imgFavorite = Resources::GetImageData("favorite.png"); + imgNotFavorite = Resources::GetImageData("not_favorite.png"); + imgLeft = Resources::GetImageData("startgame_arrow_left.png"); + imgRight = Resources::GetImageData("startgame_arrow_right.png"); + + trigA = new GuiTrigger; + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigB = new GuiTrigger; + trigB->SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + trigL = new GuiTrigger; + trigL->SetButtonOnlyTrigger(-1, WPAD_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_LEFT, PAD_BUTTON_LEFT); + trigR = new GuiTrigger; + trigR->SetButtonOnlyTrigger(-1, WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT, PAD_BUTTON_RIGHT); + trigPlus = new GuiTrigger; + trigPlus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_PLUS | WPAD_CLASSIC_BUTTON_PLUS, 0); + trigMinus = new GuiTrigger; + trigMinus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, 0); + + dialogBoxImg = new GuiImage(dialogBox); + + nameBtnTT = new GuiTooltip(tr( "Rename Game Title" )); + if (Settings.wsprompt) nameBtnTT->SetWidescreen(Settings.widescreen); + nameTxt = new GuiText("", 22, thColor("r=0 g=0 b=0 a=255 - game window name text color")); + if (Settings.wsprompt) nameTxt->SetWidescreen(Settings.widescreen); + nameTxt->SetMaxWidth(350, SCROLL_HORIZONTAL); + nameBtn = new GuiButton(120, 50); + nameBtn->SetLabel(nameTxt); + nameBtn->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + nameBtn->SetPosition(0, -122); + nameBtn->SetSoundOver(btnSoundOver); + nameBtn->SetSoundClick(btnSoundClick2); + + if (Settings.godmode == 1 && !dvdheader) + { + nameBtn->SetToolTip(nameBtnTT, 24, -30, ALIGN_LEFT); + nameBtn->SetTrigger(trigA); + nameBtn->SetEffectGrow(); + } + + sizeTxt = new GuiText((char*) NULL, 22, thColor("r=0 g=0 b=0 a=255 - game window size text color")); + sizeTxt->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + sizeTxt->SetPosition(135, 70); + + diskImg = new GuiDiskCover; + diskImg->SetWidescreen(Settings.widescreen); + diskImg->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + diskImg->SetAngle(0); + diskImg2 = new GuiDiskCover; + diskImg2->SetWidescreen(Settings.widescreen); + diskImg2->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + diskImg2->SetPosition(0, -20); + diskImg2->SetAngle(0); + diskImg2->SetBeta(180); + + playcntTxt = new GuiText((char*) NULL, 18, thColor("r=0 g=0 b=0 a=255 - game window playcount text color")); + playcntTxt->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + playcntTxt->SetPosition(-115, 45); + + gameBtn = new GuiButton(160, 160); + gameBtn->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + gameBtn->SetPosition(0, -20); + gameBtn->SetImage(diskImg); + gameBtn->SetSoundOver(btnSoundOver); + gameBtn->SetSoundClick(btnSoundClick2); + gameBtn->SetTrigger(trigA); + gameBtn->SetState(STATE_SELECTED); + + backBtnTxt = new GuiText(tr( "Back" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + backBtnImg = new GuiImage(btnOutline); + if (Settings.wsprompt) + { + backBtnTxt->SetWidescreen(Settings.widescreen); + backBtnImg->SetWidescreen(Settings.widescreen); + } + backBtn = new GuiButton(backBtnImg, backBtnImg, 1, 5, 0, 0, trigA, btnSoundOver, btnSoundClick2, 1); + backBtn->SetLabel(backBtnTxt); + backBtn->SetTrigger(trigB); + backBtn->SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + backBtn->SetPosition(0, -40); + + settingsBtnTxt = new GuiText(tr( "Settings" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + settingsBtnImg = new GuiImage(btnOutline); + if (Settings.wsprompt) + { + settingsBtnTxt->SetWidescreen(Settings.widescreen); + settingsBtnImg->SetWidescreen(Settings.widescreen); + } + settingsBtn = new GuiButton(settingsBtnImg, settingsBtnImg, 0, 4, 50, -40, trigA, btnSoundOver, btnSoundClick2, 1); + settingsBtn->SetLabel(settingsBtnTxt); + + int xPos = -198; + for(int i = 0; i < FAVORITE_STARS; ++i) + { + FavoriteBtnImg[i] = new GuiImage; + FavoriteBtnImg[i]->SetWidescreen(Settings.widescreen); + FavoriteBtn[i] = new GuiButton(imgFavorite->GetWidth(), imgFavorite->GetHeight()); + FavoriteBtn[i]->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + FavoriteBtn[i]->SetPosition(xPos, -60); + FavoriteBtn[i]->SetImage(FavoriteBtnImg[i]); + FavoriteBtn[i]->SetSoundOver(btnSoundOver); + FavoriteBtn[i]->SetSoundClick(btnSoundClick2); + FavoriteBtn[i]->SetTrigger(trigA); + FavoriteBtn[i]->SetEffectGrow(); + + xPos += 27; + } + + btnLeftImg = new GuiImage(imgLeft); + if (Settings.wsprompt) btnLeftImg->SetWidescreen(Settings.widescreen); + btnLeft = new GuiButton(btnLeftImg, btnLeftImg, 0, 5, 20, 0, trigA, btnSoundOver, btnSoundClick2, 1); + btnLeft->SetTrigger(trigL); + btnLeft->SetTrigger(trigMinus); + + btnRightImg = new GuiImage(imgRight); + if (Settings.wsprompt) btnRightImg->SetWidescreen(Settings.widescreen); + btnRight = new GuiButton(btnRightImg, btnRightImg, 1, 5, -20, 0, trigA, btnSoundOver, btnSoundClick2, 1); + btnRight->SetTrigger(trigR); + btnRight->SetTrigger(trigPlus); + + detailsBtnTxt = new GuiText(tr( "Details" ), 22, thColor("r=0 g=0 b=0 a=255 - game window details button text color")); + detailsBtnOverTxt = new GuiText(tr( "Details" ), 22, thColor("r=30 g=30 b=240 a=255 - game window details button over text color")); + detailsBtn = new GuiButton(detailsBtnTxt->GetTextWidth(), 25); + detailsBtn->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + detailsBtn->SetPosition(120, 45); + detailsBtn->SetLabel(detailsBtnTxt); + detailsBtn->SetLabelOver(detailsBtnOverTxt); + detailsBtn->SetTrigger(trigA); + detailsBtn->SetEffectGrow(); + + Append(dialogBoxImg); + if (Settings.ShowPlayCount) Append(playcntTxt); + Append(backBtn); + Append(detailsBtn); + Append(nameBtn); + Append(sizeTxt); + if (!dvdheader)//stuff we don't show if it is a DVD mounted + { + Append(btnLeft); + Append(btnRight); + for(int i = 0; i < FAVORITE_STARS; ++i) + Append(FavoriteBtn[i]); + } + //check if unlocked + if (Settings.godmode || !(Settings.ParentalBlocks & BLOCK_GAME_SETTINGS)) + { + backBtn->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + backBtn->SetPosition(-50, -40); + Append(settingsBtn); + } + + Append(diskImg2); + Append(gameBtn); //! Appending the disc on top of all + + ChangeGame(NONE); + diskImg->SetImage(diskImgData); + + SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); +} + +GameWindow::~GameWindow() +{ + if(!hidden) + { + StopEffect(); + SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + ResumeGui(); + + while(parentElement && this->GetEffect() > 0) usleep(100); + + HaltGui(); + + if(parentElement) + ((GuiWindow * ) parentElement)->Remove(this); + } + + RemoveAll(); + + delete trigA; + delete trigB; + delete trigL; + delete trigR; + delete trigPlus; + delete trigMinus; + + delete diskImgData; + delete diskImgData2; + delete dialogBox; + delete btnOutline; + delete imgFavorite; + delete imgNotFavorite; + delete imgLeft; + delete imgRight; + + delete diskImg; + delete diskImg2; + + delete dialogBoxImg; + delete backBtnImg; + delete settingsBtnImg; + delete btnLeftImg; + delete btnRightImg; + + delete nameBtnTT; + + delete sizeTxt; + delete playcntTxt; + delete nameTxt; + delete backBtnTxt; + delete settingsBtnTxt; + delete detailsBtnTxt; + delete detailsBtnOverTxt; + + delete nameBtn; + delete gameBtn; + delete backBtn; + delete settingsBtn; + delete btnLeft; + delete btnRight; + delete detailsBtn; + + for(int i = 0; i < FAVORITE_STARS; ++i) + { + delete FavoriteBtnImg[i]; + delete FavoriteBtn[i]; + } + + if(gameSound) gameSound->Stop(); + delete gameSound; + bgMusic->SetVolume(Settings.volume); + + ResumeGui(); +} + +void GameWindow::LoadGameSound(const struct discHdr * header) +{ + if (Settings.gamesoundvolume == 0) + return; + + BNRInstance::Instance()->Load(header); + + if (gameSound) + { + gameSound->Stop(); + delete gameSound; + gameSound = NULL; + } + + if( (BNRInstance::Instance()->Get() != NULL) + && gameBanner.LoadSound(BNRInstance::Instance()->Get(), BNRInstance::Instance()->GetSize()) + && gameBanner.getSound()) + { + gameSound = new GuiSound(gameBanner.getSound(), gameBanner.getSoundSize(), Settings.gamesoundvolume); + } + else if((header->type == TYPE_GAME_GC_IMG) || (header->type == TYPE_GAME_GC_DISC) || (header->type == TYPE_GAME_GC_EXTRACTED)) + { + //! on game cube load the default sound + gameSound = new GuiSound(Resources::GetFile("gc_banner.ogg"), Resources::GetFileSize("gc_banner.ogg"), Settings.gamesoundvolume); + } + if(gameSound) + { + bgMusic->SetVolume(0); + if (Settings.gamesound == 2) + gameSound->SetLoop(1); + gameSound->Play(); + } +} + +void GameWindow::LoadDiscImage(const u8 * id) +{ + HaltGui(); + delete diskImgData2; + diskImgData2 = diskImgData; + diskImgData = NULL; + + char imgPath[150]; + char IDFull[7]; + char ID3[4]; + char ID4[5]; + snprintf(IDFull, sizeof(IDFull), "%s", (char*) id); + snprintf(ID3, sizeof(ID3), "%s", IDFull); + snprintf(ID4, sizeof(ID4), "%s", IDFull); + + snprintf(imgPath, sizeof(imgPath), "%s%s.png", Settings.disc_path, IDFull); //changed to current full id + diskImgData = new GuiImageData(imgPath); + + if (!diskImgData->GetImage()) + { + delete diskImgData; + snprintf(imgPath, sizeof(imgPath), "%s%s.png", Settings.disc_path, ID3); //changed to current id + diskImgData = new GuiImageData(imgPath); + } + if (!diskImgData->GetImage()) + { + delete diskImgData; + snprintf(imgPath, sizeof(imgPath), "%s%s.png", Settings.disc_path, ID4); //changed to current id + diskImgData = new GuiImageData(imgPath); + } + if (!diskImgData->GetImage()) + { + delete diskImgData; + diskImgData = Resources::GetImageData("nodisc.png"); + } +} + +void GameWindow::SetWindowEffect(int direction, int in_out) +{ + if(direction == LEFT && Settings.xflip == XFLIP_DISK3D) + { + if(in_out == IN) + { + diskImg->SetImage(diskImgData); + diskImg->SetBeta(90); + diskImg->SetBetaRotateEffect(-90, 15); + diskImg2->SetImage(diskImgData2); + diskImg2->SetBeta(270); + diskImg2->SetBetaRotateEffect(-90, 15); + sizeTxt->SetEffect(EFFECT_FADE, 17); + nameTxt->SetEffect(EFFECT_FADE, 17); + } + else + { + diskImg->SetImage(diskImgData2); + diskImg->SetBeta(0); + diskImg->SetBetaRotateEffect(90, 15); + diskImg2->SetImage(diskImgData); + diskImg2->SetAngle(diskImg->GetAngle()); + diskImg2->SetBeta(180); + diskImg2->SetBetaRotateEffect(90, 15); + sizeTxt->SetEffect(EFFECT_FADE, -17); + nameTxt->SetEffect(EFFECT_FADE, -17); + } + } + else if(direction == RIGHT && Settings.xflip == XFLIP_DISK3D) + { + if(in_out == IN) + { + diskImg->SetImage(diskImgData); + diskImg->SetBeta(270); + diskImg->SetBetaRotateEffect(90, 15); + diskImg2->SetImage(diskImgData2); + diskImg2->SetBeta(90); + diskImg2->SetBetaRotateEffect(90, 15); + sizeTxt->SetEffect(EFFECT_FADE, 17); + nameTxt->SetEffect(EFFECT_FADE, 17); + + } + else + { + diskImg->SetImage(diskImgData2); + diskImg->SetBeta(0); + diskImg->SetBetaRotateEffect(-90, 15); + diskImg2->SetImage(diskImgData); + diskImg2->SetAngle(diskImg->GetAngle()); + diskImg2->SetBeta(180); + diskImg2->SetBetaRotateEffect(-90, 15); + sizeTxt->SetEffect(EFFECT_FADE, -17); + nameTxt->SetEffect(EFFECT_FADE, -17); + } + } + else if(direction == LEFT) + { + if(in_out == IN) + SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 50); + else + SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 50); + } + else if(direction == RIGHT) + { + if(in_out == IN) + SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 50); + else + SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 50); + } + + ResumeGui(); + while(parentElement && (this->GetEffect() > 0 || + nameTxt->GetEffect() > 0 || diskImg->GetBetaRotateEffect())) + { + usleep(1000); + } +} + +void GameWindow::ChangeGame(int EffectDirection) +{ + //! Stop thread because all the extract functions are not thread safe + //! Let it finish the current loading though + BannerAsync::HaltThread(); + + struct discHdr * header = (dvdheader ? dvdheader : gameList[gameSelected]); + LoadGameSound(header); + LoadDiscImage(header->id); + SetWindowEffect(EffectDirection, OUT); + + HaltGui(); + + if (header->tid != 0) + { + if(header->type == TYPE_GAME_NANDCHAN) + sizeTxt->SetTextf(tr("Real Nand")); + else if(header->type == TYPE_GAME_EMUNANDCHAN) + sizeTxt->SetTextf(tr("Emulated Nand")); + + } + else if(header->type == TYPE_GAME_WII_IMG) + { + float size = 0.0f; + WBFS_GameSize(header->id, &size); + sizeTxt->SetTextf("%.2fGB", size); //set size text; + } + else if(header->type == TYPE_GAME_WII_DISC) + { + float size = (float) WBFS_EstimeGameSize() / GB_SIZE; + if(size == 0.0f) + size = 4.37f*GB_SIZE; // Use default disc size if can't be determined + sizeTxt->SetTextf("%.2fGB", size); //set size text; + } + else if(header->type == TYPE_GAME_GC_IMG) + { + float size = GCGames::Instance()->GetGameSize((const char *) header->id); + sizeTxt->SetTextf("%.2fGB", size); //set size text; + // TODO: Add GC multi disc size check + } + + // Rescale the disc if the picture is bigger (HighRes Disc art from gametdb) + /* + if(diskImgData->GetWidth() > 160) + { + diskImg->SetScale(160.0f / diskImgData->GetWidth()); + diskImg->SetPosition( -(diskImgData->GetWidth() - 160)/2 , -(diskImgData->GetHeight() - 160)/2 ); + } + else + { + diskImg->SetScale(1.0f); + diskImg->SetPosition( 0, 0); + } + */ + + diskImg->SetImage(diskImgData); + nameTxt->SetText(GameTitles.GetTitle(header)); + playcntTxt->SetTextf("%s: %i", tr( "Play Count" ), GameStatistics.GetPlayCount(header)); + + int favoritevar = GameStatistics.GetFavoriteRank(header->id); + for(int i = 0; i < FAVORITE_STARS; ++i) + FavoriteBtnImg[i]->SetImage(favoritevar >= i+1 ? imgFavorite : imgNotFavorite); + + EffectDirection = EffectDirection == LEFT ? RIGHT : EffectDirection == RIGHT ? LEFT : NONE; + SetWindowEffect(EffectDirection, IN); + BannerAsync::ResumeThread(); +} + +void GameWindow::Hide(void) +{ + GuiWindow *parentWindow = (GuiWindow *) parentElement; + this->SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while(parentWindow && this->GetEffect() > 0) usleep(100); + if(parentWindow) parentWindow->Remove(this); + hidden = true; +} + +void GameWindow::Show(void) +{ + this->SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + GuiWindow *parentWindow = (GuiWindow *) parentElement; + if(parentWindow) + { + parentWindow->SetState(STATE_DISABLED); + parentWindow->Append(this); + } + hidden = false; +} + +int GameWindow::Run() +{ + int choice = -1; + + while(choice == -1) + { + usleep(50000); + + if (shutdown) //for power button + Sys_Shutdown(); + else if (reset) //for reset button + Sys_Reboot(); + + choice = MainLoop(); + } + + return choice; +} + +int GameWindow::MainLoop() +{ + diskImg->SetSpin(gameBtn->GetState() == STATE_SELECTED); + diskImg2->SetSpin(gameBtn->GetState() == STATE_SELECTED); + + if (gameBtn->GetState() == STATE_CLICKED) + { + // Hide the window + Hide(); + + // If this function was left then the game start was canceled + GameWindow::BootGame(dvdheader ? dvdheader : gameList[gameSelected]); + + // If it returns from that function reload the list + gameList.FilterList(); + + // Show the window again + Show(); + + gameBtn->ResetState(); + } + + else if (backBtn->GetState() == STATE_CLICKED) //back + { + mainWindow->SetState(STATE_DEFAULT); + returnVal = 0; + } + + else if(settingsBtn->GetState() == STATE_CLICKED) //settings + { + settingsBtn->ResetState(); + // Hide the window + Hide(); + + wiilight(0); + int settret = GameSettingsMenu::Execute(browserMenu, dvdheader ? dvdheader : gameList[gameSelected]); + + // Show the window again or return to browser on uninstall + if (settret == MENU_DISCLIST) + returnVal = 1; + else + Show(); + + } + + else if (nameBtn->GetState() == STATE_CLICKED) //rename + { + // Hide the window + Hide(); + + // This button can only be clicked when this is not a dvd header + struct discHdr *header = gameList[gameSelected]; + + //enter new game title + char entered[60]; + snprintf(entered, sizeof(entered), "%s", GameTitles.GetTitle(header)); + int result = OnScreenKeyboard(entered, 60, 0); + if (result == 1) + { + WBFS_RenameGame(header->id, entered); + GameTitles.SetGameTitle(header->id, entered); + wString oldFilter(gameList.GetCurrentFilter()); + gameList.ReadGameList(); + gameList.FilterList(oldFilter.c_str()); + if(browserMenu) browserMenu->ReloadBrowser(); + } + // Show the window again + Show(); + + nameBtn->ResetState(); + } + + else if (btnRight->GetState() == STATE_CLICKED) //next game + { + if(Settings.xflip == XFLIP_YES) + { + gameSelected = (gameSelected - 1 + gameList.size()) % gameList.size(); + ChangeGame(LEFT); + } + else if(Settings.xflip == XFLIP_SYSMENU) + { + gameSelected = (gameSelected + 1) % gameList.size(); + ChangeGame(LEFT); + } + else if(Settings.xflip == XFLIP_WTF) + { + gameSelected = (gameSelected - 1 + gameList.size()) % gameList.size(); + ChangeGame(RIGHT); + } + else + { + gameSelected = (gameSelected + 1) % gameList.size(); + ChangeGame(RIGHT); + } + + btnRight->ResetState(); + } + + else if (btnLeft->GetState() == STATE_CLICKED) //previous game + { + if(Settings.xflip == XFLIP_YES) + { + gameSelected = (gameSelected + 1) % gameList.size(); + ChangeGame(RIGHT); + } + else if(Settings.xflip == XFLIP_SYSMENU) + { + gameSelected = (gameSelected - 1 + gameList.size()) % gameList.size(); + ChangeGame(RIGHT); + } + else if(Settings.xflip == XFLIP_WTF) + { + gameSelected = (gameSelected + 1) % gameList.size(); + ChangeGame(LEFT); + } + else + { + gameSelected = (gameSelected - 1 + gameList.size()) % gameList.size(); + ChangeGame(LEFT); + } + + btnLeft->ResetState(); + } + else if(detailsBtn->GetState() == STATE_CLICKED) + { + diskImg->SetState(STATE_DISABLED); + showGameInfo(gameSelected, dvdheader); + mainWindow->SetState(STATE_DISABLED); + this->SetState(STATE_DEFAULT); + diskImg->SetState(STATE_DEFAULT); + detailsBtn->ResetState(); + } + + if (reducedVol) + { + if (gameSound) + { + if (Settings.gamesound == 1 && !gameSound->IsPlaying()) + { + bgMusic->SetVolume(Settings.volume); + reducedVol = false; + } + } + else + { + bgMusic->SetVolume(Settings.volume); + reducedVol = false; + } + } + + for(int i = 0; i < FAVORITE_STARS; ++i) + { + if(FavoriteBtn[i]->GetState() == STATE_CLICKED) + { + // This button can only be clicked when this is not a dvd header + struct discHdr * header = gameList[gameSelected]; + int FavoriteRank = (i+1 == GameStatistics.GetFavoriteRank(header->id)) ? 0 : i+1; // Press the current rank to reset the rank + + GameStatistics.SetFavoriteRank(header->id, FavoriteRank); + GameStatistics.Save(); + for(int j = 0; j < FAVORITE_STARS; ++j) + FavoriteBtnImg[j]->SetImage(FavoriteRank >= j+1 ? imgFavorite : imgNotFavorite); + + FavoriteBtn[i]->ResetState(); + } + } + + return returnVal; +} + + +void GameWindow::BootGame(struct discHdr *header) +{ + wiilight(0); + + GameCFG* game_cfg = GameSettings.GetGameCFG(header->id); + + char IDfull[7]; + snprintf(IDfull, sizeof(IDfull), "%s", (char *) header->id); + + int gameIOS = game_cfg->ios == INHERIT ? Settings.cios : game_cfg->ios; + int gameNandEmuMode = game_cfg->NandEmuMode == INHERIT ? Settings.NandEmuMode : game_cfg->NandEmuMode; + if(header->type == TYPE_GAME_EMUNANDCHAN) + gameNandEmuMode = game_cfg->NandEmuMode == INHERIT ? Settings.NandEmuChanMode : game_cfg->NandEmuMode; + + if (game_cfg->loadalternatedol == 2) + { + char filepath[200]; + snprintf(filepath, sizeof(filepath), "%s%s.dol", Settings.dolpath, IDfull); + if (CheckFile(filepath) == false) + { + sprintf(filepath, "%s %s", filepath, tr( "does not exist!" )); + if(!WindowPrompt(tr( "Error" ), filepath, tr( "Continue" ), tr( "Cancel"))) + return; + } + } + else if(game_cfg->loadalternatedol == 3 && WDMMenu::Show(header) == 0) + { + // Canceled + return; + } + else if(game_cfg->loadalternatedol == 4) + { + if(!IosLoader::IsD2X(gameIOS)) + defaultDolPrompt((char *) header->id); + } + + if (game_cfg->ocarina == ON || (game_cfg->ocarina == INHERIT && Settings.ocarina == ON)) + { + char filepath[200]; + snprintf(filepath, sizeof(filepath), "%s%s.gct", Settings.Cheatcodespath, IDfull); + if (CheckFile(filepath) == false) + { + sprintf(filepath, "%s %s", filepath, tr( "does not exist! Loading game without cheats." )); + if(!WindowPrompt(tr( "Error" ), filepath, tr( "Continue" ), tr( "Cancel"))) + return; + } + } + + if(header->type == TYPE_GAME_EMUNANDCHAN) + { + if(gameNandEmuMode != EMUNAND_NEEK) + { + // If NandEmuPath is on root of the first FAT32 partition, allow Waninkoko's rev17-21 cIOS for EmuNAND Channels + bool NandEmu_compatible = false; + const char *NandEmuChanPath = game_cfg->NandEmuPath.size() == 0 ? Settings.NandEmuChanPath : game_cfg->NandEmuPath.c_str(); + NandEmu_compatible = IosLoader::is_NandEmu_compatible(NandEmuChanPath, gameIOS); + + if(!IosLoader::IsD2X(gameIOS) && !NandEmu_compatible) + { + ShowError(tr("Launching emulated nand channels only works on d2x cIOS! Change game IOS to a d2x cIOS first.")); + return; + } + } + } + + // Restrict emuNAND with Wii games only with d2x + if(header->type == TYPE_GAME_WII_IMG || header->type == TYPE_GAME_WII_DISC) + { + if(gameNandEmuMode && !IosLoader::IsD2X(gameIOS)) + { + ShowError(tr("Launching Wii games with emulated nand only works on d2x cIOS! Change game IOS to a d2x cIOS first.")); + return; + } + } + + GameStatistics.SetPlayCount(header->id, GameStatistics.GetPlayCount(header->id)+1); + GameStatistics.Save(); + + //Just calling that shuts down everything and starts game + int ret = GameBooter::BootGame(header); + + //If the launch is canceled, reduce playCount + if(ret == -1) + { + GameStatistics.SetPlayCount(header->id, GameStatistics.GetPlayCount(header->id)-1); + GameStatistics.Save(); + } +} diff --git a/source/prompts/GameWindow.hpp b/source/prompts/GameWindow.hpp new file mode 100644 index 0000000..a5ed62a --- /dev/null +++ b/source/prompts/GameWindow.hpp @@ -0,0 +1,85 @@ +#ifndef GAMEWINDOW_HPP_ +#define GAMEWINDOW_HPP_ + +#include "GUI/gui.h" +#include "GUI/gui_diskcover.h" +#include "banner/BannerAsync.h" +#include "menu/GameBrowseMenu.hpp" +#include "usbloader/disc.h" + +#define FAVORITE_STARS 5 + +class GameWindow : public GuiWindow +{ + public: + GameWindow(GameBrowseMenu *m, struct discHdr *header); + virtual ~GameWindow(); + int Run(); + int GetSelectedGame() { return gameSelected; } + static void BootGame(struct discHdr *header); + protected: + int MainLoop(); + void LoadGameSound(const struct discHdr * header); + void LoadDiscImage(const u8 * id); + void SetWindowEffect(int direction, int in_out); + void ChangeGame(int EffectDirection); + void Hide(); + void Show(); + + bool reducedVol; + bool hidden; + int returnVal; + int gameSelected; + GameBrowseMenu *browserMenu; + struct discHdr *dvdheader; + Banner gameBanner; + + GuiTrigger * trigA; + GuiTrigger * trigB; + GuiTrigger * trigL; + GuiTrigger * trigR; + GuiTrigger * trigPlus; + GuiTrigger * trigMinus; + + GuiImageData * diskImgData; + GuiImageData * diskImgData2; + GuiImageData * dialogBox; + GuiImageData * btnOutline; + GuiImageData * imgFavorite; + GuiImageData * imgNotFavorite; + GuiImageData * imgLeft; + GuiImageData * imgRight; + + GuiDiskCover * diskImg; + GuiDiskCover * diskImg2; + + GuiImage * dialogBoxImg; + GuiImage * backBtnImg; + GuiImage * settingsBtnImg; + GuiImage * btnLeftImg; + GuiImage * btnRightImg; + GuiImage * FavoriteBtnImg[FAVORITE_STARS]; + + GuiTooltip * nameBtnTT; + + GuiText * sizeTxt; + GuiText * playcntTxt; + GuiText * nameTxt; + GuiText * backBtnTxt; + GuiText * settingsBtnTxt; + GuiText * detailsBtnTxt; + GuiText * detailsBtnOverTxt; + + GuiButton * nameBtn; + GuiButton * gameBtn; + GuiButton * backBtn; + GuiButton * settingsBtn; + GuiButton * detailsBtn; + GuiButton * btnLeft; + GuiButton * btnRight; + GuiButton * FavoriteBtn[FAVORITE_STARS]; + + GuiSound * gameSound; +}; + +#endif diff --git a/source/prompts/HomebrewPrompt.cpp b/source/prompts/HomebrewPrompt.cpp new file mode 100644 index 0000000..52c0978 --- /dev/null +++ b/source/prompts/HomebrewPrompt.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "HomebrewPrompt.hpp" +#include "themes/gettheme.h" +#include "themes/Resources.h" +#include "language/gettext.h" +#include "utils/StringTools.h" +#include "menu/menus.h" + +HomebrewPrompt::HomebrewPrompt(const char *name, const char *coder, const char *version, + const char *release_date, const char *long_description, + GuiImageData * iconImgData, u64 filesize) + : PromptWindow(NULL, NULL) +{ + SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + SetPosition(0, 6); + + whiteBox = Resources::GetImageData("bg_options.png"); + + iconImg = new GuiImage(iconImgData); + iconImg->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + iconImg->SetPosition(45, 10); + + dialogBoxImg->SetSkew(0, -80, 0, -80, 0, 50, 0, 50); + dialogBoxImg->SetWidescreen(false); + + whiteBoxImg = new GuiImage(whiteBox); + whiteBoxImg->SetPosition(0, 110); + whiteBoxImg->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + whiteBoxImg->SetSkew(0, 0, 0, 0, 0, -120, 0, -120); + + nameTxt = new GuiText(name, 30, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + nameTxt->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + nameTxt->SetPosition(0, -15); + nameTxt->SetMaxWidth(430, SCROLL_HORIZONTAL); + + coderTxt = new GuiText(fmt(tr( "Coded by: %s" ), coder), 16, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + coderTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + coderTxt->SetPosition(180, 30); + coderTxt->SetMaxWidth(280); + + versionTxt = new GuiText(fmt(tr( "Version: %s" ), version), 16, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + versionTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + versionTxt->SetPosition(40, 65); + versionTxt->SetMaxWidth(430); + + release_dateTxt = new GuiText(release_date, 16, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + release_dateTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + release_dateTxt->SetPosition(40, 85); + release_dateTxt->SetMaxWidth(430); + + const int pagesize = 6; + long_descriptionTxt = new Text(long_description, 20, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + long_descriptionTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + long_descriptionTxt->SetPosition(46, 117); + long_descriptionTxt->SetMaxWidth(358); + long_descriptionTxt->SetLinesToDraw(pagesize); + long_descriptionTxt->Refresh(); + + //convert filesize from u64 to char and put unit of measurement after it + char filesizeCH[15]; + if (filesize <= 1024.0) + snprintf(filesizeCH, sizeof(filesizeCH), "%lld B", filesize); + if (filesize > 1024.0) + snprintf(filesizeCH, sizeof(filesizeCH), "%0.2f KB", filesize / 1024.0); + if (filesize > 1048576.0) + snprintf(filesizeCH, sizeof(filesizeCH), "%0.2f MB", filesize / 1048576.0); + + filesizeTxt = new GuiText(filesizeCH, 16, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + filesizeTxt->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); + filesizeTxt->SetPosition(-40, 12); + + scrollBar = new GuiScrollbar(150); + scrollBar->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + scrollBar->SetPosition(393, 115); + scrollBar->SetPageSize(pagesize); + scrollBar->SetEntrieCount(long_descriptionTxt->GetTotalLinesCount()); + scrollBar->listChanged.connect(this, &HomebrewPrompt::onListChange); + + Append(whiteBoxImg); + if(strcmp(long_description, "") != 0 && long_descriptionTxt->GetTotalLinesCount() > pagesize) + Append(scrollBar); + + if(strcmp(name, "") != 0) Append(nameTxt); + if(strcmp(version, "") != 0) Append(versionTxt); + if(strcmp(coder, "") != 0) Append(coderTxt); + if(strcmp(release_date, "") != 0) Append(release_dateTxt); + if(strcmp(long_description, "") != 0) Append(long_descriptionTxt); + Append(filesizeTxt); + Append(iconImg); + + AddButton(tr( "Load" )); + AddButton(tr( "Back" )); + + Button[0]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Button[0]->SetPosition(40, 2); + Button[1]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Button[1]->SetPosition(-40, 2); +} + +HomebrewPrompt::~HomebrewPrompt() +{ + ResumeGui(); + + SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while(parentElement && this->GetEffect() > 0) usleep(100); + + if(parentElement) + ((GuiWindow *) parentElement)->Remove(this); + parentElement = NULL; + + RemoveAll(); + + delete whiteBox; + delete iconImg; + delete whiteBoxImg; + delete nameTxt; + delete coderTxt; + delete versionTxt; + delete release_dateTxt; + delete long_descriptionTxt; + delete filesizeTxt; + delete scrollBar; +} + +void HomebrewPrompt::onListChange(int SelItem, int SelInd) +{ + long_descriptionTxt->SetTextLine(SelItem+SelInd); +} + +int HomebrewPrompt::MainLoop() +{ + int choice = -1; + + while (choice == -1) + { + usleep(100); + + if (shutdown) + { + wiilight(0); + Sys_Shutdown(); + } + else if (reset) + { + wiilight(0); + Sys_Reboot(); + } + + choice = GetChoice(); + } + + return choice; +} diff --git a/source/prompts/HomebrewPrompt.hpp b/source/prompts/HomebrewPrompt.hpp new file mode 100644 index 0000000..88815ef --- /dev/null +++ b/source/prompts/HomebrewPrompt.hpp @@ -0,0 +1,56 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef HOMEBREWPROMPT_HPP_ +#define HOMEBREWPROMPT_HPP_ + +#include "GUI/gui_scrollbar.hpp" +#include "GUI/Text.hpp" +#include "PromptWindow.hpp" + +class HomebrewPrompt : public PromptWindow, public sigslot::has_slots<> +{ + public: + HomebrewPrompt(const char *name, const char *coder, const char *version, + const char *release_date, const char *long_description, + GuiImageData * iconImgData, u64 filesize); + virtual ~HomebrewPrompt(); + int MainLoop(); + private: + void onListChange(int SelItem, int SelInd); + + GuiImageData *whiteBox; + + GuiImage *whiteBoxImg; + GuiImage *iconImg; + + GuiText *nameTxt; + GuiText *coderTxt; + GuiText *versionTxt; + GuiText *release_dateTxt; + GuiText *filesizeTxt; + Text *long_descriptionTxt; + GuiScrollbar *scrollBar; +}; + +#endif diff --git a/source/prompts/ProgressWindow.cpp b/source/prompts/ProgressWindow.cpp new file mode 100644 index 0000000..97d999f --- /dev/null +++ b/source/prompts/ProgressWindow.cpp @@ -0,0 +1,501 @@ +/**************************************************************************** + * ProgressWindow + * USB Loader GX 2009 + * + * ProgressWindow.cpp + ***************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "menu/menus.h" +#include "sys.h" +#include "language/gettext.h" +#include "GUI/gui.h" +#include "prompts/ProgressWindow.h" +#include "usbloader/wbfs.h" +#include "themes/CTheme.h" +#include "utils/timer.h" +#include "utils/tools.h" + +extern float gamesize; +extern int install_abort_signal; + +/*** Variables used only in this file ***/ +static const float fFilterTime = 15.0f; // seconds +static lwp_t progressthread = LWP_THREAD_NULL; +static bool CancelEnabled = false; +static bool progressCanceled = false; +static char progressTitle[75]; +static char progressMsg1[75]; +static char progressMsg2[75]; +static Timer ProgressTimer; +static int showProgress = 0; +static s64 progressDone = 0.0f; +static s64 progressTotal = 0.0f; +static float fLastProgressDone = 0.0f; +static float fLastElapsedTime = 0.0f; +static float fSpeed = 0.0f; +static bool showTime = false; +static bool showSize = false; +static bool changed = true; +static bool changedMessages = true; + +/**************************************************************************** + * StartProgress + ***************************************************************************/ +extern "C" void StartProgress(const char * title, const char * msg1, const char * msg2, bool swSize, bool swTime) +{ + if(title) + strncpy(progressTitle, title, sizeof(progressTitle)-1); + else + progressTitle[0] = '\0'; + + if(msg1) + strncpy(progressMsg1, msg1, sizeof(progressMsg1)-1); + else + progressMsg1[0] = '\0'; + + if(msg2) + strncpy(progressMsg2, msg2, sizeof(progressMsg2)-1); + else + progressMsg2[0] = '\0'; + + fSpeed = 0.0f; + fLastElapsedTime = 0.0f; + fLastProgressDone = 0.0f; + progressTotal = progressDone = 0.0f; + progressCanceled = false; + showSize = swSize; + showTime = swTime; + showProgress = 1; + ProgressTimer.reset(); + + LWP_ResumeThread(progressthread); +} + +/**************************************************************************** + * ShowProgress + * + * Callbackfunction for updating the progress values + * Use this function as standard callback + ***************************************************************************/ +extern "C" void ShowProgress(s64 done, s64 total) +{ + if (done > total) + done = total; + + if(!done) + { + fLastElapsedTime = 0.0f; + fLastProgressDone = 0.0f; + progressTotal = progressDone = 0.0f; + ProgressTimer.reset(); + LWP_ResumeThread(progressthread); + showProgress = 1; + } + + if(total >= 0) + { + progressDone = done; + progressTotal = total; + } + changed = true; +} + +void ShowProgress(const char *msg2, s64 done, s64 total) +{ + if(msg2) + strncpy(progressMsg2, msg2, sizeof(progressMsg2)-1); + else + progressMsg2[0] = '\0'; + + ShowProgress(done, total); + changedMessages = true; +} + +void ShowProgress(const char *title, const char *msg1, const char *msg2, s64 done, s64 total, bool swSize, bool swTime) +{ + if(title) + strncpy(progressTitle, title, sizeof(progressTitle)-1); + else + progressTitle[0] = '\0'; + + if(msg1) + strncpy(progressMsg1, msg1, sizeof(progressMsg1)-1); + else + progressMsg1[0] = '\0'; + + if(msg2) + strncpy(progressMsg2, msg2, sizeof(progressMsg2)-1); + else + progressMsg2[0] = '\0'; + + showSize = swSize; + showTime = swTime; + + ShowProgress(done, total); + changedMessages = true; +} + +/**************************************************************************** + * ProgressStop + ***************************************************************************/ +extern "C" void ProgressStop() +{ + progressCanceled = false; + showProgress = 0; + progressTitle[0] = 0; + progressMsg1[0] = 0; + progressMsg2[0] = 0; + showTime = false; + showSize = false; + + // wait for thread to finish + while (!LWP_ThreadIsSuspended(progressthread)) + usleep(100); +} + +/**************************************************************************** + * ProgressCancelEnable + * + * Enable/disable the progress cancel button + ***************************************************************************/ +extern "C" void ProgressCancelEnable(bool enable) +{ + CancelEnabled = enable; +} + +/**************************************************************************** + * ProgressCanceled + ***************************************************************************/ +extern "C" bool ProgressCanceled() +{ + return progressCanceled; +} + +/**************************************************************************** + * UpdateProgressValues + ***************************************************************************/ +static void UpdateProgressValues(GuiImage *progressbarImg, GuiText *prTxt, GuiText *timeTxt, GuiText *speedTxt, GuiText *sizeTxt) +{ + if(!changed) + return; + + changed = false; + changedMessages = false; + + float done; + float total; + + if(gamesize > 0.0f && progressTotal > 0.0f) + { + done = ((float) progressDone / (float) progressTotal * gamesize); + total = gamesize; + + if(progressCanceled) + install_abort_signal = 1; + } + else + { + done = (float) progressDone; + total = (float) progressTotal; + } + + float fElapsedTime = ProgressTimer.elapsed(); + float fTimeDiff = fElapsedTime - fLastElapsedTime; + //! initialize filter to current value on 2nd run + if(fLastProgressDone == 0.0f && done > 0.0f && fTimeDiff > 0.0f) { + fSpeed = done / fTimeDiff; + } + else if(fTimeDiff > 0.0f) { + //! low pass filtering the speed + fSpeed += ((done - fLastProgressDone) - fSpeed * fTimeDiff) / fFilterTime; + //! store current elapse value for next cycle + fLastElapsedTime = fElapsedTime; + } + + s32 TimeLeft = 0, h = 0, m = 0, s = 0; + if(fSpeed > 0.0f) + TimeLeft = (total-done)/fSpeed; + + if(TimeLeft > 0) + { + h = TimeLeft / 3600; + m = (TimeLeft / 60) % 60; + s = TimeLeft % 60; + } + + float progressPercent; + if(total > 0.0f) + progressPercent = LIMIT(100.0f * done / total, 0.f, 100.f); + else + progressPercent = 100.0f; // total is 0 or below? i guess we are done... + + prTxt->SetTextf("%.2f", progressPercent); + + if (Settings.widescreen && Settings.wsprompt) + progressbarImg->SetSkew(0, 0, (progressbarImg->GetWidth() * progressPercent + - progressbarImg->GetWidth()) * Settings.WSFactor, + 0, (progressbarImg->GetWidth() * progressPercent + - progressbarImg->GetWidth()) * Settings.WSFactor, 0, 0, 0); + else + progressbarImg->SetSkew(0, 0, (progressbarImg->GetWidth() * progressPercent) + - progressbarImg->GetWidth(), 0, (progressbarImg->GetWidth() * progressPercent) + - progressbarImg->GetWidth(), 0, 0, 0); + + if (showTime == true) + { + timeTxt->SetTextf("%s %d:%02d:%02d", tr( "Time left:" ), (int)h, (int)m, (int)s); + } + + if (showSize == true) + { + if (total < MB_SIZE) + sizeTxt->SetTextf("%0.2fKB/%0.2fKB", done / KB_SIZE, total / KB_SIZE); + else if (total > MB_SIZE && total < GB_SIZE) + sizeTxt->SetTextf("%0.2fMB/%0.2fMB", done / MB_SIZE, total / MB_SIZE); + else + sizeTxt->SetTextf("%0.2fGB/%0.2fGB", done / GB_SIZE, total / GB_SIZE); + + speedTxt->SetTextf("%dKB/s", (int) (fSpeed/KB_SIZE)); + } + + //! store current done value for next cycle + fLastProgressDone = done; +} + +/**************************************************************************** + * ProgressWindow + * + * Opens a window, which displays progress to the user. Can either display a + * progress bar showing % completion, or a throbber that only shows that an + * action is in progress. + ***************************************************************************/ +static void ProgressWindow(const char *title, const char *msg1, const char *msg2) +{ + progressCanceled = false; + + usleep(500000); // wait to see if progress flag changes soon + if (!showProgress) return; + + const int ProgressPosY = 20; + + GuiWindow promptWindow(472, 320); + promptWindow.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + promptWindow.SetPosition(0, -10); + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData dialogBox(Resources::GetFile("dialogue_box.png"), Resources::GetFileSize("dialogue_box.png")); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + GuiImage dialogBoxImg(&dialogBox); + if (Settings.wsprompt) + { + dialogBoxImg.SetWidescreen(Settings.widescreen); + } + + GuiImageData progressbarOutline(Resources::GetFile("progressbar_outline.png"), Resources::GetFileSize("progressbar_outline.png")); + + GuiImage progressbarOutlineImg(&progressbarOutline); + if (Settings.wsprompt) + { + progressbarOutlineImg.SetWidescreen(Settings.widescreen); + } + progressbarOutlineImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + progressbarOutlineImg.SetPosition(35, ProgressPosY); + + GuiImageData progressbarEmpty(Resources::GetFile("progressbar_empty.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImage progressbarEmptyImg(&progressbarEmpty); + progressbarEmptyImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + progressbarEmptyImg.SetPosition(35, ProgressPosY); + progressbarEmptyImg.SetTileHorizontal(100); + + GuiImageData progressbar(Resources::GetFile("progressbar.png"), Resources::GetFileSize("progressbar.png")); + GuiImage progressbarImg(&progressbar); + progressbarImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + progressbarImg.SetPosition(35, ProgressPosY); + + GuiText titleTxt(title, 26, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + titleTxt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt.SetPosition(0, 50); + + GuiText msg1Txt(msg1, 22, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + msg1Txt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + msg1Txt.SetPosition(0, 90); + msg1Txt.SetMaxWidth(430, DOTTED); + + GuiText msg2Txt(msg2, 22, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + msg2Txt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + msg2Txt.SetPosition(0, 125); + msg2Txt.SetMaxWidth(430, DOTTED); + + GuiText prsTxt("%", 22, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + prsTxt.SetAlignment(ALIGN_RIGHT, ALIGN_MIDDLE); + prsTxt.SetPosition(-178, ProgressPosY); + + GuiText timeTxt((char*) NULL, 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + timeTxt.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + timeTxt.SetPosition(280, -50); + + GuiText sizeTxt((char*) NULL, 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + sizeTxt.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + sizeTxt.SetPosition(50, -50); + + GuiText speedTxt((char*) NULL, 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + speedTxt.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + speedTxt.SetPosition(50, -74); + + GuiText prTxt((char*) NULL, 22, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + prTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + prTxt.SetPosition(210, ProgressPosY); + + if ((Settings.wsprompt) && (Settings.widescreen)) /////////////adjust for widescreen + { + progressbarOutlineImg.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + progressbarOutlineImg.SetPosition(0, ProgressPosY); + progressbarEmptyImg.SetPosition(80, ProgressPosY); + progressbarEmptyImg.SetTileHorizontal(78); + progressbarImg.SetPosition(80, ProgressPosY); + msg1Txt.SetMaxWidth(380, DOTTED); + msg2Txt.SetMaxWidth(380, DOTTED); + + timeTxt.SetPosition(250, -50); + speedTxt.SetPosition(90, -74); + sizeTxt.SetPosition(90, -50); + } + + GuiText cancelTxt(tr( "Cancel" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + GuiImage cancelImg(&btnOutline); + const float cancelScale = 0.8f; + cancelImg.SetScale(cancelScale); + cancelTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + cancelTxt.SetPosition(cancelImg.GetWidth()/2*cancelScale-cancelTxt.GetTextWidth()/2, 0); + if (Settings.wsprompt) + { + cancelTxt.SetWidescreen(Settings.widescreen); + cancelImg.SetWidescreen(Settings.widescreen); + } + + GuiButton cancelBtn(&cancelImg, &cancelImg, ALIGN_LEFT, ALIGN_MIDDLE, 0, 0, &trigA, btnSoundOver, btnSoundClick2, 1); + cancelBtn.SetLabel(&cancelTxt); + cancelBtn.SetState(STATE_SELECTED); + cancelBtn.SetPosition(dialogBoxImg.GetWidth()/2-cancelImg.GetWidth()/2*cancelScale, ProgressPosY + 45); + + promptWindow.Append(&dialogBoxImg); + promptWindow.Append(&progressbarEmptyImg); + promptWindow.Append(&progressbarImg); + promptWindow.Append(&progressbarOutlineImg); + promptWindow.Append(&prTxt); + promptWindow.Append(&prsTxt); + if (title) promptWindow.Append(&titleTxt); + promptWindow.Append(&msg1Txt); + promptWindow.Append(&msg2Txt); + if (showTime) promptWindow.Append(&timeTxt); + if (showSize) + { + promptWindow.Append(&sizeTxt); + promptWindow.Append(&speedTxt); + } + if(CancelEnabled) + promptWindow.Append(&cancelBtn); + + HaltGui(); + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&promptWindow); + ResumeGui(); + + while (promptWindow.GetEffect() > 0) usleep(100); + + while (showProgress) + { + usleep(100000); + + if (shutdown) + Sys_Shutdown(); + if (reset) + Sys_Reboot(); + + if (changed) + { + if (changedMessages) + { + titleTxt.SetText(progressTitle); + msg1Txt.SetText(progressMsg1); + msg2Txt.SetText(progressMsg2); + + if(progressMsg1[0] != '\0' && progressMsg2[0] == '\0') { + msg1Txt.SetPosition(0, 120); + } + else if(progressMsg2[0] != '\0' && progressMsg1[0] == '\0') { + msg2Txt.SetPosition(0, 120); + } + else { + msg1Txt.SetPosition(0, 90); + msg2Txt.SetPosition(0, 125); + } + } + UpdateProgressValues(&progressbarImg, &prTxt, &timeTxt, &speedTxt, &sizeTxt); + } + + if(cancelBtn.GetState() == STATE_CLICKED) + { + progressCanceled = true; + cancelBtn.ResetState(); + } + } + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while (promptWindow.GetEffect() > 0) usleep(100); + + HaltGui(); + mainWindow->Remove(&promptWindow); + mainWindow->SetState(STATE_DEFAULT); + ResumeGui(); +} + +/**************************************************************************** + * ProgressThread + ***************************************************************************/ +static void * ProgressThread(void *arg) +{ + while (1) + { + if (!showProgress) LWP_SuspendThread(progressthread); + + ProgressWindow(progressTitle, progressMsg1, progressMsg2); + usleep(100); + } + return NULL; +} + +/**************************************************************************** + * InitProgressThread + * + * Startup Progressthread in idle prio + ***************************************************************************/ +void InitProgressThread() +{ + LWP_CreateThread(&progressthread, ProgressThread, NULL, NULL, 16384, 60); + + memset(progressTitle, 0, sizeof(progressTitle)); + memset(progressMsg1, 0, sizeof(progressMsg1)); + memset(progressMsg2, 0, sizeof(progressMsg2)); +} + +/**************************************************************************** + * ExitProgressThread + * + * Shutdown Progressthread + ***************************************************************************/ +void ExitProgressThread() +{ + LWP_JoinThread(progressthread, NULL); + progressthread = LWP_THREAD_NULL; +} diff --git a/source/prompts/ProgressWindow.h b/source/prompts/ProgressWindow.h new file mode 100644 index 0000000..af08579 --- /dev/null +++ b/source/prompts/ProgressWindow.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * ProgressWindow + * USB Loader GX 2009 + * + * ProgressWindow.h + ***************************************************************************/ + +#ifndef _PROGRESSWINDOW_H_ +#define _PROGRESSWINDOW_H_ + +#include + +#ifdef __cplusplus + +#define PROGRESS_CANCELED -12345 + +void InitProgressThread(); +void ExitProgressThread(); +void ShowProgress(const char *title, const char *msg1, const char *msg2, s64 done, s64 total, bool swSize = false, bool swTime = false); +void ShowProgress(const char *msg2, s64 done, s64 total); + +extern "C" +{ +#endif + +void ProgressCancelEnable(bool allowCancel); +void StartProgress(const char * title, const char * msg1, const char * msg2, bool swSize, bool swTime); +void ShowProgress(s64 done, s64 total); +bool ProgressCanceled(); +void ProgressStop(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/prompts/PromptWindow.cpp b/source/prompts/PromptWindow.cpp new file mode 100644 index 0000000..304879f --- /dev/null +++ b/source/prompts/PromptWindow.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "PromptWindow.hpp" +#include "menu/menus.h" +#include "settings/CSettings.h" +#include "themes/CTheme.h" + +PromptWindow::PromptWindow(const char *title, const char *msg) + : GuiWindow(472, 320) +{ + SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + SetPosition(0, -10); + + btnOutline = Resources::GetImageData("button_dialogue_box.png"); + dialogBox = Resources::GetImageData("dialogue_box.png"); + + width = dialogBox->GetWidth(); + height = dialogBox->GetHeight(); + + trigA = new GuiTrigger; + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigB = new GuiTrigger; + trigB->SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + dialogBoxImg = new GuiImage(dialogBox); + if(Settings.wsprompt) + dialogBoxImg->SetWidescreen(Settings.widescreen); + Append(dialogBoxImg); + + titleTxt = new GuiText(title, 26, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + titleTxt->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt->SetPosition(0, 55); + if(Settings.wsprompt && Settings.widescreen) + titleTxt->SetMaxWidth(width-140, DOTTED); + else + titleTxt->SetMaxWidth(width-40, DOTTED); + Append(titleTxt); + + msgTxt = new GuiText(msg, 22, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + msgTxt->SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + msgTxt->SetPosition(0, -40); + if(Settings.wsprompt && Settings.widescreen) + msgTxt->SetMaxWidth(width-140, WRAP); + else + msgTxt->SetMaxWidth(width-40, WRAP); + Append(msgTxt); + + SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); +} + +PromptWindow::~PromptWindow() +{ + ResumeGui(); + + SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while(parentElement && this->GetEffect() > 0) usleep(100); + + HaltGui(); + if(parentElement) + ((GuiWindow *) parentElement)->Remove(this); + parentElement = NULL; + + RemoveAll(); + + delete btnOutline; + delete dialogBox; + + delete trigA; + delete trigB; + + delete dialogBoxImg; + + delete titleTxt; + delete msgTxt; + + for(u32 i = 0; i < Button.size(); ++i) + { + delete ButtonTxt[i]; + delete ButtonImg[i]; + delete Button[i]; + } + + ResumeGui(); +} + +void PromptWindow::PositionButtons() +{ + if (Settings.wsprompt && Settings.widescreen) + { + switch(Button.size()) + { + default: + break; + case 1: + Button[0]->SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + Button[0]->SetPosition(0, -55); + break; + case 2: + Button[0]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Button[0]->SetPosition(70, -55); + Button[1]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Button[1]->SetPosition(-70, -55); + break; + case 3: + Button[0]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Button[0]->SetPosition(70, -120); + Button[1]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Button[1]->SetPosition(-70, -120); + Button[2]->SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + Button[2]->SetPosition(0, -55); + break; + case 4: + Button[0]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Button[0]->SetPosition(70, -120); + Button[1]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Button[1]->SetPosition(-70, -120); + Button[2]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Button[2]->SetPosition(70, -55); + Button[3]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Button[3]->SetPosition(-70, -55); + break; + } + } + else + { + switch(Button.size()) + { + default: + break; + case 1: + Button[0]->SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + Button[0]->SetPosition(0, -55); + break; + case 2: + Button[0]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Button[0]->SetPosition(50, -55); + Button[1]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Button[1]->SetPosition(-50, -55); + break; + case 3: + Button[0]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Button[0]->SetPosition(50, -120); + Button[1]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Button[1]->SetPosition(-50, -120); + Button[2]->SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + Button[2]->SetPosition(0, -55); + break; + case 4: + Button[0]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Button[0]->SetPosition(50, -120); + Button[1]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Button[1]->SetPosition(-50, -120); + Button[2]->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + Button[2]->SetPosition(50, -55); + Button[3]->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + Button[3]->SetPosition(-50, -55); + break; + } + } +} + +void PromptWindow::AddButton(const char *text) +{ + int size = Button.size(); + if(size > 3) + return; + + ButtonTxt.resize(size+1); + ButtonImg.resize(size+1); + Button.resize(size+1); + + ButtonTxt[size] = new GuiText(text, 20, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + ButtonImg[size] = new GuiImage(btnOutline); + if (Settings.wsprompt) + { + ButtonTxt[size]->SetWidescreen(Settings.widescreen); + ButtonImg[size]->SetWidescreen(Settings.widescreen); + } + + Button[size] = new GuiButton(ButtonImg[size], ButtonImg[size], 0, 3, 0, 0, trigA, btnSoundOver, btnSoundClick2, 1); + Button[size]->SetLabel(ButtonTxt[size]); + Button[size]->SetState(STATE_SELECTED); + Button[size]->SetTrigger(1, trigB); + Append(Button[size]); + + if(size > 0) + Button[size-1]->SetTrigger(1, NULL); + + PositionButtons(); +} + +void PromptWindow::RemoveButton() +{ + Remove(Button[Button.size()-1]); + + delete ButtonTxt[ButtonTxt.size()-1]; + delete ButtonImg[ButtonImg.size()-1]; + delete Button[Button.size()-1]; + + ButtonTxt.pop_back(); + ButtonImg.pop_back(); + Button.pop_back(); + + if(ButtonImg.size() > 0) + Button[ButtonImg.size()-1]->SetTrigger(1, trigB); + + PositionButtons(); +} + +void PromptWindow::RemoveButton(int i) +{ + if(i >= 0 && i < (int) Button.size()) + Remove(Button[i]); +} + +int PromptWindow::GetChoice() +{ + for(u32 i = 0; i < Button.size(); ++i) + { + if(Button[i]->GetState() == STATE_CLICKED) + { + Button[i]->ResetState(); + return (i+1 != Button.size()) ? i+1 : 0; + } + } + + return -1; +} diff --git a/source/prompts/PromptWindow.hpp b/source/prompts/PromptWindow.hpp new file mode 100644 index 0000000..6bd14ab --- /dev/null +++ b/source/prompts/PromptWindow.hpp @@ -0,0 +1,65 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _PROMPTWINDOW_HPP_ +#define _PROMPTWINDOW_HPP_ + +#include "GUI/gui.h" + +class PromptWindow : public GuiWindow +{ + public: + //! Constructor + PromptWindow(const char *title = 0, const char *msg = 0); + //! Destructor + virtual ~PromptWindow(); + //! Set title text + void SetTitle(const char *text) { titleTxt->SetText(text); }; + //! Set message text + void SetMessageText(const char *text) { msgTxt->SetText(text); }; + //! Add new button and rearrange all buttons position. MAX 4 buttons. + void AddButton(const char *text); + //! Removes/deletes the last button and rearranges positions + void RemoveButton(); + //! Removes a button in the position from the window but does not completely delete it + void RemoveButton(int pos); + //! Default function to get the button pressed + int GetChoice(); + //! Forbid = operation + PromptWindow& operator=(const PromptWindow &w); + protected: + void PositionButtons(); + + GuiImageData *btnOutline; + GuiImageData *dialogBox; + GuiImage *dialogBoxImg; + GuiText *titleTxt; + GuiText *msgTxt; + GuiTrigger *trigA; + GuiTrigger *trigB; + std::vector ButtonTxt; + std::vector ButtonImg; + std::vector Button; +}; + +#endif diff --git a/source/prompts/PromptWindows.cpp b/source/prompts/PromptWindows.cpp new file mode 100644 index 0000000..7aba2c5 --- /dev/null +++ b/source/prompts/PromptWindows.cpp @@ -0,0 +1,1542 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Controls/DeviceHandler.hpp" +#include "usbloader/wbfs.h" +#include "usbloader/wdvd.h" +#include "usbloader/usbstorage2.h" +#include "usbloader/GameList.h" +#include "GameCube/GCGames.h" +#include "language/gettext.h" +#include "GUI/gui.h" +#include "GUI/gui_numpad.h" +#include "GUI/gui_diskcover.h" +#include "GUI/Text.hpp" +#include "settings/CGameStatistics.h" +#include "settings/GameTitles.h" +#include "network/networkops.h" +#include "network/update.h" +#include "network/http.h" +#include "prompts/PromptWindows.h" +#include "prompts/PromptWindow.hpp" +#include "prompts/gameinfo.h" +#include "themes/CTheme.h" +#include "utils/StringTools.h" +#include "utils/tools.h" +#include "mload/mload.h" +#include "FileOperations/fileops.h" +#include "menu/menus.h" +#include "sys.h" +#include "wpad.h" +#include "wad/wad.h" +#include "zlib.h" +#include "svnrev.h" +#include "audio.h" +#include "language/UpdateLanguage.h" +#include "system/IosLoader.h" +#include "gecko.h" +#include "lstub.h" + +static const char * DMLVersions[] = +{ + //! sorted by internal release date. see IosLoader.h + "", // Original MIOS + "r51-", // old DML r51- + "r52", // old DML r52 + "v0.1", // QuadForce v0.1 + "v1.2", // DML 1.2 + "v1.4", // DML 1.4 + "v1.4b", // DML 1.4b + "v1.5", // DML 1.5 + "v2.0.x", // DM 2.0 + "v2.1", // DML 2.1 + "v2.2.x", // DM 2.2 + "v2.2.2", // DM 2.2 update 2 + "v2.2", // DML 2.2 + "v2.2.1", // DML 2.2.1 + "v2.3", // DML 2.3 (mirror link) + "v2.3", // DM 2.3 + "v2.3", // DML 2.3 (main link) + "v2.4", // DM 2.4 + "v2.4", // DML 2.4 + "v2.5", // DM 2.5 + "v2.5", // DML 2.5 + "v2.6.0", // DM 2.6 + "v2.6", // DML 2.6 + "v2.6.1", // DM 2.6 update 1 + "v2.7", // DM 2.7 + "v2.7", // DML 2.7 + "v2.8", // DML 2.8 + "v2.8", // DM 2.8 + "v2.9", // DML 2.9 + "v2.9", // DM 2.9 + "v2.0", // QuadForce v2.0 + "v3.0", // QuadForce v3.0 + "v4.0", // QuadForce v4.0 SD + "v2.10", // DML 2.10 + "v2.10", // DM 2.10 + "v4.1", // QuadForce v4.1 USB + "v2.11+", // DML 2.11 + "v2.11+", // DM 2.11 +}; + + +/**************************************************************************** + * OnScreenNumpad + * + * Opens an on-screen numpad window, with the data entered being stored + * into the specified variable. + ***************************************************************************/ +int OnScreenNumpad(char * var, u32 maxlen) +{ + int save = -1; + + GuiNumpad numpad(var, maxlen); + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetSimpleTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + GuiText okBtnTxt(tr( "OK" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + GuiImage okBtnImg(&btnOutline); + if (Settings.wsprompt) + { + okBtnTxt.SetWidescreen(Settings.widescreen); + okBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton okBtn(&okBtnImg, &okBtnImg, 0, 4, 5, -15, &trigA, btnSoundOver, btnSoundClick2, 1); + okBtn.SetLabel(&okBtnTxt); + GuiText cancelBtnTxt(tr( "Cancel" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + GuiImage cancelBtnImg(&btnOutline); + if (Settings.wsprompt) + { + cancelBtnTxt.SetWidescreen(Settings.widescreen); + cancelBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton cancelBtn(&cancelBtnImg, &cancelBtnImg, 1, 4, -5, -15, &trigA, btnSoundOver, btnSoundClick2, 1); + cancelBtn.SetLabel(&cancelBtnTxt); + cancelBtn.SetTrigger(&trigB); + + numpad.Append(&okBtn); + numpad.Append(&cancelBtn); + + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&numpad); + ResumeGui(); + + while (save == -1) + { + usleep(50000); + + if (okBtn.GetState() == STATE_CLICKED) + save = 1; + else if (cancelBtn.GetState() == STATE_CLICKED) + save = 0; + } + + if (save == 1) + { + snprintf(var, maxlen, "%s", numpad.GetText()); + + // convert all , to . characters + for(u32 i = 0; i < maxlen; ++i) + { + if(var[i] == ',') + var[i] = '.'; + } + } + + HaltGui(); + mainWindow->Remove(&numpad); + mainWindow->SetState(STATE_DEFAULT); + ResumeGui(); + gprintf("\t%s", (save == 1 ? "saved" : "discarded")); + return save; +} + +/**************************************************************************** + * OnScreenKeyboard + * + * Opens an on-screen keyboard window, with the data entered being stored + * into the specified variable. + ***************************************************************************/ +int OnScreenKeyboard(char * var, u32 maxlen, int min, bool hide) +{ + int save = -1; + + gprintf("\nOnScreenKeyboard(%s, %i, %i) \n\tkeyset = %i", var, maxlen, min, Settings.keyset); + + GuiKeyboard keyboard(var, maxlen, min, Settings.keyset); + keyboard.SetVisibleText(!hide); + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetSimpleTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + GuiText okBtnTxt(tr( "OK" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + GuiImage okBtnImg(&btnOutline); + if (Settings.wsprompt) + { + okBtnTxt.SetWidescreen(Settings.widescreen); + okBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton okBtn(&okBtnImg, &okBtnImg, 0, 4, 5, 15, &trigA, btnSoundOver, btnSoundClick2, 1); + okBtn.SetLabel(&okBtnTxt); + GuiText cancelBtnTxt(tr( "Cancel" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + GuiImage cancelBtnImg(&btnOutline); + if (Settings.wsprompt) + { + cancelBtnTxt.SetWidescreen(Settings.widescreen); + cancelBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton cancelBtn(&cancelBtnImg, &cancelBtnImg, 1, 4, -5, 15, &trigA, btnSoundOver, btnSoundClick2, 1); + cancelBtn.SetLabel(&cancelBtnTxt); + cancelBtn.SetTrigger(&trigB); + + keyboard.Append(&okBtn); + keyboard.Append(&cancelBtn); + + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&keyboard); + ResumeGui(); + + while (save == -1) + { + usleep(50000); + + if (okBtn.GetState() == STATE_CLICKED) + save = 1; + else if (cancelBtn.GetState() == STATE_CLICKED) + save = 0; + } + + if (save) + { + snprintf(var, maxlen, "%s", keyboard.GetText()); + } + + HaltGui(); + mainWindow->Remove(&keyboard); + mainWindow->SetState(STATE_DEFAULT); + ResumeGui(); + gprintf("\t%s", (save ? "saved" : "discarded")); + return save; +} + +/**************************************************************************** + * WindowCredits + * Display credits + ***************************************************************************/ +void WindowCredits() +{ + gprintf("WindowCredits()\n"); + + int angle = 0; + GuiSound * creditsMusic = NULL; + + bgMusic->Pause(); + + creditsMusic = new GuiSound(Resources::GetFile("credits_music.ogg"), Resources::GetFileSize("credits_music.ogg"), 55); + creditsMusic->SetVolume(60); + creditsMusic->SetLoop(1); + creditsMusic->Play(); + + GuiTrigger trigA; + trigA.SetButtonOnlyTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + GuiButton backBtn(0, 0); + backBtn.SetPosition(-20, -20); + backBtn.SetTrigger(&trigA); + backBtn.SetTrigger(&trigB); + + u32 i = 0; + int y = 20; + float oldFontScale = Settings.FontScaleFactor; + Settings.FontScaleFactor = 1.0f; + + GuiWindow creditsWindow(screenwidth, screenheight); + GuiWindow creditsWindowBox(580, 448); + creditsWindowBox.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + + GuiImageData creditsBox(Resources::GetFile("credits_bg.png"), Resources::GetFileSize("credits_bg.png")); + GuiImage creditsBoxImg(&creditsBox); + creditsBoxImg.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + creditsWindowBox.Append(&creditsBoxImg); + + GuiImageData star(Resources::GetFile("little_star.png"), Resources::GetFileSize("little_star.png")); + GuiImage starImg(&star); + starImg.SetWidescreen(Settings.widescreen); //added + starImg.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + starImg.SetPosition(505, 350); + + std::vector txt; + + const u8 *creditsFont = Resources::GetFile("font.ttf"); + u32 creditsFontSize = Resources::GetFileSize("font.ttf"); + + GuiText * currentTxt = new GuiText(tr( "Credits" ), 28, ( GXColor ) {255, 255, 255, 255}); + currentTxt->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + currentTxt->SetPosition(0, 8); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + + char SvnRev[80]; +#ifdef FULLCHANNEL + snprintf(SvnRev, sizeof(SvnRev), "Rev%sc IOS%u (Rev %u)%s", GetRev(), IOS_GetVersion(), IOS_GetRevision(), (*(vu32*)0xcd800064 == 0xFFFFFFFF)? " + AHB" : "" ); +#else + snprintf(SvnRev, sizeof(SvnRev), "Rev%s IOS%u (Rev %u)%s", GetRev(), (unsigned int)IOS_GetVersion(), (int)IOS_GetRevision(), (*(vu32*)0xcd800064 == 0xFFFFFFFF)? " + AHB" : "" ); +#endif + + char IosInfo[80] = ""; + iosinfo_t * info = IosLoader::GetIOSInfo(IOS_GetVersion()); + if(info) + snprintf(IosInfo, sizeof(IosInfo), "(%s v%i%s base%i)", info->name, (int)info->version, info->versionstring, (int)info->baseios); + + // Check if DIOS MIOS (Lite) is available + char GCInfo[80] = ""; + int currentMIOS = IosLoader::GetMIOSInfo(); + if(currentMIOS == DIOS_MIOS) + snprintf(GCInfo, sizeof(GCInfo), "DIOS-MIOS %s", DMLVersions[IosLoader::GetDMLVersion()]); + else if (currentMIOS == DIOS_MIOS_LITE) + snprintf(GCInfo, sizeof(GCInfo), "DIOS-MIOS Lite %s", DMLVersions[IosLoader::GetDMLVersion()]); + else if (currentMIOS == QUADFORCE) + snprintf(GCInfo, sizeof(GCInfo), "QuadForce %s", DMLVersions[IosLoader::GetDMLVersion()]); + else if (currentMIOS == QUADFORCE_USB) + snprintf(GCInfo, sizeof(GCInfo), "QuadForce USB %s", DMLVersions[IosLoader::GetDMLVersion()]); + + // Check if Devolution is available + char DEVO_loader_path[100]; + snprintf(DEVO_loader_path, sizeof(DEVO_loader_path), "%sloader.bin", Settings.DEVOLoaderPath); + FILE *f = fopen(DEVO_loader_path, "rb"); + if(f) + { + char version[5]; + fseek(f, 23, SEEK_SET); + fread(version, 1, 4, f); + fclose(f); + char *ptr = strchr(version, ' '); + if(ptr) *ptr = 0; + else version[4] = 0; + snprintf(GCInfo, sizeof(GCInfo), "%s%sDevolution r%d", GCInfo, strlen(GCInfo) > 1 ? " / " : "", atoi(version)); + } + + // Check if Nintendont is available + char GCInfo2[80] = ""; + char NINVersion[7]= ""; + nintendontVersion(Settings.NINLoaderPath, NINVersion, sizeof(NINVersion)); + if(strlen(NINVersion) > 0) + { + snprintf(GCInfo2, sizeof(GCInfo2), "Nintendont v%.6s", NINVersion ); + } + else + { + char NINBuildDate[21] = ""; + if(nintendontBuildDate(Settings.NINLoaderPath, NINBuildDate)) + snprintf(GCInfo2, sizeof(GCInfo2), "Nintendont Built %.20s", NINBuildDate ); + } + + // Header - Top left + currentTxt = new GuiText(GCInfo2, 16, ( GXColor ) {255, 255, 255, 255}); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(0, strlen(GCInfo) > 0 ? y-10 : y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + + // Header - Bottom left + currentTxt = new GuiText(GCInfo, 16, ( GXColor ) {255, 255, 255, 255}); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(0, y+6); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + + // Header - Top right + currentTxt = new GuiText(SvnRev, 16, ( GXColor ) {255, 255, 255, 255}); + currentTxt->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); + currentTxt->SetPosition(0, (info || currentMIOS > DEFAULT_MIOS) ? y-10 : y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + + // Header - Bottom right + currentTxt = new GuiText(IosInfo, 16, ( GXColor ) {255, 255, 255, 255}); + currentTxt->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); + currentTxt->SetPosition(0, y+6); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 34; + + currentTxt = new GuiText("USB Loader GX", 24, ( GXColor ) {255, 255, 255, 255}); + currentTxt->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + currentTxt->SetPosition(0, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 24; + + currentTxt = new GuiText(tr( "Unofficial Site:" ), 20, ( GXColor ) {255, 255, 255, 255}); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(10, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + + currentTxt = new GuiText("https://github.com/AsayuGit/USBLoaderGX", 20, ( GXColor ) {255, 255, 255, 255}); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(160, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 22; + + GuiText::SetPresets(20, ( GXColor ) {255, 255, 255, 255}, 3000, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP, ALIGN_LEFT, ALIGN_TOP); + + currentTxt = new GuiText(tr( "Coding:" )); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(10, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + + currentTxt = new GuiText("Cyan / Dimok / nIxx / giantpune / ardi"); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(160, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 20; + + currentTxt = new GuiText("hungyip84 / DrayX7 / lustar / r-win / Asayu"); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(160, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 22; + + char text[100]; + + currentTxt = new GuiText(tr( "Design:" )); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(10, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + + currentTxt = new GuiText("cyrex / NeoRame"); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(160, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 22; + + currentTxt = new GuiText(""); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(10, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + + currentTxt = new GuiText(""); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(160, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 22; + + currentTxt = new GuiText(tr( "Big thanks to:" )); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(10, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + + sprintf(text, "lustar %s", tr( "for GameTDB and hosting covers / disc images" )); + currentTxt = new GuiText(text); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(160, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 20; + + sprintf(text, "Cyan and Shano56 %s", tr( "for their work on the wiki page" )); + currentTxt = new GuiText(text); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(160, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 20; + + sprintf(text, "Kinyo %s", tr( "and translators for language files updates" )); + currentTxt = new GuiText(text); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(160, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 20; + + sprintf(text, "Deak Phreak %s", tr( "for hosting the themes" )); + currentTxt = new GuiText(text); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(160, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 24; + + currentTxt = new GuiText(tr( "Special thanks to:" )); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(10, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 20; + + sprintf(text, "Waninkoko, Kwiirk & Hermes %s", tr( "for the USB Loader source" )); + currentTxt = new GuiText(text); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(10, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 20; + + sprintf(text, "Tantric %s", tr( "for his awesome tool LibWiiGui" )); + currentTxt = new GuiText(text); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(10, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 20; + + sprintf(text, "Fishears/Nuke %s", tr( "for Ocarina" )); + currentTxt = new GuiText(text); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(10, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 20; + + sprintf(text, "WiiPower %s", tr( "for diverse patches" )); + currentTxt = new GuiText(text); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(10, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 20; + + sprintf(text, "Oggzee %s", tr( "for FAT/NTFS support" )); + currentTxt = new GuiText(text); + currentTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + currentTxt->SetPosition(10, y); + currentTxt->SetFont(creditsFont, creditsFontSize); + txt.push_back(currentTxt); + y += 20; + + for (i = 0; i < txt.size(); i++) + creditsWindowBox.Append(txt[i]); + + creditsWindow.Append(&creditsWindowBox); + creditsWindow.Append(&starImg); + creditsWindow.Append(&backBtn); + + creditsWindow.SetEffect(EFFECT_FADE, 30); + + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&creditsWindow); + ResumeGui(); + + while(backBtn.GetState() != STATE_CLICKED) + { + usleep(12000); + + if (shutdown) + Sys_Shutdown(); + if (reset) + Sys_Reboot(); + + angle++; + if (angle > 360) angle = 0; + starImg.SetAngle(angle); + } + backBtn.ResetState(); + + creditsMusic->Stop(); + + delete creditsMusic; + + creditsWindow.SetEffect(EFFECT_FADE, -30); + while (creditsWindow.GetEffect() > 0) + usleep(100); + HaltGui(); + mainWindow->Remove(&creditsWindow); + mainWindow->SetState(STATE_DEFAULT); + for (i = 0; i < txt.size(); i++) + { + delete txt[i]; + txt[i] = NULL; + } + Settings.FontScaleFactor = oldFontScale; + ResumeGui(); + + bgMusic->Resume(); +} + +/**************************************************************************** + * WindowScreensaver + * Display screensaver + ***************************************************************************/ +int WindowScreensaver() +{ + gprintf("WindowScreenSaver()\n"); + bool exit = false; + + /* initialize random seed: */ + srand(time(NULL)); + + GuiImageData GXlogo(Resources::GetFile("gxlogo.png"), Resources::GetFileSize("gxlogo.png"));//uncomment for themable screensaver + //GuiImageData GXlogo(gxlogo_png);//comment for themable screensaver + GuiImage GXlogoImg(&GXlogo); + GXlogoImg.SetPosition(172, 152); + GXlogoImg.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + + GuiImage BackgroundImg(640, 480, ( GXColor ) {0, 0, 0, 255}); + BackgroundImg.SetPosition(0, 0); + BackgroundImg.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + + GuiWindow screensaverWindow(screenwidth, screenheight); + screensaverWindow.Append(&BackgroundImg); + screensaverWindow.Append(&GXlogoImg); + + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&screensaverWindow); + ResumeGui(); + + while (!exit) + { + if (shutdown) + Sys_Shutdown(); + if (reset) + Sys_Reboot(); + + if(!ControlActivityTimeout()) + break; + + /* Set random position */ + GXlogoImg.SetPosition((rand() % 345), (rand() % 305)); + + sleep(4); + } + + HaltGui(); + mainWindow->Remove(&screensaverWindow); + mainWindow->SetState(STATE_DEFAULT); + ResumeGui(); + return 1; +} + +/**************************************************************************** + * WindowPrompt + * + * Displays a prompt window to user, with information, an error message, or + * presenting a user with a choice of up to 4 Buttons. + * + * Give him 1 Title, 1 Subtitle and 4 Buttons + * If title/subtitle or one of the buttons is not needed give him a 0 on that + * place. + ***************************************************************************/ +int WindowPrompt(const char *title, const char *msg, const char *btn1Label, const char *btn2Label, + const char *btn3Label, const char *btn4Label, int wait) +{ + int choice = -1; + int count = wait; + gprintf("WindowPrompt( %s, %s, %s, %s, %s, %s, %i ): ", title, msg, btn1Label, btn2Label, btn3Label, btn4Label, wait); + + PromptWindow *Window = new PromptWindow; + Window->SetTitle(title); + Window->SetMessageText(msg); + if(btn1Label) + Window->AddButton(btn1Label); + if(btn2Label) + Window->AddButton(btn2Label); + if(btn3Label) + Window->AddButton(btn3Label); + if(btn4Label) + Window->AddButton(btn4Label); + + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(Window); + ResumeGui(); + + while (choice == -1) + { + VIDEO_WaitVSync(); + + if (shutdown) + { + wiilight(0); + Sys_Shutdown(); + } + if (reset) + Sys_Reboot(); + + choice = Window->GetChoice(); + + if (count > 0) count--; + if (count == 0) choice = 1; + } + + delete Window; + + mainWindow->SetState(STATE_DEFAULT); + gprintf(" %i\n", choice); + + return choice; +} + +/**************************************************************************** + * WindowExitPrompt + * + * Displays a prompt window to user, with information, an error message, or + * presenting a user with a choice of up to 4 Buttons. + * + * Give him 1 Titel, 1 Subtitel and 4 Buttons + * If titel/subtitle or one of the buttons is not needed give him a 0 on that + * place. + ***************************************************************************/ +int WindowExitPrompt() +{ + gprintf("WindowExitPrompt()\n"); + + bgMusic->Pause(); + + GuiSound * homein = NULL; + homein = new GuiSound(Resources::GetFile("menuin.ogg"), Resources::GetFileSize("menuin.ogg"), Settings.sfxvolume); + homein->SetVolume(Settings.sfxvolume); + homein->SetLoop(0); + homein->Play(); + + GuiSound * homeout = NULL; + homeout = new GuiSound(Resources::GetFile("menuout.ogg"), Resources::GetFileSize("menuout.ogg"), Settings.sfxvolume); + homeout->SetVolume(Settings.sfxvolume); + homeout->SetLoop(0); + + int choice = -1; + + u64 oldstub = getStubDest(); + loadStub(); + if (oldstub != 0x00010001554c4e52ll && oldstub != 0x00010001554e454fll) Set_Stub(oldstub); + + GuiWindow promptWindow(640, 480); + promptWindow.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + promptWindow.SetPosition(0, 0); + GuiImageData top(Resources::GetFile("exit_top.png"), Resources::GetFileSize("exit_top.png")); + GuiImageData topOver(Resources::GetFile("exit_top_over.png"), Resources::GetFileSize("exit_top_over.png")); + GuiImageData bottom(Resources::GetFile("exit_bottom.png"), Resources::GetFileSize("exit_bottom.png")); + GuiImageData bottomOver(Resources::GetFile("exit_bottom_over.png"), Resources::GetFileSize("exit_bottom_over.png")); + GuiImageData button(Resources::GetFile("exit_button.png"), Resources::GetFileSize("exit_button.png")); + GuiImageData wiimote(Resources::GetFile("wiimote.png"), Resources::GetFileSize("wiimote.png")); + GuiImageData close(Resources::GetFile("closebutton.png"), Resources::GetFileSize("closebutton.png")); + + GuiImageData battery(Resources::GetFile("battery_white.png"), Resources::GetFileSize("battery_white.png")); + GuiImageData batteryBar(Resources::GetFile("battery_bar_white.png"), Resources::GetFileSize("battery_bar_white.png")); + GuiImageData batteryRed(Resources::GetFile("battery_red.png"), Resources::GetFileSize("battery_red.png")); + GuiImageData batteryBarRed(Resources::GetFile("battery_bar_red.png"), Resources::GetFileSize("battery_bar_red.png")); + + int i = 0, ret = 0, level; + char txt[3]; + GuiText * batteryTxt[4]; + GuiImage * batteryImg[4]; + GuiImage * batteryBarImg[4]; + GuiButton * batteryBtn[4]; + + for (i = 0; i < 4; i++) + { + sprintf(txt, "P%d", i + 1); + + batteryTxt[i] = new GuiText(txt, 22, ( GXColor ) {255, 255, 255, 255}); + batteryTxt[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + batteryImg[i] = new GuiImage(&battery); + batteryImg[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + batteryImg[i]->SetPosition(36, 0); + batteryImg[i]->SetTileHorizontal(0); + batteryBarImg[i] = new GuiImage(&batteryBar); + batteryBarImg[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + batteryBarImg[i]->SetPosition(33, 0); + + batteryBtn[i] = new GuiButton(40, 20); + batteryBtn[i]->SetLabel(batteryTxt[i]); + batteryBtn[i]->SetImage(batteryBarImg[i]); + batteryBtn[i]->SetIcon(batteryImg[i]); + batteryBtn[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + batteryBtn[i]->SetRumble(false); + batteryBtn[i]->SetAlpha(70); + batteryBtn[i]->SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_IN, 50); + } + + batteryBtn[0]->SetPosition(180, 150); + batteryBtn[1]->SetPosition(284, 150); + batteryBtn[2]->SetPosition(388, 150); + batteryBtn[3]->SetPosition(494, 150); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + GuiTrigger trigHome; + trigHome.SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, 0); + + GuiText titleTxt(tr( "HOME Menu" ), 36, ( GXColor ) {255, 255, 255, 255}); + titleTxt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt.SetPosition(-180, 40); + titleTxt.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + + GuiText closeTxt(tr( "Close" ), 28, ( GXColor ) {0, 0, 0, 255}); + closeTxt.SetPosition(10, 3); + GuiImage closeImg(&close); + if (Settings.wsprompt) + { + closeTxt.SetWidescreen(Settings.widescreen); + closeImg.SetWidescreen(Settings.widescreen); + } + GuiButton closeBtn(close.GetWidth(), close.GetHeight()); + closeBtn.SetImage(&closeImg); + closeBtn.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + closeBtn.SetPosition(190, 30); + closeBtn.SetLabel(&closeTxt); + closeBtn.SetRumble(false); + closeBtn.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + + GuiImage btn1Img(&top); + GuiImage btn1OverImg(&topOver); + GuiButton btn1(&btn1Img, &btn1OverImg, 0, 3, 0, 0, &trigA, btnSoundOver, btnSoundClick2, 0); + btn1.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + + GuiText btn2Txt(tr( "Homebrew Channel" ), 26, ( GXColor ) {0, 0, 0, 255}); + if (Settings.HomeMenu == HOME_MENU_SYSTEM) + { + btn2Txt.SetText(tr( "Wii Menu" )); + } + else if (Settings.HomeMenu == HOME_MENU_FULL) + { + btn2Txt.SetText(tr( "Exit" )); + } + GuiImage btn2Img(&button); + if (Settings.wsprompt) + { + btn2Txt.SetWidescreen(Settings.widescreen); + btn2Img.SetWidescreen(Settings.widescreen); + } + GuiButton btn2(&btn2Img, &btn2Img, 2, 5, -150, 0, &trigA, btnSoundOver, btnSoundClick2, 1); + btn2.SetLabel(&btn2Txt); + btn2.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 50); + btn2.SetRumble(false); + btn2.SetPosition(-150, 0); + + GuiText btn3Txt(tr( "Wii Menu" ), 26, ( GXColor ) {0, 0, 0, 255}); + if (Settings.HomeMenu == HOME_MENU_SYSTEM) + { + btn3Txt.SetText(tr( "Reset" )); + } + else if (Settings.HomeMenu == HOME_MENU_FULL) + { + btn3Txt.SetText(tr( "Shutdown Wii" )); + } + GuiImage btn3Img(&button); + if (Settings.wsprompt) + { + btn3Txt.SetWidescreen(Settings.widescreen); + btn3Img.SetWidescreen(Settings.widescreen); + } + GuiButton btn3(&btn3Img, &btn3Img, 2, 5, 150, 0, &trigA, btnSoundOver, btnSoundClick2, 1); + btn3.SetLabel(&btn3Txt); + btn3.SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 50); + btn3.SetRumble(false); + btn3.SetPosition(150, 0); + + GuiImage btn4Img(&bottom); + GuiImage btn4OverImg(&bottomOver); + GuiButton btn4(&btn4Img, &btn4OverImg, 0, 4, 0, 0, &trigA, btnSoundOver, btnSoundClick2, 0); + btn4.SetTrigger(&trigB); + btn4.SetTrigger(&trigHome); + btn4.SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_IN, 50); + + GuiImage wiimoteImg(&wiimote); + if (Settings.wsprompt) + { + wiimoteImg.SetWidescreen(Settings.widescreen); + } + wiimoteImg.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + wiimoteImg.SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_IN, 50); + wiimoteImg.SetPosition(50, 210); + + promptWindow.Append(&btn2); + promptWindow.Append(&btn3); + promptWindow.Append(&btn4); + promptWindow.Append(&btn1); + promptWindow.Append(&closeBtn); + promptWindow.Append(&titleTxt); + promptWindow.Append(&wiimoteImg); + + promptWindow.Append(batteryBtn[0]); + promptWindow.Append(batteryBtn[1]); + promptWindow.Append(batteryBtn[2]); + promptWindow.Append(batteryBtn[3]); + + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&promptWindow); + ResumeGui(); + + while (choice == -1) + { + VIDEO_WaitVSync(); + + for (i = 0; i < 4; i++) + { + if (WPAD_Probe(i, NULL) == WPAD_ERR_NONE) // controller connected + { + level = (userInput[i].wpad.battery_level / 100.0) * 4; + if (level > 4) level = 4; + + if (level <= 1) + { + batteryBarImg[i]->SetImage(&batteryBarRed); + batteryImg[i]->SetImage(&batteryRed); + } + else + { + batteryBarImg[i]->SetImage(&batteryBar); + } + + batteryImg[i]->SetTileHorizontal(level); + + batteryBtn[i]->SetAlpha(255); + } + else // controller not connected + { + batteryImg[i]->SetTileHorizontal(0); + batteryImg[i]->SetImage(&battery); + batteryBtn[i]->SetAlpha(70); + } + } + + if (shutdown) + { + wiilight(0); + Sys_Shutdown(); + } + if (reset) + Sys_Reboot(); + + if (btn1.GetState() == STATE_CLICKED) + { + choice = 1; + btn1.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + closeBtn.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + btn4.SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_OUT, 50); + btn2.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 50); + btn3.SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 50); + titleTxt.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + wiimoteImg.SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_OUT, 50); + + for (int i = 0; i < 4; i++) + batteryBtn[i]->SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_OUT, 50); + + } + else if (btn4.GetState() == STATE_SELECTED) + { + wiimoteImg.SetPosition(50, 165); + } + else if (btn2.GetState() == STATE_CLICKED) + { + if (Settings.HomeMenu == HOME_MENU_SYSTEM) + Sys_LoadMenu(); + else if (Settings.HomeMenu == HOME_MENU_DEFAULT) + Sys_LoadHBC(); + else if (Settings.HomeMenu == HOME_MENU_FULL) + { + ret = WindowPrompt(tr( "Exit to where?" ), 0, tr( "Homebrew Channel" ), tr( "Wii Menu" ), tr( "Reset" ), tr( "Cancel" )); + if (ret == 1) + Sys_LoadHBC(); + else if(ret == 2) + Sys_LoadMenu(); + else if(ret == 3) + RebootApp(); + } + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + promptWindow.SetState(STATE_DEFAULT); + ResumeGui(); + btn2.ResetState(); + } + else if (btn3.GetState() == STATE_CLICKED) + { + if (Settings.HomeMenu == HOME_MENU_SYSTEM) + RebootApp(); + else if (Settings.HomeMenu == HOME_MENU_DEFAULT) + Sys_LoadMenu(); + else if (Settings.HomeMenu == HOME_MENU_FULL) + { + if(isWiiU()) + ret = WindowPrompt(tr( "How to Shutdown?" ), 0, tr( "Full shutdown" ), tr("Cancel")); + else + ret = WindowPrompt(tr( "How to Shutdown?" ), 0, tr( "Full shutdown" ), tr( "Standby" ), tr("Cancel")); + + if (ret == 1) + Sys_ShutdownToStandby(); + else if(ret == 2) + Sys_ShutdownToIdle(); + } + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + promptWindow.SetState(STATE_DEFAULT); + ResumeGui(); + btn3.ResetState(); + } + else if (btn4.GetState() == STATE_CLICKED) + { + btn1.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + closeBtn.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + btn4.SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_OUT, 50); + btn2.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 50); + btn3.SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 50); + titleTxt.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + wiimoteImg.SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_OUT, 50); + + for (int i = 0; i < 4; i++) + batteryBtn[i]->SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_OUT, 50); + + choice = 0; + } + else if (btn4.GetState() != STATE_SELECTED) + { + wiimoteImg.SetPosition(50, 210); + } + } + homeout->Play(); + while (btn1.GetEffect() > 0) + usleep(100); + while (promptWindow.GetEffect() > 0) + usleep(100); + HaltGui(); + homein->Stop(); + delete homein; + mainWindow->Remove(&promptWindow); + mainWindow->SetState(STATE_DEFAULT); + while (homeout->IsPlaying() > 0) + usleep(100); + homeout->Stop(); + delete homeout; + + for(int i = 0; i < 4; ++i) + { + delete batteryTxt[i]; + delete batteryImg[i]; + delete batteryBarImg[i]; + delete batteryBtn[i]; + } + + ResumeGui(); + bgMusic->Resume(); + + return choice; +} + +/**************************************************************************** + * DiscWait + ***************************************************************************/ +int DiscWait(const char *title, const char *msg, const char *btn1Label, const char *btn2Label, int IsDeviceWait) +{ + int ret = 0; + u32 cover = 0; + + GuiWindow promptWindow(472, 320); + promptWindow.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + promptWindow.SetPosition(0, -10); + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData dialogBox(Resources::GetFile("dialogue_box.png"), Resources::GetFileSize("dialogue_box.png")); + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + GuiImage dialogBoxImg(&dialogBox); + if (Settings.wsprompt) + { + dialogBoxImg.SetWidescreen(Settings.widescreen); + } + + GuiText titleTxt(title, 26, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + titleTxt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt.SetPosition(0, 60); + GuiText msgTxt(msg, 22, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + msgTxt.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + msgTxt.SetPosition(0, -40); + msgTxt.SetMaxWidth(430); + + GuiText btn1Txt(btn1Label, 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + GuiImage btn1Img(&btnOutline); + if (Settings.wsprompt) + { + btn1Txt.SetWidescreen(Settings.widescreen); + btn1Img.SetWidescreen(Settings.widescreen); + } + GuiButton btn1(&btn1Img, &btn1Img, 1, 5, 0, 0, &trigA, btnSoundOver, btnSoundClick2, 1); + + if (btn2Label) + { + btn1.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + btn1.SetPosition(40, -45); + } + else + { + btn1.SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + btn1.SetPosition(0, -45); + } + + btn1.SetLabel(&btn1Txt); + btn1.SetTrigger(&trigB); + btn1.SetState(STATE_SELECTED); + + GuiText btn2Txt(btn2Label, 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + GuiImage btn2Img(&btnOutline); + if (Settings.wsprompt) + { + btn2Txt.SetWidescreen(Settings.widescreen); + btn2Img.SetWidescreen(Settings.widescreen); + } + GuiButton btn2(&btn2Img, &btn2Img, 1, 4, -20, -25, &trigA, btnSoundOver, btnSoundClick2, 1); + btn2.SetLabel(&btn2Txt); + + if (Settings.wsprompt && Settings.widescreen) /////////////adjust buttons for widescreen + { + msgTxt.SetMaxWidth(380); + if (btn2Label) + { + btn1.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + btn2.SetPosition(-70, -80); + btn1.SetPosition(70, -80); + } + else + { + btn1.SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + btn1.SetPosition(0, -80); + } + } + + GuiText timerTxt((char*) NULL, 26, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + timerTxt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + timerTxt.SetPosition(0, 160); + + promptWindow.Append(&dialogBoxImg); + promptWindow.Append(&titleTxt); + promptWindow.Append(&msgTxt); + + if (btn1Label) promptWindow.Append(&btn1); + if (btn2Label) promptWindow.Append(&btn2); + if (IsDeviceWait) promptWindow.Append(&timerTxt); + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&promptWindow); + ResumeGui(); + + if (IsDeviceWait) + { + time_t starttime = time(0); + time_t timenow = starttime; + do + { + gprintf("%i\n", (int) (timenow-starttime)); + ret = WBFS_Init(WBFS_DEVICE_USB); + if (ret >= 0) break; + + timerTxt.SetTextf("%i %s", (int) (30-(timenow-starttime)), tr( "seconds left" )); + DeviceHandler::Instance()->UnMountAllUSB(); + DeviceHandler::Instance()->MountAllUSB(); + timenow = time(0); + } + while (timenow-starttime < 30); + } + else + { + while (!(cover & 0x2)) + { + VIDEO_WaitVSync(); + if (btn1.GetState() == STATE_CLICKED) + { + btn1.ResetState(); + break; + } + ret = WDVD_GetCoverStatus(&cover); + if (ret < 0) break; + } + } + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while (promptWindow.GetEffect() > 0) + usleep(100); + HaltGui(); + mainWindow->Remove(&promptWindow); + mainWindow->SetState(STATE_DEFAULT); + ResumeGui(); + return ret; +} + +/**************************************************************************** + * FormatingPartition + ***************************************************************************/ +int FormatingPartition(const char *title, int part_num) +{ + PartitionHandle * usbHandle = DeviceHandler::Instance()->GetUSBHandleFromPartition(part_num); + int portPart = DeviceHandler::PartitionToPortPartition(part_num); + + char text[255]; + sprintf(text, "%s: %.2fGB", tr( "Partition" ), usbHandle->GetSize(portPart) / GB_SIZE); + int choice = WindowPrompt(tr( "Do you want to format:" ), text, tr( "Yes" ), tr( "No" )); + if (choice == 0) + return -666; + + int ret; + GuiWindow promptWindow(472, 320); + promptWindow.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + promptWindow.SetPosition(0, -10); + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData dialogBox(Resources::GetFile("dialogue_box.png"), Resources::GetFileSize("dialogue_box.png")); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + GuiImage dialogBoxImg(&dialogBox); + if (Settings.wsprompt) + { + dialogBoxImg.SetWidescreen(Settings.widescreen); + } + + GuiText titleTxt(title, 26, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + titleTxt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt.SetPosition(0, 60); + + promptWindow.Append(&dialogBoxImg); + promptWindow.Append(&titleTxt); + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&promptWindow); + ResumeGui(); + + VIDEO_WaitVSync(); + ret = WBFS_Format(usbHandle->GetLBAStart(portPart), usbHandle->GetSecCount(portPart), DeviceHandler::PartitionToUSBPort(part_num)); + + if (ret < 0) + { + WindowPrompt(tr( "Error !" ), tr( "Failed formating" ), tr( "Return" )); + } + else + { + PartitionFS * partition = usbHandle->GetPartitionRecord(portPart); + partition->PartitionType = 0xBF; + partition->FSName = "WBFS"; + sleep(1); + ret = WBFS_OpenPart(part_num); + sprintf(text, "%s %s", text, tr( "formatted!" )); + WindowPrompt(tr( "Success:" ), text, tr( "OK" )); + if (ret < 0) + { + WindowPrompt(tr( "ERROR" ), tr( "Failed to open partition" ), tr( "OK" )); + Sys_LoadMenu(); + } + } + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while (promptWindow.GetEffect() > 0) + usleep(100); + HaltGui(); + mainWindow->Remove(&promptWindow); + mainWindow->SetState(STATE_DEFAULT); + ResumeGui(); + return ret; +} + +/**************************************************************************** + * NetworkInitPrompt + ***************************************************************************/ +bool NetworkInitPrompt() +{ + gprintf("\nNetworkinitPrompt()"); + if (IsNetworkInit()) return true; + + bool success = true; + + GuiWindow promptWindow(472, 320); + promptWindow.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + promptWindow.SetPosition(0, -10); + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData dialogBox(Resources::GetFile("dialogue_box.png"), Resources::GetFileSize("dialogue_box.png")); + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + GuiImage dialogBoxImg(&dialogBox); + + if (Settings.wsprompt) + { + dialogBoxImg.SetWidescreen(Settings.widescreen); + } + + GuiText titleTxt(tr( "Initializing Network" ), 26, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + titleTxt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt.SetPosition(0, 60); + + char msg[20] = " "; + GuiText msgTxt(msg, 22, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + msgTxt.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + msgTxt.SetPosition(0, -40); + + GuiText btn1Txt(tr( "Cancel" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + GuiImage btn1Img(&btnOutline); + if (Settings.wsprompt) + { + btn1Txt.SetWidescreen(Settings.widescreen); + btn1Img.SetWidescreen(Settings.widescreen); + } + GuiButton btn1(&btn1Img, &btn1Img, 2, 4, 0, -45, &trigA, btnSoundOver, btnSoundClick2, 1); + btn1.SetLabel(&btn1Txt); + btn1.SetState(STATE_SELECTED); + + if ((Settings.wsprompt) && (Settings.widescreen)) /////////////adjust buttons for widescreen + { + btn1.SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + btn1.SetPosition(0, -80); + } + + promptWindow.Append(&dialogBoxImg); + promptWindow.Append(&titleTxt); + promptWindow.Append(&msgTxt); + promptWindow.Append(&btn1); + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&promptWindow); + ResumeGui(); + + int iTimeout = 100 * 200; // 20s + + ResumeNetworkThread(); + + while (!IsNetworkInit()) + { + usleep(100000); + + if (--iTimeout == 0) + { + msgTxt.SetText(tr( "Could not initialize network, time out!" )); + sleep(3); + success = false; + break; + } + + if (btn1.GetState() == STATE_CLICKED) + { + btn1.ResetState(); + success = false; + break; + } + } + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while (promptWindow.GetEffect() > 0) + usleep(1000); + + HaltGui(); + mainWindow->Remove(&promptWindow); + mainWindow->SetState(STATE_DEFAULT); + ResumeGui(); + + if (IsNetworkInit()) + HaltNetworkThread(); + + return success; +} +int CodeDownload(const char *id) +{ + if (!CreateSubfolder(Settings.TxtCheatcodespath)) + { + WindowPrompt(tr( "Error !" ), tr( "Can't create directory" ), tr( "OK" )); + return -1; + } + + int ret = -1; + + GuiWindow promptWindow(472, 320); + promptWindow.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + promptWindow.SetPosition(0, -10); + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData dialogBox(Resources::GetFile("dialogue_box.png"), Resources::GetFileSize("dialogue_box.png")); + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + GuiImage dialogBoxImg(&dialogBox); + if (Settings.wsprompt) + { + dialogBoxImg.SetWidescreen(Settings.widescreen); + } + + char title[50]; + sprintf(title, "%s", tr( "Code Download" )); + GuiText titleTxt(title, 26, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + titleTxt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt.SetPosition(0, 50); + char msg[50]; + sprintf(msg, "%s", tr( "Initializing Network" )); + GuiText msgTxt(msg, 26, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + msgTxt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + msgTxt.SetPosition(0, 140); + char msg2[50] = " "; + GuiText msg2Txt(msg2, 26, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + msg2Txt.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + msg2Txt.SetPosition(0, 50); + + GuiText btn1Txt(tr( "Cancel" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + GuiImage btn1Img(&btnOutline); + if (Settings.wsprompt) + { + btn1Txt.SetWidescreen(Settings.widescreen); + btn1Img.SetWidescreen(Settings.widescreen); + } + GuiButton btn1(&btn1Img, &btn1Img, 2, 4, 0, -40, &trigA, btnSoundOver, btnSoundClick2, 1); + btn1.SetLabel(&btn1Txt); + btn1.SetState(STATE_SELECTED); + + promptWindow.Append(&dialogBoxImg); + promptWindow.Append(&titleTxt); + promptWindow.Append(&msgTxt); + promptWindow.Append(&msg2Txt); + promptWindow.Append(&btn1); + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + + HaltGui(); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&promptWindow); + ResumeGui(); + + while (!IsNetworkInit()) + { + VIDEO_WaitVSync(); + + Initialize_Network(); + + if (IsNetworkInit()) + { + msgTxt.SetText(GetNetworkIP()); + } + else + { + msgTxt.SetText(tr( "Could not initialize network!" )); + } + if (btn1.GetState() == STATE_CLICKED) + { + btn1.ResetState(); + ret = 0; + break; + } + } + + if (IsNetworkInit()) + { + char txtpath[250]; + snprintf(txtpath, sizeof(txtpath), "%s%s.txt", Settings.TxtCheatcodespath, id); + + char codeurl[250]; + snprintf(codeurl, sizeof(codeurl), "http://geckocodes.org/txt.php?txt=%s", id); + //snprintf(codeurl, sizeof(codeurl), "http://geckocodes.org/codes/G/%s.txt", id); + + struct block file = downloadfile(codeurl); + + if (file.data != NULL) + { + bool validUrl = false; + if(file.size > 0) + { + char *textCpy = new (std::nothrow) char[file.size+1]; + if(textCpy) + { + memcpy(textCpy, file.data, file.size); + textCpy[file.size] = '\0'; + validUrl = (strcasestr(textCpy, "404 Not Found") == 0); + delete [] textCpy; + } + } + + if(!validUrl) + { + snprintf(codeurl, sizeof(codeurl), "%s%s", codeurl, tr( " is not on the server." )); + WindowPrompt(tr( "Error" ), codeurl, tr( "OK" )); + } + else + { + FILE * pfile = fopen(txtpath, "wb"); + if(pfile) + { + fwrite(file.data, 1, file.size, pfile); + fclose(pfile); + + // verify downloaded content - thanks airline38 + pfile = fopen(txtpath, "rb"); + if(pfile) + { + char target[4]; + fseek(pfile,0,SEEK_SET); + fread(target, sizeof(char), 4, pfile); + fclose(pfile); + //printf("target=%s game id=%s\n",target,id); + if (strncmp(target,id,4)== 0 ) + { + snprintf(txtpath, sizeof(txtpath), "%s%s", txtpath, tr(" has been Saved. The text has not been verified. Some of the code may not work right with each other. If you experience trouble, open the text in a real text editor for more information." )); + WindowPrompt(0, txtpath, tr( "OK" )); + ret = 0; + } + else + { + RemoveFile(txtpath); + snprintf(codeurl, sizeof(codeurl), "%s%s", codeurl, tr( " is not on the server." )); + WindowPrompt(tr( "Error" ), codeurl, tr( "OK" )); + } + } + } + else + WindowPrompt(tr("Error"), tr("Could not write file."), tr( "OK" )); + } + free(file.data); + } + else + { + snprintf(codeurl, sizeof(codeurl), "%s%s", codeurl, tr(" could not be downloaded.")); + WindowPrompt(tr( "Error" ), codeurl, tr( "OK" )); + } + } + + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while (promptWindow.GetEffect() > 0) + usleep(100); + + HaltGui(); + mainWindow->Remove(&promptWindow); + mainWindow->SetState(STATE_DEFAULT); + ResumeGui(); + + return ret; +} + diff --git a/source/prompts/PromptWindows.h b/source/prompts/PromptWindows.h new file mode 100644 index 0000000..3ed2707 --- /dev/null +++ b/source/prompts/PromptWindows.h @@ -0,0 +1,26 @@ +/**************************************************************************** + * PromptWindows + * USB Loader GX 2009 + * + * PromptWindows.h + ***************************************************************************/ + +#ifndef _PROMPTWINDOWS_H_ +#define _PROMPTWINDOWS_H_ + +#include "GUI/gui.h" + +int WindowPrompt(const char *title, const char *msg = NULL, const char * btn1Label = NULL, const char * btn2Label = + NULL, const char * btn3Label = NULL, const char * btn4Label = NULL, int wait = -1); + +void WindowCredits(); +int OnScreenKeyboard(char * var, u32 maxlen, int min, bool hide = false); +int OnScreenNumpad(char * var, u32 maxlen); +int WindowExitPrompt(); +int DiscWait(const char *title, const char *msg, const char *btn1Label, const char *btn2Label, int IsDeviceWait); +int FormatingPartition(const char *title, int part_num); +bool NetworkInitPrompt(); +int WindowScreensaver(); +int CodeDownload(const char *id); + +#endif diff --git a/source/prompts/TitleBrowser.cpp b/source/prompts/TitleBrowser.cpp new file mode 100644 index 0000000..8d21708 --- /dev/null +++ b/source/prompts/TitleBrowser.cpp @@ -0,0 +1,481 @@ +/**************************************************************************** + * TitleBrowser + * USB Loader GX 2009 + * + * TitleBrowser.cpp *giantpune* + ***************************************************************************/ + +#include +#include + +#include "language/gettext.h" +#include "GUI/gui.h" +#include "GUI/gui_optionbrowser.h" +#include "prompts/PromptWindows.h" +#include "prompts/ProgressWindow.h" +#include "network/networkops.h" +#include "network/http.h" +#include "FileOperations/fileops.h" +#include "themes/CTheme.h" +#include "sys.h" +#include "menu.h" +#include "audio.h" +#include "xml/GameTDB.hpp" +#include "wad/nandtitle.h" +#include "gecko.h" + +#include "Controls/DeviceHandler.hpp" +#include "usbloader/NandEmu.h" +extern u8 shutdown; +extern u8 reset; + +/******************************************************************************** + * TitleBrowser- opens a browser with a list of installed Titles + *********************************************************************************/ +bool TitleSelector(char output[]) +{ + gprintf("TitleSelector()\n"); + + s32 num_titles; + s32 r = -1; + bool ret = false; + u64 *titleList = NULL; + + // Get count of titles of the good titles + num_titles = NandTitles.SetType(0x10001); + u32 n = num_titles; + + for (u32 i = 0; i < n; i++) + { + u64 tid = NandTitles.Next(); + if (!tid) + { + break; + } + + //remove ones not actually installed on the nand + if (!NandTitles.Exists(tid)) + { + num_titles--; + } + } + + //make a list of just the tids we are adding to the titlebrowser + titleList = (u64*) memalign(32, num_titles * sizeof(u64)); + if (!titleList) + { + gprintf("TitleLister(): out of memory!\n"); + return false; + } + OptionList options4; + //write the titles on the option browser + + std::string Filepath = Settings.titlestxt_path; + Filepath += "wiitdb.xml"; + + GameTDB *XML_DB = new GameTDB(Filepath.c_str()); + XML_DB->SetLanguageCode(Settings.db_language); + + s32 i = 0; + NandTitles.SetType(0x10001); + while (i < num_titles) + { + u64 tid = NandTitles.Next(); + if (!tid) + { + gprintf("shit happened\n"); + break; + } + + if (!NandTitles.Exists(tid)) + continue; + + char id[5]; + NandTitles.AsciiTID(tid, (char*) &id); + + const char* name = NULL; + std::string TitleName; + + if(XML_DB->GetTitle(id, TitleName)) + name = TitleName.c_str(); + else + name = NandTitles.NameOf(tid); + //gprintf("%016llx: %s: %s\n%p\t%p\n", tid, id, name, &id, name ); + + options4.SetName(i, "%s", id); + options4.SetValue(i, "%s", name ? name : tr( "Unknown" )); + titleList[i] = tid; + i++; + } + + delete XML_DB; + XML_DB = NULL; + + options4.SetName(i, " "); + options4.SetValue(i, "%s", tr( "Clear" )); + + bool exit = false; + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData settingsbg(Resources::GetFile("settings_background.png"), Resources::GetFileSize("settings_background.png")); + + GuiImage settingsbackground(&settingsbg); + GuiButton settingsbackgroundbtn(settingsbackground.GetWidth(), settingsbackground.GetHeight()); + settingsbackgroundbtn.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + settingsbackgroundbtn.SetPosition(0, 0); + settingsbackgroundbtn.SetImage(&settingsbackground); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + GuiText cancelBtnTxt(tr( "Back" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + cancelBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30); + GuiImage cancelBtnImg(&btnOutline); + if (Settings.wsprompt) + { + cancelBtnTxt.SetWidescreen(Settings.widescreen); + cancelBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton cancelBtn(&cancelBtnImg, &cancelBtnImg, 2, 3, 180, 400, &trigA, btnSoundOver, btnSoundClick2, 1); + cancelBtn.SetLabel(&cancelBtnTxt); + cancelBtn.SetTrigger(&trigB); + + GuiOptionBrowser optionBrowser4(396, 280, &options4, "bg_options_settings.png"); + optionBrowser4.SetPosition(0, 90); + optionBrowser4.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + + HaltGui(); + GuiWindow w(screenwidth, screenheight); + w.Append(&settingsbackgroundbtn); + w.Append(&cancelBtn); + w.Append(&optionBrowser4); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&w); + + ResumeGui(); + + while (!exit) + { + VIDEO_WaitVSync(); + + if (shutdown == 1) Sys_Shutdown(); + if (reset == 1) Sys_Reboot(); + + r = optionBrowser4.GetClickedOption(); + + if (r > -1) + { //if a click happened + if (r < num_titles) + { + u64 tid = titleList[r]; + sprintf(output, "%08x", (unsigned int)TITLE_LOWER( tid )); + } + else output[0] = 0; + ret = true; + exit = true; + } + + else if (cancelBtn.GetState() == STATE_CLICKED) + { + //break the loop and end the function + exit = true; + } + } + + HaltGui(); + mainWindow->SetState(STATE_DEFAULT); + mainWindow->Remove(&w); + free(titleList); + ResumeGui(); + + return ret; +} + +int TitleBrowser() +{ + u32 num_titles; + u32 num_sys_titles; + s32 ret = -1; + u64 *titleList = NULL; + + // Get count of titles of the good titles + num_titles = NandTitles.SetType(0x10001); + u32 n = num_titles; + for (u32 i = 0; i < n; i++) + { + u64 tid = NandTitles.Next(); + if (!tid) + { + break; + } + + //remove ones not actually installed on the nand + if (!NandTitles.Exists(tid)) + { + num_titles--; + } + } + + // Get count of system titles + num_sys_titles = NandTitles.SetType(0x10002); + n = num_sys_titles; + for (u32 i = 0; i < n; i++) + { + u64 tid = NandTitles.Next(); + if (!tid) + { + break; + } + //these can't be booted anyways + if (TITLE_LOWER( tid ) == 0x48414741 || TITLE_LOWER( tid ) == 0x48414141 || TITLE_LOWER( tid ) == 0x48414641) + { + num_sys_titles--; + continue; + } + + //these aren't installed on the nand + if (!NandTitles.Exists(tid)) + { + num_sys_titles--; + } + } + + //make a list of just the tids we are adding to the titlebrowser + titleList = (u64*) memalign(32, (num_titles + num_sys_titles) * sizeof(u64)); + if (!titleList) + { + gprintf("TitleBrowser(): out of memory!\n"); + return -1; + } + OptionList options3; + //write the titles on the option browser + + std::string Filepath = Settings.titlestxt_path; + Filepath += "wiitdb.xml"; + + GameTDB *XML_DB = new GameTDB(Filepath.c_str()); + XML_DB->SetLanguageCode(Settings.db_language); + + u32 i = 0; + NandTitles.SetType(0x10001); + //first add the good stuff + while (i < num_titles) + { + u64 tid = NandTitles.Next(); + if (!tid) + { + gprintf("shit happened3\n"); + break; + } + gprintf("[ %u ] tid: %016llx\t%s\n", i, tid, NandTitles.NameOf(tid)); + + if (!NandTitles.Exists(tid)) + { + continue; + } + + char id[5]; + NandTitles.AsciiTID(tid, (char*) &id); + + const char* name = NULL; + std::string TitleName; + + if(XML_DB->GetTitle(id, TitleName)) + name = TitleName.c_str(); + else + name = NandTitles.NameOf(tid); + + options3.SetName(i, "%s", id); + options3.SetValue(i, "%s", name ? name : tr( "Unknown" )); + titleList[i] = tid; + i++; + } + + NandTitles.SetType(0x10002); + while (i < num_sys_titles + num_titles) + { + u64 tid = NandTitles.Next(); + if (!tid) + { + break; + } + if (TITLE_LOWER( tid ) == 0x48414741 || TITLE_LOWER( tid ) == 0x48414141 || TITLE_LOWER( tid ) == 0x48414641) continue; + + if (!NandTitles.Exists(tid)) + { + continue; + } + + char id[5]; + NandTitles.AsciiTID(tid, (char*) &id); + + const char* name = NULL; + std::string TitleName; + + if(XML_DB->GetTitle(id, TitleName)) + name = TitleName.c_str(); + else + name = NandTitles.NameOf(tid); + + options3.SetName(i, "%s", id); + options3.SetValue(i, "%s", name ? name : tr( "Unknown" )); + titleList[i] = tid; + i++; + } + + delete XML_DB; + XML_DB = NULL; + + if (i == num_titles + num_sys_titles) + { + options3.SetName(i, " "); + options3.SetValue(i, "%s", tr( "Wii Settings" )); + } + + bool exit = false; + int total = num_titles + num_sys_titles; + + if (IsNetworkInit()) ResumeNetworkWait(); + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData settingsbg(Resources::GetFile("settings_background.png"), Resources::GetFileSize("settings_background.png")); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigHome; + trigHome.SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, 0); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + GuiText titleTxt(tr( "Title Launcher" ), 28, ( GXColor ) + { 0, 0, 0, 255}); + titleTxt.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt.SetPosition(12, 40); + titleTxt.SetMaxWidth(356, SCROLL_HORIZONTAL); + + GuiImage settingsbackground(&settingsbg); + GuiButton settingsbackgroundbtn(settingsbackground.GetWidth(), settingsbackground.GetHeight()); + settingsbackgroundbtn.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + settingsbackgroundbtn.SetPosition(0, 0); + settingsbackgroundbtn.SetImage(&settingsbackground); + + GuiText cancelBtnTxt(tr( "Back" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + cancelBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30); + GuiImage cancelBtnImg(&btnOutline); + if (Settings.wsprompt) + { + cancelBtnTxt.SetWidescreen(Settings.widescreen); + cancelBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton cancelBtn(&cancelBtnImg, &cancelBtnImg, 2, 3, 180, 400, &trigA, btnSoundOver, btnSoundClick2, 1); + cancelBtn.SetScale(0.9); + cancelBtn.SetLabel(&cancelBtnTxt); + cancelBtn.SetTrigger(&trigB); + + GuiOptionBrowser optionBrowser3(396, 280, &options3, "bg_options_settings.png"); + optionBrowser3.SetPosition(0, 90); + optionBrowser3.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + + GuiImageData wifiImgData(Resources::GetFile("wifi_btn.png"), Resources::GetFileSize("wifi_btn.png")); + GuiImage wifiImg(&wifiImgData); + if (Settings.wsprompt) + { + wifiImg.SetWidescreen(Settings.widescreen); + } + GuiButton wifiBtn(wifiImg.GetWidth(), wifiImg.GetHeight()); + wifiBtn.SetImage(&wifiImg); + wifiBtn.SetPosition(100, 400); + wifiBtn.SetEffectGrow(); + wifiBtn.SetAlpha(80); + wifiBtn.SetTrigger(&trigA); + + HaltGui(); + GuiWindow w(screenwidth, screenheight); + w.Append(&settingsbackgroundbtn); + w.Append(&titleTxt); + w.Append(&cancelBtn); + w.Append(&wifiBtn); + w.Append(&optionBrowser3); + mainWindow->Append(&w); + + ResumeGui(); + + while (!exit) + { + VIDEO_WaitVSync(); + + if (shutdown == 1) Sys_Shutdown(); + if (reset == 1) + Sys_Reboot(); + + else if (wifiBtn.GetState() == STATE_CLICKED) + { + ResumeNetworkWait(); + wifiBtn.ResetState(); + } + + if (IsNetworkInit()) + { + wifiBtn.SetAlpha(255); + } + + ret = optionBrowser3.GetClickedOption(); + + if (ret > -1) + { //if a click happened + + if (ret < total) + { + //set the title's name, number, ID to text + char text[0x100]; + char id[5]; + NandTitles.AsciiTID(titleList[ret], (char*) &id); + + snprintf(text, sizeof(text), "%s : %s", id, NandTitles.NameOf(titleList[ret])); + + //prompt to boot selected title + if (WindowPrompt(tr( "Boot?" ), text, tr( "OK" ), tr( "Cancel" ))) + { //if they say yes + ExitApp(); + WII_Initialize(); + WII_LaunchTitle(titleList[ret]); + //this really shouldn't be needed because the title will be booted + exit = true; + break; + } + else + { + //if they said no to booting the title + ret = -1; + optionBrowser3.ResetState(); + } + + } + else if (ret == total) + { //if they clicked to go to the wii settings + ExitApp(); + WII_Initialize(); + WII_ReturnToSettings(); + } + } + if (cancelBtn.GetState() == STATE_CLICKED) + { + //break the loop and end the function + exit = true; + ret = -10; + } + } + + CloseConnection(); + if (IsNetworkInit()) HaltNetworkThread(); + + HaltGui(); + mainWindow->Remove(&w); + free(titleList); + ResumeGui(); + + return ret; +} + diff --git a/source/prompts/TitleBrowser.h b/source/prompts/TitleBrowser.h new file mode 100644 index 0000000..cd15cc3 --- /dev/null +++ b/source/prompts/TitleBrowser.h @@ -0,0 +1,14 @@ +/**************************************************************************** + * TitleBrowser + * USB Loader GX 2009 + * + * TitleBrowser.h + ***************************************************************************/ + +#ifndef _TITLEBROWSER_H_ +#define _TITLEBROWSER_H_ + +int TitleBrowser(); +bool TitleSelector(char output[]); + +#endif diff --git a/source/prompts/filebrowser.cpp b/source/prompts/filebrowser.cpp new file mode 100644 index 0000000..286e03a --- /dev/null +++ b/source/prompts/filebrowser.cpp @@ -0,0 +1,561 @@ +/**************************************************************************** + * libwiigui Template + * Tantric 2009 + * + * modified by dimok + * + * filebrowser.cpp + * + * Generic file routines - reading, writing, browsing + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "menu.h" + +#include "themes/CTheme.h" +#include "FileOperations/fileops.h" +#include "language/gettext.h" +#include "PromptWindows.h" +#include "GUI/gui_filebrowser.h" +#include "sys.h" +#include "filebrowser.h" + +/*** Extern variables ***/ +extern GuiWindow * mainWindow; +extern u8 shutdown; +extern u8 reset; + +/*** Extern functions ***/ +extern void ResumeGui(); +extern void HaltGui(); + +static int curDevice = -1; +static std::vector browsers; +BROWSERINFO *browser = NULL; + +/**************************************************************************** + * FileFilterCallbacks + * return: 1-visible 0-hidden + ***************************************************************************/ +int noDIRS(BROWSERENTRY *Entry, void* Args) +{ + return !Entry->isdir; +} +int noFILES(BROWSERENTRY *Entry, void* Args) +{ + return Entry->isdir; +} +int noEXT(BROWSERENTRY *Entry, void* Args) +{ + if (!Entry->isdir) + { + char *cptr = strrchr(Entry->displayname, '.'); + if (cptr && cptr != Entry->displayname) *cptr = 0; + } + return 1; +} + +void ResetBrowser(BROWSERINFO *browser); +/**************************************************************************** + * InitBrowsers() + * Clears the file browser memory, and allocates one initial entry + ***************************************************************************/ +int InitBrowsers() +{ + curDevice = -1; + browsers.clear(); + browser = NULL; + char rootdir[ROOTDIRLEN]; + for (int i = 3; i < STD_MAX; i++) + { + if (strcmp(devoptab_list[i]->name, "stdnull") && devoptab_list[i]->write_r != NULL) + { + snprintf(rootdir, sizeof(rootdir), "%s:/", devoptab_list[i]->name); + if ( DIR *dir = opendir( rootdir ) ) + { + closedir(dir); + BROWSERINFO browser; + memset(&browser, 0, sizeof(BROWSERINFO)); + strcpy(browser.rootdir, rootdir); + ResetBrowser(&browser); + browsers.push_back(browser); + } + } + } + if (!browsers.size()) return -1; + curDevice = 0; + browser = &browsers[curDevice]; + return 0; +} +/**************************************************************************** + * ResetBrowser() + * Clears the file browser memory, and allocates one initial entry + ***************************************************************************/ +void ResetBrowser(BROWSERINFO *browser) +{ + browser->pageIndex = 0; + browser->browserList.clear(); + /* + // Clear any existing values + if (browser->browserList != NULL) { + free(browser->browserList); + browser->browserList = NULL; + } + // set aside space for 1 entry + browser->browserList = (BROWSERENTRY *)malloc(sizeof(BROWSERENTRY)); + if(browser->browserList) + memset(browser->browserList, 0, sizeof(BROWSERENTRY)); + */ +} + +/**************************************************************************** + * FileSortCallback + * + * sort callback to sort file entries with the following order: + * . + * .. + * + * + ***************************************************************************/ +//int FileSortCallback(const void *f1, const void *f2) { +bool operator<(const BROWSERENTRY &f1, const BROWSERENTRY &f2) +{ + /* Special case for implicit directories */ + if (f1.filename[0] == '.' || f2.filename[0] == '.') + { + if (strcmp(f1.filename, ".") == 0) + { + return true; + } + if (strcmp(f2.filename, ".") == 0) + { + return false; + } + if (strcmp(f1.filename, "..") == 0) + { + return true; + } + if (strcmp(f2.filename, "..") == 0) + { + return false; + } + } + + /* If one is a file and one is a directory the directory is first. */ + if (f1.isdir && !(f2.isdir)) return true; + if (!(f1.isdir) && f2.isdir) return false; + + return strcasecmp(f1.filename, f2.filename) < 0; +} + +int ParseFilter(FILTERCASCADE *Filter, BROWSERENTRY* Entry) +{ + while (Filter) + { + if (Filter->filter && Filter->filter(Entry, Filter->filter_args) == 0) return 0; + Filter = Filter->next; + } + return 1; +} +/*************************************************************************** + * Browse subdirectories + **************************************************************************/ +int ParseDirectory(const char* Path, int Flags, FILTERCASCADE *Filter) +{ + DIR *dir = NULL; + char fulldir[MAXPATHLEN]; + char filename[MAXPATHLEN]; + struct stat filestat; + unsigned int i; + + if (curDevice == -1) if (InitBrowsers()) return -1; // InitBrowser fails + + if (Path) // note in this codeblock use filename temporary + { + strlcpy(fulldir, Path, sizeof(fulldir)); + if (*fulldir && fulldir[strlen(fulldir) - 1] != '/') // a file + { + char * chrp = strrchr(fulldir, '/'); + if (chrp) chrp[1] = 0; + } + if (strchr(fulldir, ':') == NULL) // Path has no device device + { + getcwd(filename, sizeof(filename)); // save the current working dir + if (*fulldir == 0) // if path is empty + strlcpy(fulldir, filename, sizeof(fulldir)); // we use the current working dir + else + { // path is not empty + if (chdir(fulldir)) // sets the path to concatenate and validate + { + if (Flags & (FB_TRYROOTDIR | FB_TRYSTDDEV)) + { + if (chdir("/") && !(Flags & FB_TRYSTDDEV)) // try to set root if is needed + return -1; + } + } + if (getcwd(fulldir, sizeof(fulldir))) return -1; // gets the concatenated current working dir + chdir(filename); // restore the saved cwd + } + } + for (i = 0; i < browsers.size(); i++) // searchs the browser who match the path + { + if (strncasecmp(fulldir, browsers[i].rootdir, strlen(browsers[i].rootdir) - 1 /*means without trailing '/'*/) + == 0) + { + browser = &browsers[curDevice]; + break; + } + } + if (i != browsers.size()) // found browser + { + curDevice = i; + browser = &browsers[curDevice]; + strcpy(browser->dir, &fulldir[strlen(browser->rootdir)]); + } + else if (Flags & FB_TRYSTDDEV) + { + curDevice = 0; + browser = &browsers[curDevice]; // when no browser was found and + browser->dir[0] = 0; // we alowed try StdDevice and try RootDir + strlcpy(fulldir, browser->rootdir, sizeof(fulldir)); // set the first browser with root-dir + } + else return -1; + } + else snprintf(fulldir, sizeof(fulldir), "%s%s", browser->rootdir, browser->dir); + + // reset browser + ResetBrowser(browser); + + // open the directory + if ((dir = opendir(fulldir)) == NULL) + { + if (Flags & FB_TRYROOTDIR) + { + snprintf(fulldir, sizeof(fulldir), browser->rootdir); + browser->dir[0] = 0; + if ((dir = opendir(browser->rootdir)) == NULL) return -1; + } + else return -1; + } + + struct dirent *dirent = NULL; + + // Adds parent directory ".." manually if in a subdirectory to fix NTFS folder browsing. + if (strcmp(fulldir, browser->rootdir) != 0) + { + snprintf(filename, sizeof(filename), ".."); + + BROWSERENTRY newEntry; + memset(&newEntry, 0, sizeof(BROWSERENTRY)); // clear the new entry + strlcpy(newEntry.filename, filename, sizeof(newEntry.filename)); + strlcpy(newEntry.displayname, filename, sizeof(newEntry.displayname)); + newEntry.isdir = 1; // flag this as a dir + if (ParseFilter(Filter, &newEntry)) browser->browserList.push_back(newEntry); + } + + while ((dirent = readdir(dir)) != 0) + { + snprintf(filename, sizeof(filename), "%s/%s", fulldir, dirent->d_name); + if(stat(filename, &filestat) != 0) + continue; + + snprintf(filename, sizeof(filename), dirent->d_name); + + if (strcmp(filename, ".") != 0 && strcmp(filename, "..") != 0) + { + BROWSERENTRY newEntry; + memset(&newEntry, 0, sizeof(BROWSERENTRY)); // clear the new entry + strlcpy(newEntry.filename, filename, sizeof(newEntry.filename)); + strlcpy(newEntry.displayname, filename, sizeof(newEntry.displayname)); + newEntry.length = filestat.st_size; + newEntry.isdir = (filestat.st_mode & S_IFDIR) == 0 ? 0 : 1; // flag this as a dir + if (ParseFilter(Filter, &newEntry)) browser->browserList.push_back(newEntry); + } + } + + // close directory + closedir(dir); + + // Sort the file list + std::sort(browser->browserList.begin(), browser->browserList.end()); + return 0; +} +int ParseDirectory(int Device, int Flags, FILTERCASCADE *Filter) +{ + if (Device >= 0 && Device < (int) browsers.size()) + { + int old_curDevice = curDevice; + curDevice = Device; + browser = &browsers[curDevice]; + if (ParseDirectory((char*) NULL, Flags, Filter) == 0) return 0; + curDevice = old_curDevice; + browser = &browsers[old_curDevice]; + } + return -1; +} + +/**************************************************************************** + * BrowseDevice + * Displays a list of files on the selected path + ***************************************************************************/ +int BrowseDevice(char * Path, int Path_size, int Flags, FILTERCASCADE *Filter/*=NULL*/) +{ + int result = -1; + int i; + + if (InitBrowsers() || ParseDirectory(Path, Flags, Filter)) + { + WindowPrompt(tr( "Error" ), 0, tr( "OK" )); + return -1; + } + int menu = MENU_NONE; + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + GuiImageData folderImgData(Resources::GetFile("icon_folder.png"), Resources::GetFileSize("icon_folder.png")); + GuiImage folderImg(&folderImgData); + GuiButton folderBtn(folderImg.GetWidth(), folderImg.GetHeight()); + folderBtn.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + folderBtn.SetPosition(-210, -145); + folderBtn.SetImage(&folderImg); + folderBtn.SetTrigger(&trigA); + folderBtn.SetEffectGrow(); + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiText ExitBtnTxt(tr( "Cancel" ), 24, ( GXColor ) {0, 0, 0, 255}); + GuiImage ExitBtnImg(&btnOutline); + if (Settings.wsprompt) + { + ExitBtnTxt.SetWidescreen(Settings.widescreen); + ExitBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton ExitBtn(btnOutline.GetWidth(), btnOutline.GetHeight()); + ExitBtn.SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + ExitBtn.SetPosition(-40, -35); + ExitBtn.SetLabel(&ExitBtnTxt); + ExitBtn.SetImage(&ExitBtnImg); + ExitBtn.SetTrigger(&trigA); + ExitBtn.SetTrigger(&trigB); + ExitBtn.SetEffectGrow(); + + GuiText usbBtnTxt(browsers[(curDevice + 1) % browsers.size()].rootdir, 24, ( GXColor ) {0, 0, 0, 255}); + GuiImage usbBtnImg(&btnOutline); + if (Settings.wsprompt) + { + usbBtnTxt.SetWidescreen(Settings.widescreen); + usbBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton usbBtn(btnOutline.GetWidth(), btnOutline.GetHeight()); + usbBtn.SetAlignment(ALIGN_CENTER, ALIGN_BOTTOM); + usbBtn.SetPosition(0, -35); + usbBtn.SetLabel(&usbBtnTxt); + usbBtn.SetImage(&usbBtnImg); + usbBtn.SetTrigger(&trigA); + usbBtn.SetEffectGrow(); + + GuiText okBtnTxt(tr( "OK" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + GuiImage okBtnImg(&btnOutline); + if (Settings.wsprompt) + { + okBtnTxt.SetWidescreen(Settings.widescreen); + okBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton okBtn(&okBtnImg, &okBtnImg, 0, 4, 40, -35, &trigA, btnSoundOver, btnSoundClick2, 1); + okBtn.SetLabel(&okBtnTxt); + + GuiFileBrowser fileBrowser(396, 248); + fileBrowser.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + fileBrowser.SetPosition(0, 120); + + GuiImageData Address(Resources::GetFile("addressbar_textbox.png"), Resources::GetFileSize("addressbar_textbox.png")); + GuiText AdressText((char*) NULL, 20, ( GXColor ) {0, 0, 0, 255}); + AdressText.SetTextf("%s%s", browser->rootdir, browser->dir); + AdressText.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + AdressText.SetPosition(20, 0); + AdressText.SetMaxWidth(Address.GetWidth() - 40, SCROLL_HORIZONTAL); + GuiImage AdressbarImg(&Address); + GuiButton Adressbar(Address.GetWidth(), Address.GetHeight()); + Adressbar.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + Adressbar.SetPosition(0, fileBrowser.GetTop() - 45); + Adressbar.SetImage(&AdressbarImg); + Adressbar.SetLabel(&AdressText); + + HaltGui(); + GuiWindow w(screenwidth, screenheight); + w.Append(&ExitBtn); + // w.Append(&titleTxt); + w.Append(&fileBrowser); + w.Append(&Adressbar); + w.Append(&okBtn); + if (!(Flags & FB_NOFOLDER_BTN)) w.Append(&folderBtn); + if (browsers.size() > 1 && !(Flags & FB_NODEVICE_BTN)) w.Append(&usbBtn); + mainWindow->Append(&w); + ResumeGui(); + int clickedIndex = -1; + while (menu == MENU_NONE) + { + VIDEO_WaitVSync(); + + if (shutdown == 1) Sys_Shutdown(); + + if (reset == 1) Sys_Reboot(); + + for (i = 0; i < FILEBROWSERSIZE; i++) + { + if (fileBrowser.fileList[i]->GetState() == STATE_CLICKED) + { + fileBrowser.fileList[i]->ResetState(); + + clickedIndex = browser->pageIndex + i; + bool pathCanged = false; + // check corresponding browser entry + if (browser->browserList[clickedIndex].isdir) + { + /* go up to parent directory */ + if (strcmp(browser->browserList[clickedIndex].filename, "..") == 0) + { + /* remove last subdirectory name */ + int len = strlen(browser->dir); + while (browser->dir[0] && browser->dir[len - 1] == '/') + browser->dir[--len] = '\0'; // remove all trailing '/' + char *cptr = strrchr(browser->dir, '/'); + if (cptr) + *++cptr = 0; + else browser->dir[0] = '\0'; // remove trailing dir + pathCanged = true; + } + /* Open a directory */ + /* current directory doesn't change */ + else if (strcmp(browser->browserList[clickedIndex].filename, ".")) + { + /* test new directory namelength */ + if ((strlen(browser->dir) + strlen(browser->browserList[clickedIndex].filename) + 1/*'/'*/) + < MAXPATHLEN) + { + /* update current directory name */ + sprintf(browser->dir, "%s%s/", browser->dir, browser->browserList[clickedIndex].filename); + pathCanged = true; + } + } + if (pathCanged) + { + LOCK( &fileBrowser ); + ParseDirectory((char*) NULL, Flags, Filter); + fileBrowser.ResetState(); + fileBrowser.UpdateList(); + AdressText.SetTextf("%s%s", browser->rootdir, browser->dir); + } + clickedIndex = -1; + } + else /* isFile */ + { + AdressText.SetTextf("%s%s%s", browser->rootdir, browser->dir, + browser->browserList[clickedIndex].filename); + } + } + } + + if (ExitBtn.GetState() == STATE_CLICKED) + { + result = 0; + break; + } + else if (okBtn.GetState() == STATE_CLICKED) + { + if (clickedIndex >= 0) + snprintf(Path, Path_size, "%s%s%s", browser->rootdir, browser->dir, + browser->browserList[clickedIndex].filename); + else snprintf(Path, Path_size, "%s%s", browser->rootdir, browser->dir); + result = 1; + break; + } + else if (usbBtn.GetState() == STATE_CLICKED) + { + usbBtn.ResetState(); + for (u32 i = 1; i < browsers.size(); i++) + { + LOCK( &fileBrowser ); + if (ParseDirectory((curDevice + i) % browsers.size(), Flags, Filter) == 0) + { + fileBrowser.ResetState(); + fileBrowser.UpdateList(); + AdressText.SetTextf("%s%s", browser->rootdir, browser->dir); + usbBtnTxt.SetText(browsers[(curDevice + 1) % browsers.size()].rootdir); + break; + } + } + } + else if (folderBtn.GetState() == STATE_CLICKED) + { + folderBtn.ResetState(); + + HaltGui(); + mainWindow->Remove(&w); + ResumeGui(); + char newfolder[100]; + char oldfolder[100]; + snprintf(newfolder, sizeof(newfolder), "%s%s", browser->rootdir, browser->dir); + strcpy(oldfolder, newfolder); + + int result = OnScreenKeyboard(newfolder, sizeof(newfolder), strlen(browser->rootdir)); + if (result == 1) + { + unsigned int len = strlen(newfolder); + if (len > 0 && len + 1 < sizeof(newfolder) && newfolder[len - 1] != '/') + { + newfolder[len] = '/'; + newfolder[len + 1] = '\0'; + } + + struct stat st; + if (stat(newfolder, &st) != 0) + { + if (WindowPrompt(tr( "Directory does not exist!" ), + tr( "The entered directory does not exist. Would you like to create it?" ), + tr( "OK" ), tr( "Cancel" )) == 1) if (CreateSubfolder(newfolder) == false) WindowPrompt( + tr( "Error !" ), tr( "Can't create directory" ), tr( "OK" )); + } + if (ParseDirectory(newfolder, Flags, Filter) == 0) + { + fileBrowser.ResetState(); + fileBrowser.UpdateList(); + AdressText.SetTextf("%s%s", browser->rootdir, browser->dir); + usbBtnTxt.SetText(browsers[(curDevice + 1) % browsers.size()].rootdir); + } + } + HaltGui(); + mainWindow->Append(&w); + ResumeGui(); + } + + } + HaltGui(); + mainWindow->Remove(&w); + ResumeGui(); + + //} + + return result; +} + +int BrowseDevice(char * Path, int Path_size, int Flags, FILEFILTERCALLBACK Filter, void *FilterArgs) +{ + if (Filter) + { + FILTERCASCADE filter = { Filter, FilterArgs, NULL }; + return BrowseDevice(Path, Path_size, Flags, &filter); + } + return BrowseDevice(Path, Path_size, Flags); +} diff --git a/source/prompts/filebrowser.h b/source/prompts/filebrowser.h new file mode 100644 index 0000000..31d2fcd --- /dev/null +++ b/source/prompts/filebrowser.h @@ -0,0 +1,79 @@ +/**************************************************************************** + * libwiigui Template + * Tantric 2009 + * + * modified by dimok and ardi + * + * filebrowser.h + * + * Generic file routines - reading, writing, browsing + ****************************************************************************/ + +#ifndef _FILEBROWSER_H_ +#define _FILEBROWSER_H_ + +#include +#include +#include + +#define MAXJOLIET 255 +#define MAXDISPLAY MAXPATHLEN +#define ROOTDIRLEN 10 + +typedef struct +{ + u64 offset; // DVD offset + u64 length; // file length in 64 bytes for sizes higher than 4GB + char isdir; // 0 - file, 1 - directory + char filename[MAXJOLIET + 1]; // full filename + char displayname[MAXDISPLAY + 1]; // name for browser display +} BROWSERENTRY; + +typedef struct +{ + char dir[MAXPATHLEN]; // directory path of browserList + char rootdir[ROOTDIRLEN];// directory path of browserList + int pageIndex; // starting index of browserList page display + std::vector browserList; +} BROWSERINFO; +extern BROWSERINFO *browser; + +#define FB_NOFOLDER_BTN 0x0001 +#define FB_NODEVICE_BTN 0x0002 +#define FB_TRYROOTDIR 0x0004 +#define FB_TRYSTDDEV 0x0008 +#define FB_DEFAULT (FB_TRYROOTDIR | FB_TRYSTDDEV) + +typedef int (*FILEFILTERCALLBACK)(BROWSERENTRY *Entry, void* Args); +int noDIRS(BROWSERENTRY *Entry, void* Args); +int noFILES(BROWSERENTRY *Entry, void* Args); +int noEXT(BROWSERENTRY *Entry, void* Args); + +typedef struct _FILTERCASCADE +{ + FILEFILTERCALLBACK filter; + void *filter_args; + _FILTERCASCADE *next; +} FILTERCASCADE; + +/**************************************************************************** + * BrowseDevice + * Displays a list of files on the selected path + * Path returns the selectet Path/File + * Path_size is the space of the Path-array + * Ret: 0 ok / -1 Error + ***************************************************************************/ +/*************************************************************************** + * Example: + * FILTERKASKADE filter2 = {noEXT, NULL, NULL}; + * FILTERKASKADE filter1 = {noDirs, NULL, &filter2}; + * char Path[MAXPATHLEN] = "SD:/"; + * BrowseDevice(Path, MAXPATHLEN, FB_DEFAULT, &filter1); + * + * + ***************************************************************************/ +int BrowseDevice(char * Path, int Path_size, int Flags/*=FB_DEFAULT*/, FILTERCASCADE *Filter = NULL); +int BrowseDevice(char * Path, int Path_size, int Flags, FILEFILTERCALLBACK Filter, void *FilterArgs = NULL); + +#endif + diff --git a/source/prompts/gameinfo.cpp b/source/prompts/gameinfo.cpp new file mode 100644 index 0000000..cfeb4a3 --- /dev/null +++ b/source/prompts/gameinfo.cpp @@ -0,0 +1,1184 @@ +#include +#include +#include +#include +#include +#include + +#include "usbloader/wbfs.h" +#include "settings/CGameCategories.hpp" +#include "language/gettext.h" +#include "GUI/gui.h" +#include "GUI/Text.hpp" +#include "menu.h" +#include "menu/menus.h" +#include "sys.h" +#include "wpad.h" +#include "FileOperations/fileops.h" +#include "prompts/PromptWindows.h" +#include "themes/CTheme.h" +#include "settings/GameTitles.h" +#include "gameinfo.h" +#include "usbloader/GameList.h" +#include "gecko.h" +#include "xml/GameTDB.hpp" +#include "utils/ShowError.h" +#include "BoxCover/BoxCover.hpp" + +static inline const char * ConsoleFromTitleID(const char* TitleID) +{ + switch (TitleID[0]) + { + case 'W': return "WiiWare"; + case 'D': return "VC_Arcade"; + case 'H': return "Wii_System_Channel"; + case 'F': return "VC_NES"; + case 'G': return "GameCube"; + case 'J': return "VC_SNES"; + case 'N': return "VC_N64"; + case 'L': return "VC_Master_System"; + case 'M': return "VC_Genesis_Megadrive"; + case 'E': return "VC_NeoGeo"; + case 'C': return "VC_Commodore"; + case 'X': return "VC_MSX"; + case 'P': return "VC_TurboGraphX"; + case 'Q': return "VC_TurboGraphX-CD"; + case 'R': return "Wii_Game_Disc"; + case 'S': return "Wii_Game_Disc"; + default: return "Unknown"; + } +} + +static inline const char * HdrTypeText(u8 type) +{ + switch (type) + { + + case TYPE_GAME_WII_IMG : return "Wii_Image"; + case TYPE_GAME_WII_DISC : return "Wii_Disc"; + case TYPE_GAME_GC_IMG : return "Gamecube_Image"; + case TYPE_GAME_GC_DISC : return "Gamecube_Disc"; + case TYPE_GAME_GC_EXTRACTED : return "Gamecube_Extracted"; + case TYPE_GAME_NANDCHAN : return "Channel_NAND"; + case TYPE_GAME_EMUNANDCHAN : return "Channel_EmuNAND"; + default : return "Unknown"; + } +} + +/**************************************************************************** + * gameinfo + ***************************************************************************/ +static int InternalShowGameInfo(struct discHdr *header) +{ + mainWindow->SetState(STATE_DISABLED); + + char ID[7]; + strlcpy(ID, (char *) header->id, sizeof(ID)); + + char xmlpath[300]; + snprintf(xmlpath, sizeof(xmlpath), "%swiitdb.xml", Settings.titlestxt_path); + + GameTDB XML_DB; + + if(!XML_DB.OpenFile(xmlpath)) + { + ShowError(tr("Could not open wiitdb.xml.")); + return -1; + } + + XML_DB.SetLanguageCode(Settings.db_language); + + GameXMLInfo GameInfo; + + if(!XML_DB.GetGameXMLInfo(ID, &GameInfo)) + { + ShowError(tr("Could not find info for this game in the wiitdb.xml.")); + return -1; + } + + XML_DB.CloseFile(); + + int choice = -1; + int titley = 10; + int marginY = titley + 40; + int indexy = marginY; + int wifiY = 0; + int intputX = 200, inputY = -30, txtXOffset = 90; + u8 nunchuk = 0, classiccontroller = 0, balanceboard = 0, dancepad = 0, guitar = 0, gamecube = 0, wheel = 0, + motionplus = 0, drums = 0, microphone = 0, zapper = 0, nintendods = 0, + //vitalitysensor=0, + wiispeak = 0; + int newline = 1; + u8 page = 1; + + BoxCover * boxCov = NULL; + GuiImageData * playersImgData = NULL; + GuiImage * playersImg = NULL; + + GuiImageData * wifiplayersImgData = NULL; + GuiImage * wifiplayersImg = NULL; + GuiImage * ratingImg = NULL; + + GuiImage * classiccontrollerImg = NULL; + GuiImage * nunchukImg = NULL; + GuiImage * guitarImg = NULL; + GuiImage * drumsImg = NULL; + GuiImage * dancepadImg = NULL; + GuiImage * motionplusImg = NULL; + GuiImage * wheelImg = NULL; + GuiImage * balanceboardImg = NULL; + GuiImage * microphoneImg = NULL; + GuiImage * zapperImg = NULL; + GuiImage * nintendodsImg = NULL; + GuiImage * wiispeakImg = NULL; + //GuiImage * vitalitysensorImg = NULL; + GuiImage * gcImg = NULL; + GuiImage * dialogBoxImg1 = NULL; + GuiImage * dialogBoxImg2 = NULL; + GuiImage * dialogBoxImg3 = NULL; + GuiImage * dialogBoxImg4 = NULL; + GuiImage * dialogBoxImg11 = NULL; + GuiImage * dialogBoxImg22 = NULL; + GuiImage * dialogBoxImg33 = NULL; + GuiImage * dialogBoxImg44 = NULL; + GuiImage * coverImg = NULL; + + GuiImageData * classiccontrollerImgData = NULL; + GuiImageData * nunchukImgData = NULL; + GuiImageData * guitarImgData = NULL; + GuiImageData * drumsImgData = NULL; + GuiImageData * motionplusImgData = NULL; + GuiImageData * wheelImgData = NULL; + GuiImageData * balanceboardImgData = NULL; + GuiImageData * dancepadImgData = NULL; + GuiImageData * microphoneImgData = NULL; + GuiImageData * zapperImgData = NULL; + GuiImageData * nintendodsImgData = NULL; + GuiImageData * wiispeakImgData = NULL; + //GuiImageData * vitalitysensorImgData = NULL; + GuiImageData * gamecubeImgData = NULL; + GuiImageData * ratingImgData = NULL; + GuiImageData * cover = NULL; + + GuiText * releasedTxt = NULL; + GuiText * publisherTxt = NULL; + GuiText * developerTxt = NULL; + GuiText * titleTxt = NULL; + Text * synopsisTxt = NULL; + GuiText * genreTitleTxt = NULL; + GuiText ** genreTxt = NULL; + GuiText ** wifiTxt = NULL; + GuiText * gametdb1Txt = NULL; + GuiText * memTxt = NULL; + + GuiWindow gameinfoWindow(600, 308); + gameinfoWindow.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + gameinfoWindow.SetPosition(0, -50); + + GuiWindow InfoWindow(600, 308); + InfoWindow.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + + GuiWindow txtWindow(350, 270); + txtWindow.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + txtWindow.SetPosition(95, 40); + + GuiImageData dialogBox1(Resources::GetFile("gameinfo1.png"), Resources::GetFileSize("gameinfo1.png")); + GuiImageData dialogBox2(Resources::GetFile("gameinfo1a.png"), Resources::GetFileSize("gameinfo1a.png")); + GuiImageData dialogBox3(Resources::GetFile("gameinfo2.png"), Resources::GetFileSize("gameinfo2.png")); + GuiImageData dialogBox4(Resources::GetFile("gameinfo2a.png"), Resources::GetFileSize("gameinfo2a.png")); + + GuiTrigger trig1; + trig1.SetButtonOnlyTrigger(-1, WPAD_BUTTON_1 | WPAD_CLASSIC_BUTTON_X, 0); + GuiTrigger trigA; + trigA.SetButtonOnlyTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + GuiTrigger trigU; + trigU.SetButtonOnlyTrigger(-1, WPAD_BUTTON_UP | WPAD_CLASSIC_BUTTON_UP, PAD_BUTTON_UP); + GuiTrigger trigD; + trigD.SetButtonOnlyTrigger(-1, WPAD_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_DOWN, PAD_BUTTON_DOWN); + GuiTrigger trigH; + trigH.SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, 0); + + //buttons for changing between synopsis and other info + GuiButton backBtn(0, 0); + backBtn.SetPosition(-20, -20); + backBtn.SetTrigger(&trigB); + gameinfoWindow.Append(&backBtn); + + GuiTrigger trigA_Simple; + trigA_Simple.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + GuiTrigger trigLeft; + trigLeft.SetButtonOnlyTrigger(-1, WPAD_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_LEFT, PAD_BUTTON_LEFT); + + GuiTrigger trigRight; + trigRight.SetButtonOnlyTrigger(-1, WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT, PAD_BUTTON_RIGHT); + + GuiButton LeftBtn(0, 0); + LeftBtn.SetTrigger(&trigLeft); + if(header->type != TYPE_GAME_WII_DISC && header->type != TYPE_GAME_GC_DISC) + gameinfoWindow.Append(&LeftBtn); + + GuiButton RightBtn(0, 0); + RightBtn.SetTrigger(&trigRight); + if(header->type != TYPE_GAME_WII_DISC && header->type != TYPE_GAME_GC_DISC) + gameinfoWindow.Append(&RightBtn); + + GuiButton coverBtn(180, 250); + coverBtn.SetPosition(20, 20); + coverBtn.SetTrigger(&trigA_Simple); + gameinfoWindow.Append(&coverBtn); + + GuiButton nextBtn(400, 300); + nextBtn.SetPosition(200, 20); + nextBtn.SetTrigger(&trigA_Simple); + gameinfoWindow.Append(&nextBtn); + + //buttons for scrolling the synopsis + GuiButton upBtn(0, 0); + upBtn.SetPosition(0, 0); + upBtn.SetTrigger(&trigU); + + GuiButton dnBtn(0, 0); + dnBtn.SetPosition(0, 0); + dnBtn.SetTrigger(&trigD); + + GuiButton homeBtn(0, 0); + homeBtn.SetPosition(0, 0); + homeBtn.SetTrigger(&trigH); + gameinfoWindow.Append(&homeBtn); + + char linebuf2[100] = ""; + + // enable icons for required accessories + for (u32 i = 0; i < GameInfo.AccessoirList.size(); ++i) + { + if(!GameInfo.AccessoirList[i].Required) + continue; + + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "classiccontroller") == 0) classiccontroller = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "nunchuk") == 0) nunchuk = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "guitar") == 0) guitar = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "drums") == 0) drums = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "dancepad") == 0) dancepad = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "motionplus") == 0) motionplus = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "wheel") == 0) wheel = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "balanceboard") == 0) balanceboard = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "microphone") == 0) microphone = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "zapper") == 0) zapper = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "nintendods") == 0) nintendods = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "wiispeak") == 0) wiispeak = 1; + //if (strcmp(GameInfo.AccessoirList[i].Name.c_str(),"vitalitysensor")==0) + // vitalitysensor=1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "gamecube") == 0) gamecube = 1; + } + + // switch icons + if (nunchuk) + nunchukImgData = Resources::GetImageData("nunchukR.png"); + else nunchukImgData = Resources::GetImageData("nunchuk.png"); + + if (classiccontroller) + classiccontrollerImgData = Resources::GetImageData("classiccontrollerR.png"); + else classiccontrollerImgData = Resources::GetImageData("classiccontroller.png"); + + if (guitar) + guitarImgData = Resources::GetImageData("guitarR.png"); + else guitarImgData = Resources::GetImageData("guitar.png"); + + if (gamecube) + gamecubeImgData = Resources::GetImageData("gcncontrollerR.png"); + else gamecubeImgData = Resources::GetImageData("gcncontroller.png"); + + if (wheel) + wheelImgData = Resources::GetImageData("wheelR.png"); + else wheelImgData = Resources::GetImageData("wheel.png"); + + if (motionplus) + motionplusImgData = Resources::GetImageData("motionplusR.png"); + else motionplusImgData = Resources::GetImageData("motionplus.png"); + + if (drums) + drumsImgData = Resources::GetImageData("drumsR.png"); + else drumsImgData = Resources::GetImageData("drums.png"); + + if (microphone) + microphoneImgData = Resources::GetImageData("microphoneR.png"); + else microphoneImgData = Resources::GetImageData("microphone.png"); + + if (zapper) + zapperImgData = Resources::GetImageData("zapperR.png"); + else zapperImgData = Resources::GetImageData("zapper.png"); + + if (wiispeak) + wiispeakImgData = Resources::GetImageData("wiispeakR.png"); + else wiispeakImgData = Resources::GetImageData("wiispeak.png"); + + if (nintendods) + nintendodsImgData = Resources::GetImageData("nintendodsR.png"); + else nintendodsImgData = Resources::GetImageData("nintendods.png"); + + if (balanceboard) + balanceboardImgData = Resources::GetImageData("balanceboardR.png"); + else balanceboardImgData = Resources::GetImageData("balanceboard.png"); + + if (dancepad) + dancepadImgData = Resources::GetImageData("dancepadR.png"); + else dancepadImgData = Resources::GetImageData("dancepad.png"); + + // look for optional accessories + for (u32 i = 0; i < GameInfo.AccessoirList.size(); ++i) + { + if(GameInfo.AccessoirList[i].Required) + continue; + + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "classiccontroller") == 0) classiccontroller = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "nunchuk") == 0) nunchuk = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "guitar") == 0) guitar = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "drums") == 0) drums = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "dancepad") == 0) dancepad = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "motionplus") == 0) motionplus = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "wheel") == 0) wheel = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "balanceboard") == 0) balanceboard = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "microphone") == 0) microphone = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "zapper") == 0) zapper = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "nintendods") == 0) nintendods = 1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "wiispeak") == 0) wiispeak = 1; + //if (strcmp(GameInfo.AccessoirList[i].Name.c_str(),"vitalitysensor")==0) + // vitalitysensor=1; + if (strcmp(GameInfo.AccessoirList[i].Name.c_str(), "gamecube") == 0) gamecube = 1; + } + + dialogBoxImg1 = new GuiImage(&dialogBox1); + dialogBoxImg1->SetAlignment(0, 3); + dialogBoxImg1->SetPosition(-9, 0); + + dialogBoxImg2 = new GuiImage(&dialogBox2); + dialogBoxImg2->SetAlignment(0, 3); + dialogBoxImg2->SetPosition(145, 0); + + dialogBoxImg3 = new GuiImage(&dialogBox3); + dialogBoxImg3->SetAlignment(0, 3); + dialogBoxImg3->SetPosition(301, 0); + + dialogBoxImg4 = new GuiImage(&dialogBox4); + dialogBoxImg4->SetAlignment(0, 3); + dialogBoxImg4->SetPosition(457, 0); + + gameinfoWindow.Append(dialogBoxImg1); + gameinfoWindow.Append(dialogBoxImg2); + gameinfoWindow.Append(dialogBoxImg3); + gameinfoWindow.Append(dialogBoxImg4); + + bool loadFlatCover = false; + bool load3DCover = false; + char imgPath[150]; + snprintf(imgPath, sizeof(imgPath), "%s/%s.png", Settings.coversFull_path, ID); + if(!CheckFile(imgPath)) + { + loadFlatCover = true; + snprintf(imgPath, sizeof(imgPath), "%s/%s.png", Settings.covers2d_path, ID); + } + if(!CheckFile(imgPath)) + { + loadFlatCover = false; + load3DCover = true; + snprintf(imgPath, sizeof(imgPath), "%s/%s.png", Settings.covers_path, ID); + } + cover = new GuiImageData(imgPath); //load full id image + if (!cover->GetImage()) + { + delete cover; + cover = NULL; + } + + if(load3DCover && cover) //! No cover is always 3D box + { + coverImg = new GuiImage(cover); + coverImg->SetWidescreen(Settings.widescreen); + coverImg->SetPosition(15, 30); + } + else + { + boxCov = new BoxCover(cover, loadFlatCover); + boxCov->SetPosition(-1.6f, 0.4f, -27.0f); + boxCov->SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 40); + + if(GameInfo.CaseColor == 0xFF0000) + { + boxCov->SetBoxColor((GXColor) { 198, 34, 4, 255 }); + } + else if(GameInfo.CaseColor >= 0) + { + u8 * Color = (u8 *) &GameInfo.CaseColor; + boxCov->SetBoxColor((GXColor) { Color[1], Color[2], Color[3], 255 }); + } + + gameinfoWindow.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 100); + } + + // # of players + if (GameInfo.Players > 0) + { + if (GameInfo.Players == 1) + playersImgData = Resources::GetImageData("wiimote1.png"); + + else if (GameInfo.Players == 2) + playersImgData = Resources::GetImageData("wiimote2.png"); + + else if (GameInfo.Players == 3) + playersImgData = Resources::GetImageData("wiimote3.png"); + + else if (GameInfo.Players == 4) + playersImgData = Resources::GetImageData("wiimote4.png"); + + playersImg = new GuiImage(playersImgData); + playersImg->SetWidescreen(Settings.widescreen); + playersImg->SetPosition(intputX, inputY); + playersImg->SetAlignment(0, 4); + InfoWindow.Append(playersImg); + intputX += (Settings.widescreen ? playersImg->GetWidth() * Settings.WSFactor : playersImg->GetWidth()) + 5; + } + + //draw the input types for this game + if (motionplus == 1) + { + motionplusImg = new GuiImage(motionplusImgData); + motionplusImg->SetWidescreen(Settings.widescreen); + motionplusImg->SetPosition(intputX, inputY); + motionplusImg->SetAlignment(0, 4); + InfoWindow.Append(motionplusImg); + intputX += (Settings.widescreen ? motionplusImg->GetWidth() * Settings.WSFactor : motionplusImg->GetWidth()) + 5; + } + if (nunchuk == 1) + { + nunchukImg = new GuiImage(nunchukImgData); + nunchukImg->SetWidescreen(Settings.widescreen); + nunchukImg->SetPosition(intputX, inputY); + nunchukImg->SetAlignment(0, 4); + InfoWindow.Append(nunchukImg); + intputX += (Settings.widescreen ? nunchukImg->GetWidth() * Settings.WSFactor : nunchukImg->GetWidth()) + 5; + } + if (classiccontroller == 1) + { + classiccontrollerImg = new GuiImage(classiccontrollerImgData); + classiccontrollerImg->SetWidescreen(Settings.widescreen); + classiccontrollerImg->SetPosition(intputX, inputY); + classiccontrollerImg->SetAlignment(0, 4); + InfoWindow.Append(classiccontrollerImg); + intputX += (Settings.widescreen ? classiccontrollerImg->GetWidth() * Settings.WSFactor : classiccontrollerImg->GetWidth()) + 5; + } + if (gamecube == 1) + { + gcImg = new GuiImage(gamecubeImgData); + gcImg->SetWidescreen(Settings.widescreen); + gcImg->SetPosition(intputX, inputY); + gcImg->SetAlignment(0, 4); + InfoWindow.Append(gcImg); + intputX += (Settings.widescreen ? gcImg->GetWidth() * Settings.WSFactor : gcImg->GetWidth()) + 5; + } + if (wheel == 1) + { + wheelImg = new GuiImage(wheelImgData); + wheelImg->SetWidescreen(Settings.widescreen); + wheelImg->SetPosition(intputX, inputY); + wheelImg->SetAlignment(0, 4); + InfoWindow.Append(wheelImg); + intputX += (Settings.widescreen ? wheelImg->GetWidth() * Settings.WSFactor : wheelImg->GetWidth()) + 5; + } + if (guitar == 1) + { + guitarImg = new GuiImage(guitarImgData); + guitarImg->SetWidescreen(Settings.widescreen); + guitarImg->SetPosition(intputX, inputY); + guitarImg->SetAlignment(0, 4); + InfoWindow.Append(guitarImg); + intputX += (Settings.widescreen ? guitarImg->GetWidth() * Settings.WSFactor : guitarImg->GetWidth()) + 5; + } + if (drums == 1) + { + drumsImg = new GuiImage(drumsImgData); + drumsImg->SetWidescreen(Settings.widescreen); + drumsImg->SetPosition(intputX, inputY); + drumsImg->SetAlignment(0, 4); + InfoWindow.Append(drumsImg); + intputX += (Settings.widescreen ? drumsImg->GetWidth() * Settings.WSFactor : drumsImg->GetWidth()) + 5; + } + if (microphone == 1) + { + microphoneImg = new GuiImage(microphoneImgData); + microphoneImg->SetWidescreen(Settings.widescreen); + microphoneImg->SetPosition(intputX, inputY); + microphoneImg->SetAlignment(0, 4); + InfoWindow.Append(microphoneImg); + intputX += (Settings.widescreen ? microphoneImg->GetWidth() * Settings.WSFactor : microphoneImg->GetWidth()) + 5; + } + if (zapper == 1) + { + zapperImg = new GuiImage(zapperImgData); + zapperImg->SetWidescreen(Settings.widescreen); + zapperImg->SetPosition(intputX, inputY); + zapperImg->SetAlignment(0, 4); + InfoWindow.Append(zapperImg); + intputX += (Settings.widescreen ? zapperImg->GetWidth() * Settings.WSFactor : zapperImg->GetWidth()) + 5; + } + if (wiispeak == 1) + { + wiispeakImg = new GuiImage(wiispeakImgData); + wiispeakImg->SetWidescreen(Settings.widescreen); + wiispeakImg->SetPosition(intputX, inputY); + wiispeakImg->SetAlignment(0, 4); + InfoWindow.Append(wiispeakImg); + intputX += (Settings.widescreen ? wiispeakImg->GetWidth() * Settings.WSFactor : wiispeakImg->GetWidth()) + 5; + } + if (nintendods == 1) + { + nintendodsImg = new GuiImage(nintendodsImgData); + nintendodsImg->SetWidescreen(Settings.widescreen); + nintendodsImg->SetPosition(intputX, inputY); + nintendodsImg->SetAlignment(0, 4); + InfoWindow.Append(nintendodsImg); + intputX += (Settings.widescreen ? nintendodsImg->GetWidth() * Settings.WSFactor : nintendodsImg->GetWidth()) + 5; + } + if (dancepad == 1) + { + dancepadImg = new GuiImage(dancepadImgData); + dancepadImg->SetWidescreen(Settings.widescreen); + dancepadImg->SetPosition(intputX, inputY); + dancepadImg->SetAlignment(0, 4); + InfoWindow.Append(dancepadImg); + intputX += (Settings.widescreen ? dancepadImg->GetWidth() * Settings.WSFactor : dancepadImg->GetWidth()) + 5; + } + if (balanceboard == 1) + { + balanceboardImg = new GuiImage(balanceboardImgData); + balanceboardImg->SetWidescreen(Settings.widescreen); + balanceboardImg->SetPosition(intputX, inputY); + balanceboardImg->SetAlignment(0, 4); + InfoWindow.Append(balanceboardImg); + intputX += (Settings.widescreen ? balanceboardImg->GetWidth() * Settings.WSFactor : balanceboardImg->GetWidth()) + 5; + } + + // # online players + if (GameInfo.WifiPlayers > 0) + { + if(GameInfo.WifiPlayers == 1) + wifiplayersImgData = Resources::GetImageData("wifi1.png"); + + else if(GameInfo.WifiPlayers == 2) + wifiplayersImgData = Resources::GetImageData("wifi2.png"); + + else if(GameInfo.WifiPlayers == 4) + wifiplayersImgData = Resources::GetImageData("wifi4.png"); + + else if(GameInfo.WifiPlayers == 6) + wifiplayersImgData = Resources::GetImageData("wifi6.png"); + + else if(GameInfo.WifiPlayers == 10) + wifiplayersImgData = Resources::GetImageData("wifi10.png"); + + else if(GameInfo.WifiPlayers == 8) + wifiplayersImgData =Resources::GetImageData("wifi8.png"); + + else if(GameInfo.WifiPlayers == 12) + wifiplayersImgData = Resources::GetImageData("wifi12.png"); + + else if(GameInfo.WifiPlayers == 16) + wifiplayersImgData = Resources::GetImageData("wifi16.png"); + + else if(GameInfo.WifiPlayers == 32) + wifiplayersImgData = Resources::GetImageData("wifi32.png"); + + wifiplayersImg = new GuiImage(wifiplayersImgData); + wifiplayersImg->SetWidescreen(Settings.widescreen); + wifiplayersImg->SetPosition(intputX, inputY); + wifiplayersImg->SetAlignment(0, 4); + InfoWindow.Append(wifiplayersImg); + intputX += (Settings.widescreen ? wifiplayersImg->GetWidth() * Settings.WSFactor : wifiplayersImg->GetWidth()) + 5; + } + + // ratings + if (GameInfo.RatingType >= 0) + { + if (GameInfo.RatingType == 1) + { + if (strcmp(GameInfo.RatingValue.c_str(), "EC") == 0) + ratingImgData = Resources::GetImageData("esrb_ec.png"); + else if (strcmp(GameInfo.RatingValue.c_str(), "E") == 0) + ratingImgData = Resources::GetImageData("esrb_e.png"); + else if (strcmp(GameInfo.RatingValue.c_str(), "E10+") == 0) + ratingImgData = Resources::GetImageData("esrb_eten.png"); + else if (strcmp(GameInfo.RatingValue.c_str(), "T") == 0) + ratingImgData = Resources::GetImageData("esrb_t.png"); + else if (strcmp(GameInfo.RatingValue.c_str(), "M") == 0) + ratingImgData = Resources::GetImageData("esrb_m.png"); + else if (strcmp(GameInfo.RatingValue.c_str(), "AO") == 0) + ratingImgData = Resources::GetImageData("esrb_ao.png"); + else + ratingImgData = Resources::GetImageData("norating.png"); + } //there are 2 values here cause some countries are stupid and + else if (GameInfo.RatingType == 2) //can't use the same as everybody else + { + if ((strcmp(GameInfo.RatingValue.c_str(), "3") == 0) || (strcmp(GameInfo.RatingValue.c_str(), "4") == 0)) + ratingImgData = Resources::GetImageData("pegi_3.png"); + else if ((strcmp(GameInfo.RatingValue.c_str(), "7") == 0) || (strcmp(GameInfo.RatingValue.c_str(), "7") == 0)) + ratingImgData = Resources::GetImageData("pegi_7.png"); + else if (strcmp(GameInfo.RatingValue.c_str(), "12") == 0) + ratingImgData = Resources::GetImageData("pegi_12.png"); + else if ((strcmp(GameInfo.RatingValue.c_str(), "16") == 0) || (strcmp(GameInfo.RatingValue.c_str(), "15") == 0)) + ratingImgData = Resources::GetImageData("pegi_16.png"); + else if (strcmp(GameInfo.RatingValue.c_str(), "18") == 0) + ratingImgData = Resources::GetImageData("pegi_18.png"); + else + { + ratingImgData = Resources::GetImageData("norating.png"); + } + } + else if (GameInfo.RatingType == 0) + { + if (strcmp(GameInfo.RatingValue.c_str(), "A") == 0) + ratingImgData = Resources::GetImageData("cero_a.png"); + else if (strcmp(GameInfo.RatingValue.c_str(), "B") == 0) + ratingImgData = Resources::GetImageData("cero_b.png"); + else if (strcmp(GameInfo.RatingValue.c_str(), "C") == 0) + ratingImgData = Resources::GetImageData("cero_c.png"); + else if (strcmp(GameInfo.RatingValue.c_str(), "D") == 0) + ratingImgData = Resources::GetImageData("cero_d.png"); + else if (strcmp(GameInfo.RatingValue.c_str(), "Z") == 0) + ratingImgData = Resources::GetImageData("cero_z.png"); + else + { + ratingImgData = Resources::GetImageData("norating.png"); + } + } + + else + { + ratingImgData = Resources::GetImageData("norating.png"); + } + ratingImg = new GuiImage(ratingImgData); + ratingImg->SetWidescreen(Settings.widescreen); + ratingImg->SetPosition(-25, inputY); + ratingImg->SetAlignment(1, 4); + InfoWindow.Append(ratingImg); + intputX += (Settings.widescreen ? ratingImg->GetWidth() * Settings.WSFactor : ratingImg->GetWidth()) + 5; + } + + // title + int titlefontsize = 25; + if (GameInfo.Title.size() > 0) + { + titleTxt = new GuiText(GameInfo.Title.c_str(), titlefontsize, ( GXColor ) {0, 0, 0, 255}); + titleTxt->SetMaxWidth(350, SCROLL_HORIZONTAL); + titleTxt->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt->SetPosition(txtXOffset, 12 + titley); + InfoWindow.Append(titleTxt); + } + + //date + snprintf(linebuf2, sizeof(linebuf2), " "); + if (GameInfo.PublishDate != 0) + { + int year = GameInfo.PublishDate >> 16; + int day = GameInfo.PublishDate & 0xFF; + int month = (GameInfo.PublishDate >> 8) & 0xFF; + snprintf(linebuf2, sizeof(linebuf2), "%02i ", day); + + switch (month) + { + case 1: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "Jan" )); + break; + case 2: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "Feb" )); + break; + case 3: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "Mar" )); + break; + case 4: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "Apr" )); + break; + case 5: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "May" )); + break; + case 6: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "June" )); + break; + case 7: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "July" )); + break; + case 8: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "Aug" )); + break; + case 9: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "Sept" )); + break; + case 10: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "Oct" )); + break; + case 11: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "Nov" )); + break; + case 12: + snprintf(linebuf2, sizeof(linebuf2), "%s%s ", linebuf2, tr( "Dec" )); + break; + } + + char linebuf[300]; + snprintf(linebuf, sizeof(linebuf), "%s : %s%i", tr( "Released" ), linebuf2, year); + releasedTxt = new GuiText(linebuf, 16, ( GXColor ) {0, 0, 0, 255}); + if (releasedTxt->GetTextWidth() > 300) newline = 2; + releasedTxt->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); + releasedTxt->SetPosition(-17, 12 + indexy); + indexy += (20 * newline); + newline = 1; + InfoWindow.Append(releasedTxt); + } + + //publisher + if (GameInfo.Publisher.size() != 0) + { + snprintf(linebuf2, sizeof(linebuf2), "%s %s", tr( "Published by" ), GameInfo.Publisher.c_str()); + publisherTxt = new GuiText(linebuf2, 16, ( GXColor ) {0, 0, 0, 255}); + if (publisherTxt->GetTextWidth() > 250) newline = 2; + publisherTxt->SetMaxWidth(250, WRAP); + publisherTxt->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); + publisherTxt->SetPosition(-17, 12 + indexy); + indexy += (20 * newline); + newline = 1; + InfoWindow.Append(publisherTxt); + } + + //developer + if (GameInfo.Developer.size() != 0 && strcasecmp(GameInfo.Developer.c_str(), GameInfo.Publisher.c_str()) != 0) + { + snprintf(linebuf2, sizeof(linebuf2), "%s %s", tr( "Developed by" ), GameInfo.Developer.c_str()); + developerTxt = new GuiText(linebuf2, 16, ( GXColor ) {0, 0, 0, 255}); + if (developerTxt->GetTextWidth() > 250) newline = 2; + developerTxt->SetMaxWidth(250, WRAP); + developerTxt->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); + developerTxt->SetPosition(-17, 12 + indexy); + indexy += (20 * newline); + newline = 1; + InfoWindow.Append(developerTxt); + } + + GuiText *categoryTitle = NULL; + std::vector categoriesTxt; + indexy += 10; + + const std::vector gameCategories = GameCategories[ID]; + if(gameCategories.size() > 1) + { + categoryTitle = new GuiText(tr("Categories:"), 16, ( GXColor ) {0, 0, 0, 255}); + categoryTitle->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + categoryTitle->SetPosition(505, 12 + indexy); + indexy += 20; + InfoWindow.Append(categoryTitle); + } + + for (u32 i = 0; i < gameCategories.size(); ++i) + { + if(gameCategories[i] == 0) + continue; + + if(indexy > 170 && gameCategories.size() > i+1) + { + categoriesTxt.push_back(new GuiText("...", 16, ( GXColor ) {0, 0, 0, 255})); + categoriesTxt[categoriesTxt.size()-1]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + categoriesTxt[categoriesTxt.size()-1]->SetPosition(515, 12 + indexy); + indexy += 20; + InfoWindow.Append(categoriesTxt[categoriesTxt.size()-1]); + break; + } + + categoriesTxt.push_back(new GuiText(GameCategories.CategoryList[gameCategories[i]], 16, ( GXColor ) {0, 0, 0, 255})); + categoriesTxt[categoriesTxt.size()-1]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + categoriesTxt[categoriesTxt.size()-1]->SetPosition(515, 12 + indexy); + categoriesTxt[categoriesTxt.size()-1]->SetMaxWidth(74, DOTTED); + indexy += 20; + InfoWindow.Append(categoriesTxt[categoriesTxt.size()-1]); + } + + //genre + int genreY = marginY; + if(GameInfo.GenreList.size() > 0) + { + genreTitleTxt = new GuiText(tr("Genre:"), 16, ( GXColor ) {0, 0, 0, 255}); + genreTitleTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + genreTitleTxt->SetPosition(205, 12 + genreY); + genreY += 20; + InfoWindow.Append(genreTitleTxt); + } + + genreTxt = new GuiText *[GameInfo.GenreList.size()+1]; //to not alloc a 0 vector + for (u32 i = 0; i < GameInfo.GenreList.size(); ++i) + { + genreTxt[i] = new GuiText(GameInfo.GenreList[i].c_str(), 16, ( GXColor ) {0, 0, 0, 255}); + genreTxt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + genreTxt[i]->SetPosition(215, 12 + genreY); + genreY += 20; + InfoWindow.Append(genreTxt[i]); + } + + //online + wifiTxt = new GuiText *[GameInfo.WifiFeatureList.size()+1]; //to not alloc a 0 vector + for (int i = GameInfo.WifiFeatureList.size()-1; i >= 0 && GameInfo.WifiFeatureList.size() > 0; --i) + { + if (strcmp(GameInfo.WifiFeatureList[i].c_str(), "Nintendods") == 0) + { + snprintf(linebuf2, sizeof(linebuf2), "Nintendo DS"); + } + else + { + snprintf(linebuf2, sizeof(linebuf2), "%s", GameInfo.WifiFeatureList[i].c_str()); + } + wifiTxt[i] = new GuiText(linebuf2, 16, ( GXColor ) {0, 0, 0, 255}); + wifiTxt[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + wifiTxt[i]->SetPosition(215, 200 + wifiY); + wifiY -= 20; + InfoWindow.Append(wifiTxt[i]); + } + if (GameInfo.WifiFeatureList.size() > 0) + { + snprintf(linebuf2, sizeof(linebuf2), "%s:", tr( "WiFi Features" )); + } + else + { + linebuf2[0] = 0; + } + wifiTxt[0] = new GuiText(linebuf2, 16, ( GXColor ) {0, 0, 0, 255}); + wifiTxt[0]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + wifiTxt[0]->SetPosition(205, 200 + wifiY); + InfoWindow.Append(wifiTxt[0]); + + //synopsis + int pagesize = 12; + if (GameInfo.Synopsis.size() != 0) + { + synopsisTxt = new Text(GameInfo.Synopsis.c_str(), 16, ( GXColor ) {0, 0, 0, 255}); + synopsisTxt->SetMaxWidth(350); + synopsisTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + synopsisTxt->SetPosition(0, 0); + synopsisTxt->SetLinesToDraw(pagesize); + synopsisTxt->Refresh(); + + txtWindow.Append(synopsisTxt); + txtWindow.Append(&upBtn); + txtWindow.Append(&dnBtn); + } + + gametdb1Txt = new GuiText("http://gametdb.com", 16, ( GXColor ) {0, 0, 0, 255}); + gametdb1Txt->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); + gametdb1Txt->SetPosition(40, -15); + gameinfoWindow.Append(gametdb1Txt); + if(coverImg) + { + gameinfoWindow.Append(coverImg); + txtWindow.SetAlignment(ALIGN_CENTER, ALIGN_TOP); + txtWindow.SetPosition(0, -170); + } + // Set info window first + gameinfoWindow.Append(&InfoWindow); + + HaltGui(); + //mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&gameinfoWindow); + if(boxCov) mainWindow->Append(boxCov); + ResumeGui(); + + while (choice == -1) + { + + VIDEO_WaitVSync(); + if (shutdown == 1) + { + wiilight(0); + Sys_Shutdown(); + } + else if (reset == 1) + Sys_Reboot(); + + else if(LeftBtn.GetState() == STATE_CLICKED) + { + if(gameList.size() > 0) + choice = 3; + LeftBtn.ResetState(); + break; + } + + else if(RightBtn.GetState() == STATE_CLICKED) + { + if(gameList.size() > 0) + choice = 4; + RightBtn.ResetState(); + break; + } + + else if ((backBtn.GetState() == STATE_CLICKED) || (backBtn.GetState() == STATE_HELD)) + { + backBtn.ResetState(); + if (page == 1) + { + choice = 1; + break; + } + else if (page == 2) + { + HaltGui(); + gameinfoWindow.Remove(&txtWindow); + gameinfoWindow.Append(&InfoWindow); + ResumeGui(); + page = 1; + } + } + else if(coverBtn.GetState() == STATE_CLICKED && boxCov) + { + boxCov->SetEffect(EFFECT_BOX_FLY_CENTRE, 100); + gameinfoWindow.Remove(&nextBtn); + gameinfoWindow.Remove(&homeBtn); + gameinfoWindow.Remove(&LeftBtn); + gameinfoWindow.Remove(&RightBtn); + boxCov->SetZoomable(true); + + while(backBtn.GetState() != STATE_CLICKED && homeBtn.GetState() != STATE_CLICKED) + { + usleep(10000); + if (shutdown) + Sys_Shutdown(); + else if (reset) + Sys_Reboot(); + } + + gameinfoWindow.Append(&nextBtn); + gameinfoWindow.Append(&homeBtn); + gameinfoWindow.Append(&LeftBtn); + gameinfoWindow.Append(&RightBtn); + + boxCov->SetZoomable(false); + boxCov->SetEffect(EFFECT_BOX_FLY_BACK, 100); + backBtn.ResetState(); + coverBtn.ResetState(); + + } + else if (((nextBtn.GetState() == STATE_CLICKED) || (nextBtn.GetState() == STATE_HELD)) && GameInfo.Synopsis.size() > 0) + { + nextBtn.ResetState(); + + if (page == 1) + { + HaltGui(); + gameinfoWindow.Remove(&InfoWindow); + gameinfoWindow.Append(&txtWindow); + ResumeGui(); + page = 2; + } + else + { + HaltGui(); + gameinfoWindow.Remove(&txtWindow); + gameinfoWindow.Append(&InfoWindow); + ResumeGui(); + page = 1; + } + + } + else if ((upBtn.GetState() == STATE_CLICKED || upBtn.GetState() == STATE_HELD) && page == 2) + { + synopsisTxt->PreviousLine(); + + usleep(60000); + if (!((ButtonsHold() & WPAD_BUTTON_UP) || (ButtonsHold() & PAD_BUTTON_UP))) upBtn.ResetState(); + + } + else if ((dnBtn.GetState() == STATE_CLICKED || dnBtn.GetState() == STATE_HELD) && page == 2) + { + synopsisTxt->NextLine(); + + usleep(60000); + if (!((ButtonsHold() & WPAD_BUTTON_DOWN) || (ButtonsHold() & PAD_BUTTON_DOWN))) dnBtn.ResetState(); + } + else if (homeBtn.GetState() == STATE_CLICKED) + { + choice = 2; + break; + } + } + + HaltGui(); + gameinfoWindow.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 100); + if(boxCov) boxCov->SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60); + ResumeGui(); + + while (gameinfoWindow.GetEffect() > 0) usleep(100); + HaltGui(); + mainWindow->Remove(&gameinfoWindow); + if(boxCov) mainWindow->Remove(boxCov); + mainWindow->SetState(STATE_DEFAULT); + + delete boxCov; + delete playersImgData; + delete playersImg; + + delete wifiplayersImgData; + delete wifiplayersImg; + delete ratingImg; + + delete classiccontrollerImg; + delete nunchukImg; + delete guitarImg; + delete drumsImg; + delete dancepadImg; + delete motionplusImg; + delete wheelImg; + delete balanceboardImg; + delete microphoneImg; + delete zapperImg; + delete wiispeakImg; + delete nintendodsImg; + delete gcImg; + delete dialogBoxImg1; + delete dialogBoxImg2; + delete dialogBoxImg3; + delete dialogBoxImg4; + delete dialogBoxImg11; + delete dialogBoxImg22; + delete dialogBoxImg33; + delete dialogBoxImg44; + delete coverImg; + delete classiccontrollerImgData; + delete nunchukImgData; + delete guitarImgData; + delete drumsImgData; + delete motionplusImgData; + delete wheelImgData; + delete balanceboardImgData; + delete dancepadImgData; + delete microphoneImgData; + delete zapperImgData; + delete wiispeakImgData; + delete nintendodsImgData; + delete gamecubeImgData; + delete ratingImgData; + delete cover; + delete releasedTxt; + delete publisherTxt; + delete developerTxt; + delete titleTxt; + delete synopsisTxt; + delete genreTitleTxt; + delete gametdb1Txt; + delete memTxt; + delete categoryTitle; + + for (u32 i = 0; i < GameInfo.GenreList.size(); ++i) + delete genreTxt[i]; + + for (u32 i = 0; i < GameInfo.WifiFeatureList.size(); ++i) + delete wifiTxt[i]; + + for (u32 i = 0; i < categoriesTxt.size(); ++i) + delete categoriesTxt[i]; + + delete [] genreTxt; + delete [] wifiTxt; + + ResumeGui(); + + return choice; +} + +int showGameInfo(int gameSelected, struct discHdr *dvdheader) +{ + int choice = 5; + + while(choice > 2) + { + struct discHdr * header = (dvdheader ? dvdheader : gameList[gameSelected]); + + choice = InternalShowGameInfo(header); + + if(choice == 3) + { + --gameSelected; + if(gameSelected < 0) + gameSelected = gameList.size()-1; + } + else if(choice == 4) + { + gameSelected = (gameSelected + 1) % gameList.size(); + } + } + + return choice; +} + +/** + * Save the game list. + * @param csv If true, saves in CSV format; otherwise, saves in TXT format. + */ +bool save_gamelist(bool bCSV) // save gamelist +{ + mainWindow->SetState(STATE_DISABLED); + CreateSubfolder(Settings.update_path); + + // Save the game list. + char tmp[256]; + if(bCSV) + snprintf(tmp, sizeof(tmp), "%sGameList.csv", Settings.update_path); + else + snprintf(tmp, sizeof(tmp), "%sGameList.txt", Settings.update_path); + + FILE *f = fopen(tmp, "w"); + if (!f) + { + mainWindow->SetState(STATE_DEFAULT); + return false; + } + //make sure that all games are added to the gamelist + gameList.LoadUnfiltered(); + + f32 size = 0.0; + f32 freespace, used; + int i; + + WBFS_DiskSpace(&used, &freespace); + + if (bCSV) + { + fprintf(f, "\"ID\",\"Size(GB)\",\"Name\",\"Type\",\"Console\"\n"); + + for (i = 0; i < gameList.size(); i++) + { + struct discHdr* header = gameList[i]; + WBFS_GameSize(header->id, &size); + fprintf(f, "\"%.6s\",\"%.2f\",\"%s\",\"%s\",\"%s\"\n", (char*)header->id, size, GameTitles.GetTitle(header), HdrTypeText(header->type), ConsoleFromTitleID((char*)header->id)); + } + } + else + { + fprintf(f, "# USB Loader Has Saved this file\n"); + fprintf(f, "# This file was created based on your list of games and language settings.\n\n"); + + fprintf(f, "%.2fGB %s %.2fGB %s\n\n", freespace, tr( "of" ), (freespace + used), tr( "free" )); + fprintf(f, "ID Size(GB) Name ; Game type ; Console (based on TitleID) \n"); + + for (i = 0; i < gameList.size(); i++) + { + struct discHdr* header = gameList[i]; + WBFS_GameSize(header->id, &size); + fprintf(f, "%.6s", (char*)header->id); + fprintf(f, " [%.2f] ", size); + fprintf(f, " %s ; ", GameTitles.GetTitle(header)); + fprintf(f, " %s ; ", HdrTypeText(header->type)); + fprintf(f, " %s ", ConsoleFromTitleID((char*)header->id)); + fprintf(f, "\n"); + } + } + fclose(f); + + gameList.FilterList(); + mainWindow->SetState(STATE_DEFAULT); + return true; +} diff --git a/source/prompts/gameinfo.h b/source/prompts/gameinfo.h new file mode 100644 index 0000000..7f9311a --- /dev/null +++ b/source/prompts/gameinfo.h @@ -0,0 +1,16 @@ +/**************************************************************************** + * PromptWindows + * USB Loader GX 2009 + * + * PromptWindows.h + ***************************************************************************/ + +#ifndef _GAMEINFO_H_ +#define _GAMEINFO_H_ + +#include "usbloader/disc.h" + +int showGameInfo(int selectedGame, struct discHdr *header); +bool save_gamelist(bool bCSV); + +#endif diff --git a/source/settings/CCategoryList.cpp b/source/settings/CCategoryList.cpp new file mode 100644 index 0000000..c52b7a5 --- /dev/null +++ b/source/settings/CCategoryList.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include "CCategoryList.hpp" +#include "language/gettext.h" +#include "FileOperations/fileops.h" +#include "svnrev.h" + +#define VALID_CONFIG_REV 1085 + +CCategoryList CategoryList; + +CCategoryList::CCategoryList() +{ + clear(); + goToFirst(); +} + +void CCategoryList::clear() +{ + nameList.clear(); + nameList[0] = tr("All"); +} + +const char * CCategoryList::operator[](unsigned int id) +{ + map::iterator itr = nameList.find(id); + if(itr == nameList.end()) + return NULL; + + return nameList[id].c_str(); +} + +bool CCategoryList::AddCategory(const string &name) +{ + if(findCategory(name)) + return false; + + unsigned int i = 1; + map::iterator itr; + + //! Find next free key + while((itr = nameList.find(i)) != nameList.end()) + i++; + + nameList[i] = name; + listIter = nameList.find(i); + + return true; +} + +bool CCategoryList::SetCategory(unsigned int id, const string &name) +{ + RemoveCategory(name); + nameList[id] = name; + listIter = nameList.find(id); + return true; +} + +void CCategoryList::RemoveCategory(const string &name) +{ + for (map::iterator itr = nameList.begin(); itr != nameList.end(); itr++) + { + if(strcasecmp(name.c_str(), itr->second.c_str()) == 0) + { + nameList.erase(itr); + break; + } + } +} + +void CCategoryList::RemoveCategory(unsigned int id) +{ + map::iterator itr = nameList.find(id); + + if(itr != nameList.end()) + nameList.erase(itr); +} + +bool CCategoryList::findCategory(const string &name) +{ + for (listIter = nameList.begin(); listIter != nameList.end(); listIter++) + { + if(strcasecmp(name.c_str(), listIter->second.c_str()) == 0) + return true; + } + return false; +} diff --git a/source/settings/CCategoryList.hpp b/source/settings/CCategoryList.hpp new file mode 100644 index 0000000..c5567a3 --- /dev/null +++ b/source/settings/CCategoryList.hpp @@ -0,0 +1,61 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef CATEGORYLIST_HPP_ +#define CATEGORYLIST_HPP_ + +#include +#include + +using namespace std; + +class CCategoryList +{ + public: + CCategoryList(); + bool Load(string filepath); + bool Save(); + bool AddCategory(const string &name); + bool SetCategory(unsigned int id, const string &name); + void RemoveCategory(unsigned int id); + void RemoveCategory(const string &name); + bool goToFirst() { listIter = nameList.begin(); return true; } + bool goToNext() { listIter++; return listIter != nameList.end(); } + unsigned int getCurrentID() const { return listIter->first; } + const string &getCurrentName() const { return listIter->second; } + const char * operator[](unsigned int id); + const char *at(unsigned int id) { return operator[](id); } + void goToNextCicle() { listIter++; if(listIter == nameList.end()) listIter = nameList.begin(); } + void goToPreviousCicle() { if(listIter == nameList.begin()) listIter = nameList.end(); listIter--; } + bool findCategory(const string &name); + bool findCategory(unsigned int id) { listIter = nameList.find(id); return listIter != nameList.end(); }; + int pos() const { return distance(nameList.begin(), listIter); } + int size() const { return nameList.size(); } + void clear(); + private: + string configPath; + map::const_iterator listIter; + map nameList; +}; + +#endif diff --git a/source/settings/CGameCategories.cpp b/source/settings/CGameCategories.cpp new file mode 100644 index 0000000..b566f0a --- /dev/null +++ b/source/settings/CGameCategories.cpp @@ -0,0 +1,407 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include "CGameCategories.hpp" +#include "GameTitles.h" +#include "settings/CSettings.h" +#include "usbloader/GameList.h" +#include "language/gettext.h" +#include "FileOperations/fileops.h" +#include "prompts/ProgressWindow.h" +#include "xml/GameTDB.hpp" +#include "utils/StringTools.h" +#include "svnrev.h" + +using namespace tinyxml2; + +#define VALID_CONFIG_REV 1084 + +CGameCategories GameCategories; + +CGameCategories::CGameCategories() + : defaultCategory(1, 0) +{ +} + +const vector &CGameCategories::operator[](const char *id) const +{ + if(!id) return defaultCategory; + + for(map >::const_iterator itr = List.begin(); itr != List.end(); itr++) + { + if(strncasecmp(itr->first.c_str(), id, 6) == 0) + return itr->second; + } + + return defaultCategory; +} + +bool CGameCategories::Load(string filepath) +{ + if(filepath.size() == 0) + return false; + + if(filepath[filepath.size()-1] != '/') + filepath += '/'; + + filepath += "GXGameCategories.xml"; + configPath = filepath; + + clear(); + + XMLDocument xmlDoc; + if(xmlDoc.LoadFile(filepath.c_str()) != 0) + return false; + + if(!ValidVersion(xmlDoc.FirstChildElement("Revision"))) + return false; + + XMLElement * node = xmlDoc.FirstChildElement("Categories"); + if(!node) + return false; + + node = node->FirstChildElement("Category"); + + while(node != NULL) + { + const char * ID = node->Attribute("ID"); + const char * Name = node->Attribute("Name"); + + if(ID && Name) + CategoryList.SetCategory(atoi(ID), Name); + + node = node->NextSiblingElement(); + } + + node = xmlDoc.FirstChildElement("GameCategories"); + if(!node) + return false; + + node = node->FirstChildElement("Game"); + + while(node != NULL) + { + const char * gameID = node->Attribute("ID"); + + XMLElement * category = node->FirstChildElement("Category"); + + while(category != NULL) + { + const char * categoryID = category->Attribute("ID"); + if(gameID && categoryID) + SetCategory(gameID, atoi(categoryID)); + + category = category->NextSiblingElement(); + } + + node = node->NextSiblingElement(); + } + + CategoryList.goToFirst(); + + return true; +} + +bool CGameCategories::Save() +{ + char filepath[300]; + snprintf(filepath, sizeof(filepath), configPath.c_str()); + + char * ptr = strrchr(filepath, '/'); + if(ptr) + ptr[0] = 0; + + CreateSubfolder(filepath); + + StartProgress(tr("Generating GXGameCategories.xml"), tr("Please wait..."), 0, false, true); + XMLDocument xmlDoc; + + XMLDeclaration *declaration = xmlDoc.NewDeclaration(); + xmlDoc.InsertEndChild(declaration); + XMLElement *Revision = xmlDoc.NewElement("Revision"); + XMLText *revText = xmlDoc.NewText(GetRev()); + Revision->InsertEndChild(revText); + xmlDoc.InsertEndChild(Revision); + + int progressSize = CategoryList.size() + List.size(); + int progress = 0; + + //! Add all categories as an ID map + { + //! On LinkEndChild TinyXML owns and deletes the elements allocated here. + //! This is more memory efficient than making another copy of the elements. + XMLElement *Categories = xmlDoc.NewElement("Categories"); + + CategoryList.goToFirst(); + do + { + ShowProgress(progress, progressSize); + + XMLElement *Category = xmlDoc.NewElement("Category"); + Category->SetAttribute("ID", fmt("%02i", CategoryList.getCurrentID())); + Category->SetAttribute("Name", CategoryList.getCurrentName().c_str()); + + Categories->LinkEndChild(Category); + + ++progress; + } + while(CategoryList.goToNext()); + + xmlDoc.LinkEndChild(Categories); + } + + //! Add game specific categories now + { + //! On LinkEndChild TinyXML owns and deletes the elements allocated here. + //! This is more memory efficient than making another copy of the elements. + XMLElement *GameCategories = xmlDoc.NewElement("GameCategories"); + + for(map >::iterator itr = List.begin(); itr != List.end(); itr++) + { + ShowProgress(progress, progressSize); + + XMLElement *Game = xmlDoc.NewElement("Game"); + Game->SetAttribute("ID", itr->first.c_str()); + Game->SetAttribute("Title", GameTitles.GetTitle(itr->first.c_str())); + + for(u32 i = 0; i < itr->second.size(); ++i) + { + const char *CatName = CategoryList[itr->second[i]]; + if(!CatName) + CatName = ""; + + XMLElement *Category = xmlDoc.NewElement("Category"); + Category->SetAttribute("ID", fmt("%02i", itr->second[i])); + Category->SetAttribute("Name", CatName); + + Game->LinkEndChild(Category); + } + + GameCategories->LinkEndChild(Game); + ++progress; + } + + xmlDoc.LinkEndChild(GameCategories); + } + + ShowProgress(tr("Writing GXGameCategories.xml"), tr("Please wait..."), 0, progressSize, progressSize, false, true); + + xmlDoc.SaveFile(configPath.c_str()); + ProgressStop(); + + return true; +} + +bool CGameCategories::ValidVersion(XMLElement *revisionNode) +{ + if(!revisionNode) return false; + + if(!revisionNode->FirstChild() || !revisionNode->FirstChild()->Value()) + return false; + + return atoi(revisionNode->FirstChild()->Value()) >= VALID_CONFIG_REV; +} + +bool CGameCategories::SetCategory(const char *gameID, unsigned int id) +{ + if(!gameID) return false; + + char gameID6[7]; + snprintf(gameID6, sizeof(gameID6), gameID); + + string stringGameID(gameID6); + + return SetCategory(stringGameID, id); +} + +bool CGameCategories::SetCategory(const string &gameID, unsigned int id) +{ + if(List[gameID].empty()) + List[gameID] = defaultCategory; + + vector tmpVect(List[gameID]); + + for(u32 i = 0; i < tmpVect.size(); ++i) + { + if(tmpVect[i] == id) + return false; + } + + List[gameID].push_back(id); + return true; +} + +bool CGameCategories::ReplaceCategory(const char *gameID, unsigned int id) +{ + if(!gameID) return false; + + char gameID6[7]; + snprintf(gameID6, sizeof(gameID6), gameID); + + List[string(gameID6)] = defaultCategory; + List[string(gameID6)].push_back(id); + return true; +} + + +bool CGameCategories::ReplaceCategory(const string &gameID, unsigned int id) +{ + List[gameID] = defaultCategory; + List[gameID].push_back(id); + return true; +} + +void CGameCategories::RemoveCategory(unsigned int id) +{ + for(map >::iterator itr = List.begin(); itr != List.end(); itr++) + { + for(u32 i = 0; i < itr->second.size(); ++i) + { + if(itr->second[i] == id) + { + itr->second.erase(itr->second.begin()+ i); + --i; + } + } + } +} + +void CGameCategories::RemoveGameCategories(const string &gameID) +{ + for (map >::iterator itr = List.begin(); itr != List.end(); itr++) + { + if(gameID == itr->first) + { + List.erase(itr); + } + } +} + +void CGameCategories::RemoveCategory(const char *gameID, unsigned int id) +{ + if(!gameID) return; + + string gameID6; + for(int i = 0; i < 6 && gameID[i] != 0; ++i) + gameID6.push_back(gameID[i]); + + RemoveCategory(gameID6, id); +} + +void CGameCategories::RemoveCategory(const string &gameID, unsigned int id) +{ + for (map >::iterator itr = List.begin(); itr != List.end(); itr++) + { + if(gameID == itr->first) + { + for(u32 i = 0; i < itr->second.size(); ++i) + { + if(itr->second[i] == id) + { + itr->second.erase(itr->second.begin()+ i); + break; + } + } + break; + } + } +} + +bool CGameCategories::isInCategory(const char *gameID, unsigned int id) +{ + if(id == 0) //! ID = 0 means category 'All' so it is always true + return true; + + if(!gameID) return false; + + string gameID6; + for(int i = 0; i < 6 && gameID[i] != 0; ++i) + gameID6.push_back(gameID[i]); + + for (map >::iterator itr = GameCategories.List.begin(); itr != GameCategories.List.end(); itr++) + { + if(itr->first == gameID6) + { + for(u32 i = 0; i < itr->second.size(); ++i) + { + if(itr->second[i] == id) + return true; + } + break; + } + } + + return false; +} + +bool CGameCategories::ImportFromGameTDB(const string &xmlpath) +{ + GameTDB XML_DB; + + if(!XML_DB.OpenFile(xmlpath.c_str())) + return false; + + StartProgress(tr("Importing categories"), tr("Please wait..."), 0, false, true); + + XML_DB.SetLanguageCode(Settings.db_language); + wString filter(gameList.GetCurrentFilter()); + gameList.LoadUnfiltered(); + + for(int i = 0; i < gameList.size(); ++i) + { + ShowProgress(i, gameList.size()); + + vector genreList; + string GameType; + + if(XML_DB.GetGameType((const char *) gameList[i]->id, GameType)) + { + if(!CategoryList.findCategory(GameType)) + CategoryList.AddCategory(GameType); + + this->SetCategory(gameList[i]->id, CategoryList.getCurrentID()); + } + + if(!XML_DB.GetGenreList((const char *) gameList[i]->id, genreList)) + continue; + + for(u32 n = 0; n < genreList.size(); ++n) + { + if(!CategoryList.findCategory(genreList[n])) + CategoryList.AddCategory(genreList[n]); + + this->SetCategory(gameList[i]->id, CategoryList.getCurrentID()); + } + + } + + XML_DB.CloseFile(); + gameList.FilterList(filter.c_str()); + + ProgressStop(); + + return true; +} diff --git a/source/settings/CGameCategories.hpp b/source/settings/CGameCategories.hpp new file mode 100644 index 0000000..3fc65d2 --- /dev/null +++ b/source/settings/CGameCategories.hpp @@ -0,0 +1,70 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GAMECATEGORIES_HPP_ +#define GAMECATEGORIES_HPP_ + +#include +#include +#include +#include +#include "xml/tinyxml2.h" +#include "CCategoryList.hpp" + +using namespace tinyxml2; + +class CGameCategories +{ + public: + CGameCategories(); + bool Load(string filepath); + bool Save(); + bool SetCategory(const string &gameID, unsigned int id); + bool SetCategory(const char *gameID, unsigned int id); + bool SetCategory(const unsigned char *gameID, int unsigned id) { return SetCategory((const char *) gameID, id); }; + bool ReplaceCategory(const string &gameID, unsigned int id); + bool ReplaceCategory(const char *gameID, unsigned int id); + bool ReplaceCategory(const unsigned char *gameID, int unsigned id) { return SetCategory((const char *) gameID, id); }; + void RemoveCategory(unsigned int id); + void RemoveCategory(const string &gameID, unsigned int id); + void RemoveCategory(const char *gameID, unsigned int id); + void RemoveCategory(const unsigned char *gameID, unsigned int id) { RemoveCategory((const char *) gameID, id); }; + void RemoveGameCategories(const string &gameID); + const vector &operator[](const char *gameID) const; + const vector &operator[](const unsigned char *gameID) const { return operator[]((const char *) gameID); } + bool ImportFromGameTDB(const string &xmlpath); + void clear() { List.clear(); CategoryList.clear(); }; + static bool isInCategory(const char *gameID, unsigned int id); + + CCategoryList CategoryList; + protected: + bool ValidVersion(XMLElement *xmlfile); + + string configPath; + const vector defaultCategory; + map > List; +}; + +extern CGameCategories GameCategories; + +#endif diff --git a/source/settings/CGameSettings.cpp b/source/settings/CGameSettings.cpp new file mode 100644 index 0000000..a62f824 --- /dev/null +++ b/source/settings/CGameSettings.cpp @@ -0,0 +1,726 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include + +#include "CSettings.h" +#include "CGameSettings.h" +#include "FileOperations/fileops.h" +#include "svnrev.h" + +#define VALID_CONFIG_REV 1031 + +CGameSettings GameSettings; + +CGameSettings::CGameSettings() +{ + SetDefault(DefaultConfig); +} + +CGameSettings::~CGameSettings() +{ +} + +GameCFG * CGameSettings::GetGameCFG(const char * id) +{ + if(!id) + { + DefaultConfig.id[0] = '\0'; + return &DefaultConfig; + } + + for(u32 i = 0; i < GameList.size(); ++i) + { + if(strncasecmp(id, GameList[i].id, 6) == 0) + return &GameList[i]; + } + + memcpy(DefaultConfig.id, id, 6); + + return &DefaultConfig; +} + +bool CGameSettings::AddGame(const GameCFG & NewGame) +{ + for(u32 i = 0; i < GameList.size(); ++i) + { + if(strncasecmp(NewGame.id, GameList[i].id, 6) == 0) + { + GameList[i] = NewGame; + return true; + } + } + + GameList.push_back(NewGame); + + return true; +} + +bool CGameSettings::RemoveAll() +{ + GameList.clear(); + std::vector().swap(GameList); + + return Save(); +} + +bool CGameSettings::Remove(const char * id) +{ + if(!id) + return false; + + for(u32 i = 0; i < GameList.size(); ++i) + { + if(strncasecmp(id, GameList[i].id, 6) == 0) + { + GameList.erase(GameList.begin()+i); + break; + } + } + + return true; +} + +bool CGameSettings::Load(const char * path) +{ + char filepath[300]; + snprintf(filepath, sizeof(filepath), "%sGXGameSettings.cfg", path); + + ConfigPath = filepath; + + FILE *file = fopen(filepath, "r"); + if (!file) return false; + + if(!ValidVersion(file)) + { + fclose(file); + return false; + } + + const int lineSize = 20*1024; + + char *line = new (std::nothrow) char[lineSize]; + if(!line) { + fclose(file); + return false; + } + + while (fgets(line, lineSize, file)) + { + if (line[0] == '#') + continue; + + this->ParseLine(line); + } + + delete [] line; + + fclose(file); + + return true; +} + +bool CGameSettings::ValidVersion(FILE * file) +{ + if(!file) return false; + + char line[255]; + int revision = 0; + + while (fgets(line, sizeof(line), file)) + { + const char * ptr = strcasestr(line, "USB Loader GX R"); + if(ptr) + { + ptr += strlen("USB Loader GX R"); + revision = atoi(ptr); + break; + } + } + + rewind(file); + + return revision >= VALID_CONFIG_REV; +} + +bool CGameSettings::Save() +{ + char filepath[300]; + strlcpy(filepath, ConfigPath.c_str(), sizeof(filepath)); + + char * ptr = strrchr(filepath, '/'); + if(ptr) + ptr[0] = 0; + + CreateSubfolder(filepath); + + FILE * f = fopen(ConfigPath.c_str(), "w"); + if (!f) return false; + + fprintf(f, "# USB Loader GX R%s - Individual game settings file\n", GetRev()); + fprintf(f, "# note: this file is automatically generated\n"); + fprintf(f, "# Num Games: %d\n", GameList.size()); + for (u32 i = 0; i < GameList.size(); ++i) + { + fprintf(f, "game:%s = ", GameList[i].id); + fprintf(f, "video:%d; ", GameList[i].video); + fprintf(f, "videoPatchDol:%d; ", GameList[i].videoPatchDol); + fprintf(f, "patchFix480p:%d; ", GameList[i].patchFix480p); + fprintf(f, "aspectratio:%d; ", GameList[i].aspectratio); + fprintf(f, "language:%d; ", GameList[i].language); + fprintf(f, "ocarina:%d; ", GameList[i].ocarina); + fprintf(f, "vipatch:%d; ", GameList[i].vipatch); + fprintf(f, "ios:%d; ", GameList[i].ios); + fprintf(f, "parentalcontrol:%d; ", GameList[i].parentalcontrol); + fprintf(f, "iosreloadblock:%d; ", GameList[i].iosreloadblock); + fprintf(f, "patchcountrystrings:%d; ", GameList[i].patchcountrystrings); + fprintf(f, "loadalternatedol:%d; ", GameList[i].loadalternatedol); + fprintf(f, "alternatedolstart:%d; ", (int)GameList[i].alternatedolstart); + fprintf(f, "alternatedolname:%s; ", GameList[i].alternatedolname.c_str()); + fprintf(f, "returnTo:%d; ", GameList[i].returnTo); + fprintf(f, "sneekVideoPatch:%d; ", GameList[i].sneekVideoPatch); + fprintf(f, "NandEmuMode:%d; ", GameList[i].NandEmuMode); + fprintf(f, "NandEmuPath:%s; ", GameList[i].NandEmuPath.c_str()); + fprintf(f, "Hooktype:%d; ", GameList[i].Hooktype); + fprintf(f, "WiirdDebugger:%d; ", GameList[i].WiirdDebugger); + fprintf(f, "GameCubeMode:%d; ", GameList[i].GameCubeMode); + fprintf(f, "DMLVideo:%d; ", GameList[i].DMLVideo); + fprintf(f, "DMLProgPatch:%d; ", GameList[i].DMLProgPatch); + fprintf(f, "DMLNMM:%d; ", GameList[i].DMLNMM); + fprintf(f, "DMLActivityLED:%d; ", GameList[i].DMLActivityLED); + fprintf(f, "DMLPADHOOK:%d; ", GameList[i].DMLPADHOOK); + fprintf(f, "DMLNoDisc2:%d; ", GameList[i].DMLNoDisc2); + fprintf(f, "DMLWidescreen:%d; ", GameList[i].DMLWidescreen); + fprintf(f, "DMLScreenshot:%d; ", GameList[i].DMLScreenshot); + fprintf(f, "DMLJPNPatch:%d; ", GameList[i].DMLJPNPatch); + fprintf(f, "DMLDebug:%d; ", GameList[i].DMLDebug); + fprintf(f, "NINDeflicker:%d; ", GameList[i].NINDeflicker); + fprintf(f, "NINPal50Patch:%d; ", GameList[i].NINPal50Patch); + fprintf(f, "NINWiiUWide:%d; ", GameList[i].NINWiiUWide); + fprintf(f, "NINVideoScale:%d; ", GameList[i].NINVideoScale); + fprintf(f, "NINVideoOffset:%d; ", GameList[i].NINVideoOffset); + fprintf(f, "NINRemlimit:%d; ", GameList[i].NINRemlimit); + fprintf(f, "NINArcadeMode:%d; ", GameList[i].NINArcadeMode); + fprintf(f, "NINCCRumble:%d; ", GameList[i].NINCCRumble); + fprintf(f, "NINSkipIPL:%d; ", GameList[i].NINSkipIPL); + fprintf(f, "NINBBA:%d; ", GameList[i].NINBBA); // ASA + fprintf(f, "NINBBAPROF:%d ", GameList[i].NINBBAPROF); //ASA + fprintf(f, "NINMCEmulation:%d; ", GameList[i].NINMCEmulation); + fprintf(f, "NINMCSize:%d; ", GameList[i].NINMCSize); + fprintf(f, "NINUSBHID:%d; ", GameList[i].NINUSBHID); + fprintf(f, "NINMaxPads:%d; ", GameList[i].NINMaxPads); + fprintf(f, "NINNativeSI:%d; ", GameList[i].NINNativeSI); + fprintf(f, "NINOSReport:%d; ", GameList[i].NINOSReport); + fprintf(f, "NINLED:%d; ", GameList[i].NINLED); + fprintf(f, "NINLog:%d; ", GameList[i].NINLog); + fprintf(f, "NINLoaderPath:%s; ", GameList[i].NINLoaderPath.c_str()); + fprintf(f, "DEVOMCEmulation:%d; ", GameList[i].DEVOMCEmulation); + fprintf(f, "DEVOWidescreen:%d; ", GameList[i].DEVOWidescreen); + fprintf(f, "DEVOActivityLED:%d; ", GameList[i].DEVOActivityLED); + fprintf(f, "DEVOFZeroAX:%d; ", GameList[i].DEVOFZeroAX); + fprintf(f, "DEVOTimerFix:%d; ", GameList[i].DEVOTimerFix); + fprintf(f, "DEVODButtons:%d; ", GameList[i].DEVODButtons); + fprintf(f, "DEVOCropOverscan:%d; ", GameList[i].DEVOCropOverscan); + fprintf(f, "DEVODiscDelay:%d; ", GameList[i].DEVODiscDelay); + fprintf(f, "PrivateServer:%d; ", GameList[i].PrivateServer); + fprintf(f, "Locked:%d;\n", GameList[i].Locked); + } + fprintf(f, "# END\n"); + fclose(f); + + return true; +} + +bool CGameSettings::SetSetting(GameCFG & game, const char *name, const char *value) +{ + if (strcmp(name, "video") == 0) + { + game.video = atoi(value); + return true; + } + else if (strcmp(name, "videoPatchDol") == 0) + { + game.videoPatchDol = atoi(value); + return true; + } + else if (strcmp(name, "patchFix480p") == 0) + { + game.patchFix480p = atoi(value); + return true; + } + else if(strcmp(name, "aspectratio") == 0) + { + game.aspectratio = atoi(value); + return true; + } + else if(strcmp(name, "language") == 0) + { + game.language = atoi(value); + return true; + } + else if(strcmp(name, "ocarina") == 0) + { + game.ocarina = atoi(value); + return true; + } + else if(strcmp(name, "vipatch") == 0) + { + game.vipatch = atoi(value); + return true; + } + else if(strcmp(name, "ios") == 0) + { + game.ios = atoi(value); + return true; + } + else if(strcmp(name, "parentalcontrol") == 0) + { + game.parentalcontrol = atoi(value); + return true; + } + else if(strcmp(name, "iosreloadblock") == 0) + { + game.iosreloadblock = atoi(value); + return true; + } + else if(strcmp(name, "loadalternatedol") == 0) + { + game.loadalternatedol = atoi(value); + return true; + } + else if(strcmp(name, "alternatedolstart") == 0) + { + game.alternatedolstart = atoi(value); + return true; + } + else if(strcmp(name, "patchcountrystrings") == 0) + { + game.patchcountrystrings = atoi(value); + return true; + } + else if(strcmp(name, "alternatedolname") == 0) + { + game.alternatedolname = value; + return true; + } + else if(strcmp(name, "returnTo") == 0) + { + game.returnTo = atoi(value); + return true; + } + else if(strcmp(name, "sneekVideoPatch") == 0) + { + game.sneekVideoPatch = atoi(value); + return true; + } + else if(strcmp(name, "NandEmuMode") == 0) + { + game.NandEmuMode = atoi(value); + return true; + } + else if(strcmp(name, "NandEmuPath") == 0) + { + game.NandEmuPath = value; + return true; + } + else if(strcmp(name, "Hooktype") == 0) + { + game.Hooktype = atoi(value); + return true; + } + else if(strcmp(name, "WiirdDebugger") == 0) + { + game.WiirdDebugger = atoi(value); + return true; + } + else if(strcmp(name, "Locked") == 0) + { + game.Locked = atoi(value); + return true; + } + else if(strcmp(name, "GameCubeMode") == 0) + { + game.GameCubeMode = atoi(value); + return true; + } + else if(strcmp(name, "DMLVideo") == 0) + { + game.DMLVideo = atoi(value); + return true; + } + else if(strcmp(name, "DMLProgPatch") == 0) + { + game.DMLProgPatch = atoi(value); + return true; + } + else if(strcmp(name, "DMLNMM") == 0) + { + game.DMLNMM = atoi(value); + return true; + } + else if(strcmp(name, "DMLActivityLED") == 0) + { + game.DMLActivityLED = atoi(value); + return true; + } + else if(strcmp(name, "DMLPADHOOK") == 0) + { + game.DMLPADHOOK = atoi(value); + return true; + } + else if(strcmp(name, "DMLNoDisc2") == 0) + { + game.DMLNoDisc2 = atoi(value); + return true; + } + else if(strcmp(name, "DMLWidescreen") == 0) + { + game.DMLWidescreen = atoi(value); + return true; + } + else if(strcmp(name, "DMLScreenshot") == 0) + { + game.DMLScreenshot = atoi(value); + return true; + } + else if(strcmp(name, "DMLJPNPatch") == 0) + { + game.DMLJPNPatch = atoi(value); + return true; + } + else if(strcmp(name, "DMLDebug") == 0) + { + game.DMLDebug = atoi(value); + return true; + } + else if(strcmp(name, "NINDeflicker") == 0) + { + game.NINDeflicker = atoi(value); + return true; + } + else if(strcmp(name, "NINPal50Patch") == 0) + { + game.NINPal50Patch = atoi(value); + return true; + } + else if(strcmp(name, "NINWiiUWide") == 0) + { + game.NINWiiUWide = atoi(value); + return true; + } + else if (strcmp(name, "NINVideoScale") == 0) + { + game.NINVideoScale = atoi(value); + return true; + } + else if (strcmp(name, "NINVideoOffset") == 0) + { + game.NINVideoOffset = atoi(value); + return true; + } + else if (strcmp(name, "NINRemlimit") == 0) + { + game.NINRemlimit = atoi(value); + return true; + } + else if(strcmp(name, "NINArcadeMode") == 0) + { + game.NINArcadeMode = atoi(value); + return true; + } + else if (strcmp(name, "NINCCRumble") == 0) + { + game.NINCCRumble = atoi(value); + return true; + } + else if (strcmp(name, "NINSkipIPL") == 0) + { + game.NINSkipIPL = atoi(value); + return true; + } + else if (strcmp(name, "NINBBA") == 0) // ASA + { + game.NINBBA = atoi(value); + return true; + } + else if (strcmp(name, "NINBBAPROF") == 0) // ASA + { + game.NINBBAPROF = atoi(value); + return true; + } + else if(strcmp(name, "NINMCEmulation") == 0) + { + game.NINMCEmulation = atoi(value); + return true; + } + else if(strcmp(name, "NINMCSize") == 0) + { + game.NINMCSize = atoi(value); + return true; + } + else if(strcmp(name, "NINUSBHID") == 0) + { + game.NINUSBHID = atoi(value); + return true; + } + else if(strcmp(name, "NINMaxPads") == 0) + { + game.NINMaxPads = atoi(value); + return true; + } + else if(strcmp(name, "NINNativeSI") == 0) + { + game.NINNativeSI = atoi(value); + return true; + } + else if(strcmp(name, "NINOSReport") == 0) + { + game.NINOSReport = atoi(value); + return true; + } + else if(strcmp(name, "NINLED") == 0) + { + game.NINLED = atoi(value); + return true; + } + else if(strcmp(name, "NINLog") == 0) + { + game.NINLog = atoi(value); + return true; + } + else if(strcmp(name, "NINLoaderPath") == 0) + { + game.NINLoaderPath = value; + return true; + } + else if(strcmp(name, "DEVOMCEmulation") == 0) + { + game.DEVOMCEmulation = atoi(value); + return true; + } + else if(strcmp(name, "DEVOWidescreen") == 0) + { + game.DEVOWidescreen = atoi(value); + return true; + } + else if(strcmp(name, "DEVOActivityLED") == 0) + { + game.DEVOActivityLED = atoi(value); + return true; + } + else if(strcmp(name, "DEVOFZeroAX") == 0) + { + game.DEVOFZeroAX = atoi(value); + return true; + } + else if(strcmp(name, "DEVOTimerFix") == 0) + { + game.DEVOTimerFix = atoi(value); + return true; + } + else if(strcmp(name, "DEVODButtons") == 0) + { + game.DEVODButtons = atoi(value); + return true; + } + else if(strcmp(name, "DEVOCropOverscan") == 0) + { + game.DEVOCropOverscan = atoi(value); + return true; + } + else if(strcmp(name, "DEVODiscDelay") == 0) + { + game.DEVODiscDelay = atoi(value); + return true; + } + else if(strcmp(name, "PrivateServer") == 0) + { + game.PrivateServer = atoi(value); + return true; + } + + return false; +} + +bool CGameSettings::ReadGameID(const char * src, char * GameID, int size) +{ + if(strncasecmp(src, "game:", 5) != 0) + return false; + + char * ptr = strchr(src, ':'); + if(!ptr) + return false; + + ptr++; + + int i = 0; + + for(i = 0; i < size; i++, ptr++) + { + if(*ptr == ' ' || *ptr == '\0') + break; + + GameID[i] = *ptr; + } + + GameID[i] = 0; + + return true; +} + +void CGameSettings::ParseLine(char *line) +{ + char GameID[8]; + + if(!ReadGameID(line, GameID, 6)) + return; + + if(strlen(GameID) != 6 && strlen(GameID) != 4) + return; + + GameCFG NewCFG; + SetDefault(NewCFG); + + strcpy(NewCFG.id, GameID); + + char * LinePtr = strchr(line, '='); + + while(LinePtr != NULL) + { + LinePtr++; + + char * eq = strchr(LinePtr, ':'); + + if (!eq) break; + + std::string name, value; + + this->TrimLine(name, LinePtr, ':'); + this->TrimLine(value, eq + 1, ';'); + + SetSetting(NewCFG, name.c_str(), value.c_str()); + + LinePtr = strchr(LinePtr, ';'); + } + + AddGame(NewCFG); +} + +void CGameSettings::TrimLine(std::string &dest, const char *src, char stopChar) +{ + if(!src) + return; + + while (*src == ' ') + src++; + + while(*src != 0) + { + if(*src == stopChar || *src == '\n' || *src == '\r') + break; + + dest.push_back(*src); + src++; + } +} + +int CGameSettings::GetPartenalPEGI(int parental) +{ + switch(parental) + { + case 1: return 7; + case 2: return 12; + case 3: return 16; + case 4: return 18; + default: return -1; + } +} + +void CGameSettings::SetDefault(GameCFG &game) +{ + memset(game.id, 0, sizeof(game.id)); + game.video = INHERIT; + game.videoPatchDol = INHERIT; + game.patchFix480p = INHERIT; + game.aspectratio = INHERIT; + game.language = INHERIT; + game.ocarina = INHERIT; + game.vipatch = INHERIT; + game.ios = INHERIT; + game.parentalcontrol = PARENTAL_LVL_EVERYONE; + game.patchcountrystrings = INHERIT; + game.loadalternatedol = ALT_DOL_DEFAULT; + game.alternatedolstart = 0; + game.iosreloadblock = INHERIT; + game.alternatedolname.clear(); + game.returnTo = ON; + game.sneekVideoPatch = INHERIT; + game.NandEmuMode = INHERIT; + game.NandEmuPath.clear(); + game.Hooktype = INHERIT; + game.WiirdDebugger = INHERIT; + game.GameCubeMode = INHERIT; + game.DMLVideo = INHERIT; + game.DMLProgPatch = INHERIT; + game.DMLNMM = INHERIT; + game.DMLActivityLED = INHERIT; + game.DMLPADHOOK = INHERIT; + game.DMLNoDisc2 = INHERIT; + game.DMLWidescreen = INHERIT; + game.DMLScreenshot = INHERIT; + game.DMLJPNPatch = INHERIT; + game.DMLDebug = INHERIT; + game.NINDeflicker = INHERIT; + game.NINPal50Patch = INHERIT; + game.NINWiiUWide = INHERIT; + game.NINVideoScale = INHERIT; + game.NINVideoOffset = INHERIT - 20; + game.NINRemlimit = INHERIT; + game.NINArcadeMode = INHERIT; + game.NINCCRumble = INHERIT; + game.NINSkipIPL = INHERIT; + game.NINBBA = INHERIT; // ASA + game.NINBBAPROF = INHERIT; // ASA + game.NINMCEmulation = INHERIT; + game.NINMCSize = INHERIT; + game.NINUSBHID = INHERIT; + game.NINMaxPads = INHERIT; + game.NINNativeSI = INHERIT; + game.NINOSReport = INHERIT; + game.NINLED = INHERIT; + game.NINLog = INHERIT; + game.NINLoaderPath.clear(); + game.DEVOMCEmulation = INHERIT; + game.DEVOWidescreen = INHERIT; + game.DEVOActivityLED = INHERIT; + game.DEVOFZeroAX = INHERIT; + game.DEVOTimerFix = INHERIT; + game.DEVODButtons = INHERIT; + game.DEVOCropOverscan = INHERIT; + game.DEVODiscDelay = INHERIT; + game.PrivateServer = INHERIT; + game.Locked = OFF; +} diff --git a/source/settings/CGameSettings.h b/source/settings/CGameSettings.h new file mode 100644 index 0000000..809c746 --- /dev/null +++ b/source/settings/CGameSettings.h @@ -0,0 +1,187 @@ +#ifndef _GAME_SETTINGS_H_ +#define _GAME_SETTINGS_H_ + +#include +#include +#include +#include +#include "usbloader/disc.h" + +typedef struct _GameCFG +{ + char id[7]; + short video; + short videoPatchDol; + short patchFix480p; + short aspectratio; + short language; + short ocarina; + short vipatch; + short ios; + short parentalcontrol; + short iosreloadblock; + short loadalternatedol; + u32 alternatedolstart; + short patchcountrystrings; + std::string alternatedolname; + short returnTo; + short sneekVideoPatch; + short NandEmuMode; + std::string NandEmuPath; + short Hooktype; + short WiirdDebugger; + short GameCubeMode; + short DMLVideo; + short DMLProgPatch; + short DMLNMM; + short DMLActivityLED; + short DMLPADHOOK; + short DMLNoDisc2; + short DMLWidescreen; + short DMLScreenshot; + short DMLJPNPatch; + short DMLDebug; + short NINDeflicker; + short NINPal50Patch; + short NINWiiUWide; + short NINVideoScale; + short NINVideoOffset; + short NINRemlimit; + short NINArcadeMode; + short NINCCRumble; + short NINSkipIPL; + short NINBBA; // ASA + short NINBBAPROF; // ASA + short NINMCEmulation; + short NINMCSize; + short NINUSBHID; + short NINMaxPads; + short NINNativeSI; + short NINOSReport; + short NINLED; + short NINLog; + std::string NINLoaderPath; + short DEVOMCEmulation; + short DEVOWidescreen; + short DEVOActivityLED; + short DEVOFZeroAX; + short DEVOTimerFix; + short DEVODButtons; + short DEVOCropOverscan; + short DEVODiscDelay; + short PrivateServer; + short Locked; + + void operator=(const struct _GameCFG &game) + { + memcpy(this->id, game.id, sizeof(game.id)); + this->video = game.video; + this->videoPatchDol = game.videoPatchDol; + this->patchFix480p = game.patchFix480p; + this->aspectratio = game.aspectratio; + this->language = game.language; + this->ocarina = game.ocarina; + this->vipatch = game.vipatch; + this->ios = game.ios; + this->parentalcontrol = game.parentalcontrol; + this->iosreloadblock = game.iosreloadblock; + this->loadalternatedol = game.loadalternatedol; + this->alternatedolstart = game.alternatedolstart; + this->patchcountrystrings = game.patchcountrystrings; + this->alternatedolname = game.alternatedolname; + this->returnTo = game.returnTo; + this->sneekVideoPatch = game.sneekVideoPatch; + this->NandEmuMode = game.NandEmuMode; + this->NandEmuPath = game.NandEmuPath; + this->Hooktype = game.Hooktype; + this->WiirdDebugger = game.WiirdDebugger; + this->GameCubeMode = game.GameCubeMode; + this->DMLVideo = game.DMLVideo; + this->DMLProgPatch = game.DMLProgPatch; + this->DMLNMM = game.DMLNMM; + this->DMLActivityLED = game.DMLActivityLED; + this->DMLPADHOOK = game.DMLPADHOOK; + this->DMLNoDisc2 = game.DMLNoDisc2; + this->DMLWidescreen = game.DMLWidescreen; + this->DMLScreenshot = game.DMLScreenshot; + this->DMLJPNPatch = game.DMLJPNPatch; + this->DMLDebug = game.DMLDebug; + this->NINDeflicker = game.NINDeflicker; + this->NINPal50Patch = game.NINPal50Patch; + this->NINWiiUWide = game.NINWiiUWide; + this->NINVideoScale = game.NINVideoScale; + this->NINVideoOffset = game.NINVideoOffset; + this->NINRemlimit = game.NINRemlimit; + this->NINArcadeMode = game.NINArcadeMode; + this->NINCCRumble = game.NINCCRumble; + this->NINSkipIPL = game.NINSkipIPL; + this->NINBBA = game.NINBBA; // ASA + this->NINBBAPROF = game.NINBBAPROF; // ASA + this->NINMCEmulation = game.NINMCEmulation; + this->NINMCSize = game.NINMCSize; + this->NINUSBHID = game.NINUSBHID; + this->NINMaxPads = game.NINMaxPads; + this->NINNativeSI = game.NINNativeSI; + this->NINOSReport = game.NINOSReport; + this->NINLED = game.NINLED; + this->NINLog = game.NINLog; + this->NINLoaderPath = game.NINLoaderPath; + this->DEVOMCEmulation = game.DEVOMCEmulation; + this->DEVOWidescreen = game.DEVOWidescreen; + this->DEVOActivityLED = game.DEVOActivityLED; + this->DEVOFZeroAX = game.DEVOFZeroAX; + this->DEVOTimerFix = game.DEVOTimerFix; + this->DEVODButtons = game.DEVODButtons; + this->DEVOCropOverscan = game.DEVOCropOverscan; + this->DEVODiscDelay = game.DEVODiscDelay; + this->PrivateServer = game.PrivateServer; + this->Locked = game.Locked; + } +} GameCFG; + +class CGameSettings +{ + public: + //!Constructor + CGameSettings(); + //!Destructor + ~CGameSettings(); + //!Load + bool Load(const char * path); + //!Save + bool Save(); + //!AddGame + bool AddGame(const GameCFG & NewGame); + //!Reset + bool RemoveAll(); + //!Overload Reset for one Game + bool Remove(const char * id); + bool Remove(const u8 * id) { return Remove((const char *) id); } + bool Remove(const struct discHdr * game) { if(!game) return false; else return Remove(game->id); } + //!Get GameCFG + GameCFG * GetGameCFG(const char * id); + //!Overload + GameCFG * GetGameCFG(const u8 * id) { return GetGameCFG((const char *) id); } + //!Overload + GameCFG * GetGameCFG(const struct discHdr * game) { if(!game) return NULL; else return GetGameCFG(game->id); } + //!Quick settings to PEGI conversion + static int GetPartenalPEGI(int parentalsetting); + //!Set the default configuration block + void SetDefault(GameCFG &game); + protected: + bool ReadGameID(const char * src, char * GameID, int size); + bool SetSetting(GameCFG & game, const char *name, const char *value); + bool ValidVersion(FILE * file); + //!Find the config file in the default paths + bool FindConfig(); + + void ParseLine(char *line); + void TrimLine(std::string &dest, const char *src, char stopChar); + std::string ConfigPath; + std::vector GameList; + GameCFG DefaultConfig; +}; + +extern CGameSettings GameSettings; + +#endif diff --git a/source/settings/CGameStatistics.cpp b/source/settings/CGameStatistics.cpp new file mode 100644 index 0000000..2d6abb2 --- /dev/null +++ b/source/settings/CGameStatistics.cpp @@ -0,0 +1,328 @@ +#include +#include +#include +#include + +#include "CGameStatistics.h" +#include "FileOperations/fileops.h" +#include "svnrev.h" + +#define VALID_CONFIG_REV 1031 + +CGameStatistics GameStatistics; + + +CGameStatistics::CGameStatistics() +{ +} + +CGameStatistics::~CGameStatistics() +{ +} + +GameStatus * CGameStatistics::GetGameStatus(const char * id) const +{ + if(!id) + return NULL; + + for(u32 i = 0; i < GameList.size(); ++i) + { + if(strncasecmp(id, GameList[i].id, 6) == 0) + { + return (GameStatus *) &GameList[i]; + } + } + + return NULL; +} + +bool CGameStatistics::AddGame(const GameStatus & NewGame) +{ + for(u32 i = 0; i < GameList.size(); ++i) + { + if(strncasecmp(NewGame.id, GameList[i].id, 6) == 0) + { + memcpy(&GameList[i], &NewGame, sizeof(GameStatus)); + return true; + } + } + + GameList.push_back(NewGame); + + return true; +} + +bool CGameStatistics::RemoveAll() +{ + GameList.clear(); + std::vector().swap(GameList); + + return Save(); +} + +bool CGameStatistics::Remove(const char * id) +{ + if(!id) + return false; + + for(u32 i = 0; i < GameList.size(); ++i) + { + if(strncasecmp(id, GameList[i].id, 6) == 0) + { + GameList.erase(GameList.begin()+i); + break; + } + } + + return true; +} + +bool CGameStatistics::Load(const char * path) +{ + char line[1024]; + char filepath[300]; + snprintf(filepath, sizeof(filepath), "%sGXGameStatistics.cfg", path); + + ConfigPath = filepath; + + FILE *file = fopen(filepath, "r"); + if (!file) return false; + + if(!ValidVersion(file)) + { + fclose(file); + return false; + } + + while (fgets(line, sizeof(line), file)) + { + if (line[0] == '#') + continue; + + this->ParseLine(line); + } + fclose(file); + + return true; +} + +bool CGameStatistics::ValidVersion(FILE * file) +{ + if(!file) return false; + + char line[255]; + int revision = 0; + + while (fgets(line, sizeof(line), file)) + { + const char * ptr = strcasestr(line, "USB Loader GX R"); + if(ptr) + { + ptr += strlen("USB Loader GX R"); + revision = atoi(ptr); + break; + } + } + + rewind(file); + + return revision >= VALID_CONFIG_REV; +} + +bool CGameStatistics::Save() +{ + char filepath[300]; + strcpy(filepath, ConfigPath.c_str()); + + char * ptr = strrchr(filepath, '/'); + if(ptr) + ptr[0] = 0; + + if(!CreateSubfolder(filepath)) + return false; + + FILE * f = fopen(ConfigPath.c_str(), "w"); + if (!f) return false; + + fprintf(f, "# USB Loader GX R%s - Game statistics file\n", GetRev()); + fprintf(f, "# note: this file is automatically generated\n"); + fprintf(f, "# Num Games: %d\n", GameList.size()); + for (u32 i = 0; i < GameList.size(); i++) + { + fprintf(f, "game:%s = ", GameList[i].id); + fprintf(f, "FavoriteRank:%d; ", GameList[i].FavoriteRank); + fprintf(f, "PlayCount:%d;\n", GameList[i].PlayCount); + } + fprintf(f, "# END\n"); + fclose(f); + + return true; +} + +bool CGameStatistics::SetSetting(GameStatus & game, char *name, char *value) +{ + int i = 0; + + if(strcmp(name, "FavoriteRank") == 0) + { + if (sscanf(value, "%d", &i) == 1) + { + game.FavoriteRank = i; + } + return true; + } + else if(strcmp(name, "PlayCount") == 0) + { + if (sscanf(value, "%d", &i) == 1) + { + game.PlayCount = i; + } + return true; + } + + return false; +} + +bool CGameStatistics::ReadGameID(const char * src, char * GameID, int size) +{ + if(strncasecmp(src, "game:", 5) != 0) + return false; + + char * ptr = strchr(src, ':'); + if(!ptr) + return false; + + ptr++; + + int i = 0; + + for(i = 0; i < size; i++, ptr++) + { + if(*ptr == ' ' || *ptr == '\0') + break; + + GameID[i] = *ptr; + } + + GameID[i] = 0; + + return true; +} + +void CGameStatistics::ParseLine(char *line) +{ + char name[1024], value[1024]; + char GameID[8]; + + if(!ReadGameID(line, GameID, 6)) + return; + + if(strlen(GameID) != 6 && strlen(GameID) != 4) + return; + + GameStatus NewGame; + memset(&NewGame, 0, sizeof(GameStatus)); + + snprintf(NewGame.id, sizeof(NewGame.id), GameID); + + char * LinePtr = strchr(line, '='); + + while(LinePtr != NULL) + { + LinePtr++; + + char * eq = strchr(LinePtr, ':'); + + if (!eq) break; + + this->TrimLine(name, LinePtr, sizeof(name)); + this->TrimLine(value, eq + 1, sizeof(value)); + + SetSetting(NewGame, name, value); + + LinePtr = strchr(LinePtr, ';'); + } + + AddGame(NewGame); +} + +void CGameStatistics::TrimLine(char *dest, const char *src, int size) +{ + while (*src == ' ') + src++; + + int i = 0; + + for(i = 0; i < size; i++, src++) + { + if(*src == ';' || *src == ':' || *src == '\n' || + *src == '\r' || *src == '\0') + break; + + dest[i] = *src; + } + + dest[i] = '\0'; +} + +void CGameStatistics::SetPlayCount(const char * id, int count) +{ + if(!id) + return; + + GameStatus NewStatus; + snprintf(NewStatus.id, sizeof(NewStatus.id), id); + NewStatus.FavoriteRank = 0; + NewStatus.PlayCount = count; + + GameStatus * game = GetGameStatus(id); + if(game) + { + NewStatus.FavoriteRank = game->FavoriteRank; + } + + AddGame(NewStatus); +} + +void CGameStatistics::SetFavoriteRank(const char * id, int rank) +{ + if(!id) + return; + + GameStatus NewStatus; + snprintf(NewStatus.id, sizeof(NewStatus.id), id); + NewStatus.FavoriteRank = rank; + NewStatus.PlayCount = 0; + + GameStatus * game = GetGameStatus(id); + if(game) + { + NewStatus.PlayCount = game->PlayCount; + } + + AddGame(NewStatus); +} + +int CGameStatistics::GetPlayCount(const char * id) const +{ + if(!id) + return 0; + + GameStatus * game = GetGameStatus(id); + if(game) + return game->PlayCount; + + return 0; +} + +int CGameStatistics::GetFavoriteRank(const char * id) const +{ + if(!id) + return 0; + + GameStatus * game = GetGameStatus(id); + if(game) + return game->FavoriteRank; + + return 0; +} diff --git a/source/settings/CGameStatistics.h b/source/settings/CGameStatistics.h new file mode 100644 index 0000000..ec0cca1 --- /dev/null +++ b/source/settings/CGameStatistics.h @@ -0,0 +1,72 @@ +#ifndef _GAME_STATISTICS_H_ +#define _GAME_STATISTICS_H_ + +#include +#include +#include +#include +#include "usbloader/disc.h" + +typedef struct _Stats +{ + char id[7]; + u8 FavoriteRank; + int PlayCount; +} GameStatus; + +class CGameStatistics +{ + public: + //!Constructor + CGameStatistics(); + //!Destructor + ~CGameStatistics(); + //!Load + bool Load(const char * path); + //!Save + bool Save(); + //!AddGame + bool AddGame(const GameStatus & NewGame); + //!Reset + bool RemoveAll(); + //!Overload for removing one game out of the list + bool Remove(const char * id); + bool Remove(const u8 * id) { return Remove((const char *) id); }; + bool Remove(const struct discHdr * game) { if(!game) return false; else return Remove(game->id); }; + //!Overloads for set playcount + void SetPlayCount(const char * id, int count); + void SetPlayCount(const u8 * id, int count) { SetPlayCount((const char *) id, count); }; + void SetPlayCount(const struct discHdr * game, int count) { if(!game) return; SetPlayCount(game->id, count); }; + //!Overloads for get playcount + int GetPlayCount(const char * id) const; + int GetPlayCount(const u8 * id) const { return GetPlayCount((const char *) id); }; + int GetPlayCount(const struct discHdr * game) const { if(!game) return 0; else return GetPlayCount(game->id); }; + //!Overloads for set FavoriteRank + void SetFavoriteRank(const char * id, int rank); + void SetFavoriteRank(const u8 * id, int rank) { SetFavoriteRank((const char *) id, rank); }; + void SetFavoriteRank(const struct discHdr * game, int rank) { if(!game) return; SetFavoriteRank(game->id, rank); }; + //!Overloads for get FavoriteRank + int GetFavoriteRank(const char * id) const; + int GetFavoriteRank(const u8 * id) const { return GetFavoriteRank((const char *) id); }; + int GetFavoriteRank(const struct discHdr * game) const { if(!game) return 0; else return GetFavoriteRank(game->id); }; + //!Get GameStatus + GameStatus * GetGameStatus(const char * id) const; + //!Overload + GameStatus * GetGameStatus(const u8 * id) const { return GetGameStatus((const char *) id); }; + //!Overload + GameStatus * GetGameStatus(const struct discHdr * game) const { if(!game) return NULL; else return GetGameStatus(game->id); }; + + protected: + bool ReadGameID(const char * src, char * GameID, int size); + bool SetSetting(GameStatus & game, char *name, char *value); + bool ValidVersion(FILE * file); + + void ParseLine(char *line); + void TrimLine(char *dest, const char *src, int size); + std::string ConfigPath; + std::vector GameList; +}; + +extern CGameStatistics GameStatistics; + +#endif diff --git a/source/settings/CSettings.cpp b/source/settings/CSettings.cpp new file mode 100644 index 0000000..3b92a8f --- /dev/null +++ b/source/settings/CSettings.cpp @@ -0,0 +1,1532 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include + +#include "CSettings.h" +#include "CGameSettings.h" +#include "CGameStatistics.h" +#include "Controls/DeviceHandler.hpp" +#include "language/gettext.h" +#include "themes/CTheme.h" +#include "FileOperations/fileops.h" +#include "utils/encrypt.h" +#include "svnrev.h" + +#define VALID_CONFIG_REV 1031 + +CSettings Settings; + +CSettings::CSettings() +{ + CONF_Init(); + strcpy(BootDevice, "sd:"); + snprintf(ConfigPath, sizeof(ConfigPath), "%s/config/", BootDevice); + this->SetDefault(); + FirstTimeRun = true; +} + +CSettings::~CSettings() +{ +} + +void CSettings::SetDefault() +{ + snprintf(covers_path, sizeof(covers_path), "%simages/", ConfigPath); + snprintf(covers2d_path, sizeof(covers2d_path), "%simages/2D/", ConfigPath); + snprintf(coversFull_path, sizeof(coversFull_path), "%simages/full/", ConfigPath); + snprintf(disc_path, sizeof(disc_path), "%simages/disc/", ConfigPath); + snprintf(titlestxt_path, sizeof(titlestxt_path), "%s", ConfigPath); + snprintf(languagefiles_path, sizeof(languagefiles_path), "%slanguage/", ConfigPath); + snprintf(update_path, sizeof(update_path), "%s/apps/usbloader_gx/", BootDevice); + snprintf(BNRCachePath, sizeof(BNRCachePath), "%s/apps/usbloader_gx/cache_bnr/", BootDevice); + snprintf(homebrewapps_path, sizeof(homebrewapps_path), "%s/apps/", BootDevice); + snprintf(Cheatcodespath, sizeof(Cheatcodespath), "%s/codes/", BootDevice); + snprintf(TxtCheatcodespath, sizeof(TxtCheatcodespath), "%s/txtcodes/", BootDevice); + snprintf(BcaCodepath, sizeof(BcaCodepath), "%s/bca/", BootDevice); + snprintf(WipCodepath, sizeof(WipCodepath), "%s/wip/", BootDevice); + snprintf(WDMpath, sizeof(WDMpath), "%s/wdm/", BootDevice); + snprintf(WiinnertagPath, sizeof(WiinnertagPath), "%s", ConfigPath); + snprintf(theme_path, sizeof(theme_path), "%stheme/", ConfigPath); + snprintf(dolpath, sizeof(dolpath), "%s/", BootDevice); + snprintf(NandEmuPath, sizeof(NandEmuPath), "%s/nands/01/", BootDevice); + snprintf(DEVOLoaderPath, sizeof(DEVOLoaderPath), "%s/apps/gc_devo/", BootDevice); + snprintf(NINLoaderPath, sizeof(NINLoaderPath), "%s/apps/nintendont/", BootDevice); + strlcpy(NandEmuChanPath, NandEmuPath, sizeof(NandEmuChanPath)); + strlcpy(GameCubePath, "usb1:/games/", sizeof(GameCubePath)); + strlcpy(GameCubeSDPath, "sd:/games/", sizeof(GameCubeSDPath)); + strlcpy(CustomBannersURL, "http://banner.rc24.xyz/", sizeof(CustomBannersURL)); + theme[0] = 0; + language_path[0] = 0; + ogg_path[0] = 0; + unlockCode[0] = 0; + db_language[0] = 0; + returnTo[0] = 0; + + NTSC = (CONF_GetVideo() == CONF_VIDEO_NTSC); + PAL50 = (CONF_GetVideo() == CONF_VIDEO_PAL) && (CONF_GetEuRGB60() == 0); + widescreen = (CONF_GetAspectRatio() == CONF_ASPECT_16_9); + + godmode = 1; + videomode = VIDEO_MODE_DISCDEFAULT; + videopatch = OFF; + videoPatchDol = OFF; + patchFix480p = OFF; + language = CONSOLE_DEFAULT; + ocarina = OFF; + hddinfo = CLOCK_HR12; + sinfo = ON; + rumble = ON; + GameSort = SORT_ABC; + volume = 80; + sfxvolume = 80; + gamesoundvolume = 80; + tooltips = ON; + gamesound = ON; + parentalcontrol = PARENTAL_LVL_ADULT; + LoaderIOS = BUILD_IOS; + cios = 249; + gridRows = 3; + partition = 0; + discart = DISCARTS_ORIGINALS_CUSTOMS; + coversfull = COVERSFULL_HQ; + xflip = XFLIP_SYSMENU; + quickboot = OFF; + wiilight = WIILIGHT_ON; + autonetwork = OFF; + patchcountrystrings = OFF; + titlesOverride = ON; + ForceDiscTitles = OFF; + screensaver = SCREENSAVER_10_MIN; + musicloopmode = ON; + marknewtitles = ON; + ShowFreeSpace = ON; + PlaylogUpdate = OFF; + ParentalBlocks = BLOCK_ALL; + InstallToDir = INSTALL_TO_NAME_GAMEID; + GameSplit = GAMESPLIT_4GB; + InstallPartitions = REMOVE_UPDATE_PARTITION; + HomeMenu = HOME_MENU_DEFAULT; + MultiplePartitions = OFF; + BlockIOSReload = AUTO; + USBPort = 0; + USBAutoMount = ON; + CacheTitles = ON; + WSFactor = 0.8f; //actually should be 0.75 for real widescreen + FontScaleFactor = 0.8f; //it's a work around to not have to change ALL fonts now + ClockFontScaleFactor = 1.0f; // Scale of 1 to prevent misaligned clock. + EnabledCategories.resize(1); + EnabledCategories[0] = 0; + RequiredCategories.resize(0); + ForbiddenCategories.resize(0); + Wiinnertag = OFF; + SelectedGame = 0; + GameListOffset = 0; + sneekVideoPatch = OFF; + NandEmuMode = OFF; + NandEmuChanMode = 2; + UseSystemFont = ON; + Hooktype = 0; + WiirdDebugger = OFF; + WiirdDebuggerPause = OFF; + ShowPlayCount = ON; + bannerFavIcon = BANNER_FAVICON_SINGLE_LINEA; + RememberUnlock = ON; + LoaderMode = MODE_WIIGAMES | MODE_GCGAMES; + SearchMode = SEARCH_BEGINNING; + GameAspectRatio = ASPECT_SYSTEM_DEFAULT; + PointerSpeed = 0.18f; + UseChanLauncher = OFF; + AdjustOverscanX = 0; + AdjustOverscanY = 0; + TooltipDelay = 1500; // ms + GameWindowMode = GAMEWINDOW_BANNER; + CacheBNRFiles = ON; + BannerAnimStart = BANNER_START_ON_ZOOM; + BannerGridSpeed = 25.6f; // pixel/frames + BannerZoomDuration = 30; // frames + BannerProjectionOffsetX = (!widescreen || PAL50) ? 0.0f : 2.0f; + BannerProjectionOffsetY = PAL50 ? -1.0f : (NTSC ? 0.0f : -4.0f); + BannerProjectionWidth = (Settings.widescreen ? (Settings.PAL50 ? 616 : 620.0f) : 608.0f); + BannerProjectionHeight = (Settings.PAL50 ? 448.0f : (NTSC ? 470.0f : 464.0f)); + GCBannerScale = 1.5f; + GameCubeMode = GC_MODE_NINTENDONT; + GameCubeSource = AUTO; + MultiDiscPrompt = OFF; + DMLVideo = DML_VIDEO_AUTO; + DMLProgPatch = OFF; + DMLNMM = OFF; + DMLActivityLED = OFF; + DMLPADHOOK = OFF; + DMLNoDisc2 = OFF; + DMLWidescreen = OFF; + DMLScreenshot = OFF; + DMLJPNPatch = OFF; + DMLDebug = OFF; + NINDeflicker = OFF; + NINPal50Patch = OFF; + NINWiiUWide = widescreen; + NINVideoScale = 0; + NINVideoOffset = 0; + NINRemlimit = OFF; + NINArcadeMode = OFF; + NINCCRumble = OFF; + NINSkipIPL = OFF; + NINBBA = OFF; // ASA + NINBBAPROF = 0; // ASA + NINMCEmulation = ON; + NINMCSize = 2; + NINAutoboot = ON; + NINSettings = AUTO; + NINUSBHID = OFF; + NINMaxPads = 4; + NINNativeSI = OFF; + NINOSReport = OFF; + NINLED = OFF; + NINLog = OFF; + DEVOMCEmulation = OFF; + DEVOWidescreen = OFF; + DEVOActivityLED = ON; + DEVOFZeroAX = OFF; + DEVOTimerFix = OFF; + DEVODButtons = OFF; + DEVOCropOverscan = OFF; + DEVODiscDelay = OFF; + GCInstallCompressed = OFF; + GCInstallAligned = OFF; + PrivateServer = OFF; +} + +bool CSettings::Load() +{ + FindConfig(); + //! Reset default path variables to the right device + SetDefault(); + + char filepath[300]; + snprintf(filepath, sizeof(filepath), "%sGXGlobal.cfg", ConfigPath); + + FILE * file = fopen(filepath, "r"); + if (!file) return false; + + if(!ValidVersion(file)) + { + fclose(file); + return false; + } + + char line[1024]; + + while (fgets(line, sizeof(line), file)) + { + if (line[0] == '#') continue; + + this->ParseLine(line); + } + fclose(file); + + // A valid config file exists on the loader + // meaning it is not the first run of the loader. + FirstTimeRun = false; + + return true; +} + +bool CSettings::ValidVersion(FILE * file) +{ + if(!file) return false; + + char line[255]; + int revision = 0; + + while (fgets(line, sizeof(line), file)) + { + const char * ptr = strcasestr(line, "USB Loader GX R"); + if(ptr) + { + ptr += strlen("USB Loader GX R"); + revision = atoi(ptr); + break; + } + } + + rewind(file); + + return revision >= VALID_CONFIG_REV; +} + +bool CSettings::Reset() +{ + this->SetDefault(); + + if (this->Save()) return true; + + return false; +} + +bool CSettings::Save() +{ + if (!FindConfig()) return false; + + char filedest[300]; + snprintf(filedest, sizeof(filedest), "%sGXGlobal.cfg", ConfigPath); + + if(!CreateSubfolder(ConfigPath)) return false; + + FILE * file = fopen(filedest, "w"); + if (!file) return false; + + fprintf(file, "# USB Loader GX R%s - Main settings file\n", GetRev()); + fprintf(file, "# Note: This file is automatically generated\n"); + fprintf(file, "godmode = %d\n", godmode); + fprintf(file, "videomode = %d\n", videomode); + fprintf(file, "videopatch = %d\n", videopatch); + fprintf(file, "videoPatchDol = %d\n", videoPatchDol); + fprintf(file, "patchFix480p = %d\n", patchFix480p); + fprintf(file, "language = %d\n", language); + fprintf(file, "ocarina = %d\n", ocarina); + fprintf(file, "hddinfo = %d\n", hddinfo); + fprintf(file, "sinfo = %d\n", sinfo); + fprintf(file, "rumble = %d\n", rumble); + fprintf(file, "volume = %d\n", volume); + fprintf(file, "sfxvolume = %d\n", sfxvolume); + fprintf(file, "gamesoundvolume = %d\n", gamesoundvolume); + fprintf(file, "tooltips = %d\n", tooltips); + fprintf(file, "RememberUnlock = %d\n", RememberUnlock); + char EncryptedTxt[50]; + EncryptString(unlockCode, EncryptedTxt); + fprintf(file, "password = %s\n", EncryptedTxt); + fprintf(file, "GameSort = %d\n", GameSort); + fprintf(file, "LoaderIOS = %d\n", LoaderIOS); + fprintf(file, "cios = %d\n", cios); + fprintf(file, "keyset = %d\n", keyset); + fprintf(file, "xflip = %d\n", xflip); + fprintf(file, "gridRows = %d\n", gridRows); + fprintf(file, "quickboot = %d\n", quickboot); + fprintf(file, "wsprompt = %d\n", wsprompt); + fprintf(file, "parentalcontrol = %d\n", parentalcontrol); + fprintf(file, "covers_path = %s\n", covers_path); + fprintf(file, "covers2d_path = %s\n", covers2d_path); + fprintf(file, "coversFull_path = %s\n", coversFull_path); + fprintf(file, "theme_path = %s\n", theme_path); + fprintf(file, "theme = %s\n", theme); + fprintf(file, "disc_path = %s\n", disc_path); + fprintf(file, "language_path = %s\n", language_path); + fprintf(file, "languagefiles_path = %s\n", languagefiles_path); + fprintf(file, "TxtCheatcodespath = %s\n", TxtCheatcodespath); + fprintf(file, "titlestxt_path = %s\n", titlestxt_path); + fprintf(file, "gamesound = %d\n", gamesound); + fprintf(file, "dolpath = %s\n", dolpath); + fprintf(file, "ogg_path = %s\n", ogg_path); + fprintf(file, "wiilight = %d\n", wiilight); + fprintf(file, "gameDisplay = %d\n", gameDisplay); + fprintf(file, "update_path = %s\n", update_path); + fprintf(file, "homebrewapps_path = %s\n", homebrewapps_path); + fprintf(file, "BNRCachePath = %s\n", BNRCachePath); + fprintf(file, "Cheatcodespath = %s\n", Cheatcodespath); + fprintf(file, "BcaCodepath = %s\n", BcaCodepath); + fprintf(file, "WipCodepath = %s\n", WipCodepath); + fprintf(file, "WDMpath = %s\n", WDMpath); + fprintf(file, "titlesOverride = %d\n", titlesOverride); + fprintf(file, "ForceDiscTitles = %d\n", ForceDiscTitles); + fprintf(file, "patchcountrystrings = %d\n", patchcountrystrings); + fprintf(file, "screensaver = %d\n", screensaver); + fprintf(file, "musicloopmode = %d\n", musicloopmode); + fprintf(file, "autonetwork = %d\n", autonetwork); + fprintf(file, "discart = %d\n", discart); + fprintf(file, "coversfull = %d\n", coversfull); + fprintf(file, "partition = %d\n", partition); + fprintf(file, "marknewtitles = %d\n", marknewtitles); + fprintf(file, "ShowFreeSpace = %d\n", ShowFreeSpace); + fprintf(file, "InstallToDir = %d\n", InstallToDir); + fprintf(file, "GameSplit = %d\n", GameSplit); + fprintf(file, "InstallPartitions = %08X\n", (unsigned int)InstallPartitions); + fprintf(file, "PlaylogUpdate = %d\n", PlaylogUpdate); + fprintf(file, "ParentalBlocks = %08X\n", (unsigned int)ParentalBlocks); + fprintf(file, "returnTo = %s\n", returnTo); + fprintf(file, "HomeMenu = %d\n", HomeMenu); + fprintf(file, "MultiplePartitions = %d\n", MultiplePartitions); + fprintf(file, "USBPort = %d\n", USBPort); + fprintf(file, "USBAutoMount = %d\n", USBAutoMount); + fprintf(file, "CacheTitles = %d\n", CacheTitles); + fprintf(file, "BlockIOSReload = %d\n", BlockIOSReload); + fprintf(file, "WSFactor = %0.3f\n", WSFactor); + fprintf(file, "FontScaleFactor = %0.3f\n", FontScaleFactor); + fprintf(file, "ClockFontScaleFactor = %0.3f\n", ClockFontScaleFactor); + fprintf(file, "EnabledCategories = "); + for(u32 i = 0; i < EnabledCategories.size(); ++i) + { + fprintf(file, "%i", (int)EnabledCategories[i]); + if(i+1 < EnabledCategories.size()) + fprintf(file, ","); + } + fprintf(file, "\n"); + fprintf(file, "RequiredCategories = "); + for(u32 i = 0; i < RequiredCategories.size(); ++i) + { + fprintf(file, "%i", (int)RequiredCategories[i]); + if(i+1 < RequiredCategories.size()) + fprintf(file, ","); + } + fprintf(file, "\n"); + fprintf(file, "ForbiddenCategories = "); + for(u32 i = 0; i < ForbiddenCategories.size(); ++i) + { + fprintf(file, "%i", (int)ForbiddenCategories[i]); + if(i+1 < ForbiddenCategories.size()) + fprintf(file, ","); + } + fprintf(file, "\n"); + fprintf(file, "Wiinnertag = %d\n", Wiinnertag); + fprintf(file, "WiinnertagPath = %s\n", WiinnertagPath); + fprintf(file, "SelectedGame = %d\n", SelectedGame); + fprintf(file, "GameListOffset = %d\n", GameListOffset); + fprintf(file, "sneekVideoPatch = %d\n", sneekVideoPatch); + fprintf(file, "NandEmuMode = %d\n", NandEmuMode); + fprintf(file, "NandEmuChanMode = %d\n", NandEmuChanMode); + fprintf(file, "NandEmuPath = %s\n", NandEmuPath); + fprintf(file, "NandEmuChanPath = %s\n", NandEmuChanPath); + fprintf(file, "UseSystemFont = %d\n", UseSystemFont); + fprintf(file, "Hooktype = %d\n", Hooktype); + fprintf(file, "WiirdDebugger = %d\n", WiirdDebugger); + fprintf(file, "WiirdDebuggerPause = %d\n", WiirdDebuggerPause); + fprintf(file, "ShowPlayCount = %d\n", ShowPlayCount); + fprintf(file, "bannerFavIcon = %d\n", bannerFavIcon); + fprintf(file, "LoaderMode = %d\n", LoaderMode); + fprintf(file, "SearchMode = %d\n", SearchMode); + fprintf(file, "GameAspectRatio = %d\n", GameAspectRatio); + fprintf(file, "PointerSpeed = %g\n", PointerSpeed); + fprintf(file, "UseChanLauncher = %d\n", UseChanLauncher); + fprintf(file, "AdjustOverscanX = %d\n", AdjustOverscanX); + fprintf(file, "AdjustOverscanY = %d\n", AdjustOverscanY); + fprintf(file, "TooltipDelay = %d\n", TooltipDelay); + fprintf(file, "GameWindowMode = %d\n", GameWindowMode); + fprintf(file, "CacheBNRFiles = %d\n", CacheBNRFiles); + fprintf(file, "BannerAnimStart = %d\n", BannerAnimStart); + fprintf(file, "BannerGridSpeed = %g\n", BannerGridSpeed); + fprintf(file, "BannerZoomDuration = %d\n", BannerZoomDuration); + fprintf(file, "BannerProjectionOffsetX = %g\n", BannerProjectionOffsetX); + fprintf(file, "BannerProjectionOffsetY = %g\n", BannerProjectionOffsetY); + fprintf(file, "BannerProjectionWidth = %g\n", BannerProjectionWidth); + fprintf(file, "BannerProjectionHeight = %g\n", BannerProjectionHeight); + fprintf(file, "GCBannerScale = %g\n", GCBannerScale); + fprintf(file, "GameCubePath = %s\n", GameCubePath); + fprintf(file, "GameCubeSDPath = %s\n", GameCubeSDPath); + fprintf(file, "GameCubeMode = %d\n", GameCubeMode); + fprintf(file, "GameCubeSource = %d\n", GameCubeSource); + fprintf(file, "MultiDiscPrompt = %d\n", MultiDiscPrompt); + fprintf(file, "DMLVideo = %d\n", DMLVideo); + fprintf(file, "DMLProgPatch = %d\n", DMLProgPatch); + fprintf(file, "DMLNMM = %d\n", DMLNMM); + fprintf(file, "DMLActivityLED = %d\n", DMLActivityLED); + fprintf(file, "DMLPADHOOK = %d\n", DMLPADHOOK); + fprintf(file, "DMLNoDisc2 = %d\n", DMLNoDisc2); + fprintf(file, "DMLWidescreen = %d\n", DMLWidescreen); + fprintf(file, "DMLScreenshot = %d\n", DMLScreenshot); + fprintf(file, "DMLJPNPatch = %d\n", DMLJPNPatch); + fprintf(file, "DMLDebug = %d\n", DMLDebug); + fprintf(file, "NINDeflicker = %d\n", NINDeflicker); + fprintf(file, "NINPal50Patch = %d\n", NINPal50Patch); + fprintf(file, "NINWiiUWide = %d\n", NINWiiUWide); + fprintf(file, "NINVideoScale = %d\n", NINVideoScale); + fprintf(file, "NINVideoOffset = %d\n", NINVideoOffset); + fprintf(file, "NINRemlimit = %d\n", NINRemlimit); + fprintf(file, "NINArcadeMode = %d\n", NINArcadeMode); + fprintf(file, "NINCCRumble = %d\n", NINCCRumble); + fprintf(file, "NINSkipIPL = %d\n", NINSkipIPL); + fprintf(file, "NINBBA = %d\n", NINBBA); // ASA + fprintf(file, "NINBBAPROF = %d\n", NINBBAPROF); // ASA + fprintf(file, "NINMCEmulation = %d\n", NINMCEmulation); + fprintf(file, "NINMCSize = %d\n", NINMCSize); + fprintf(file, "NINAutoboot = %d\n", NINAutoboot); + fprintf(file, "NINSettings = %d\n", NINSettings); + fprintf(file, "NINUSBHID = %d\n", NINUSBHID); + fprintf(file, "NINMaxPads = %d\n", NINMaxPads); + fprintf(file, "NINNativeSI = %d\n", NINNativeSI); + fprintf(file, "NINOSReport = %d\n", NINOSReport); + fprintf(file, "NINLED = %d\n", NINLED); + fprintf(file, "NINLog = %d\n", NINLog); + fprintf(file, "DEVOMCEmulation = %d\n", DEVOMCEmulation); + fprintf(file, "DEVOWidescreen = %d\n", DEVOWidescreen); + fprintf(file, "DEVOActivityLED = %d\n", DEVOActivityLED); + fprintf(file, "DEVOFZeroAX = %d\n", DEVOFZeroAX); + fprintf(file, "DEVOTimerFix = %d\n", DEVOTimerFix); + fprintf(file, "DEVODButtons = %d\n", DEVODButtons); + fprintf(file, "DEVOCropOverscan = %d\n", DEVOCropOverscan); + fprintf(file, "DEVODiscDelay = %d\n", DEVODiscDelay); + fprintf(file, "DEVOLoaderPath = %s\n", DEVOLoaderPath); + fprintf(file, "NINLoaderPath = %s\n", NINLoaderPath); + fprintf(file, "GCInstallCompressed = %d\n", GCInstallCompressed); + fprintf(file, "GCInstallAligned = %d\n", GCInstallAligned); + fprintf(file, "PrivateServer = %d\n", PrivateServer); + fprintf(file, "CustomBannersURL = %s\n", CustomBannersURL); + fclose(file); + + return true; +} + +bool CSettings::SetSetting(char *name, char *value) +{ + if (strcmp(name, "godmode") == 0) + { + godmode = atoi(value); + return true; + } + else if (strcmp(name, "videomode") == 0) + { + videomode = atoi(value); + return true; + } + else if (strcmp(name, "videopatch") == 0) + { + videopatch = atoi(value); + return true; + } + else if (strcmp(name, "videoPatchDol") == 0) + { + videoPatchDol = atoi(value); + return true; + } + else if (strcmp(name, "patchFix480p") == 0) + { + patchFix480p = atoi(value); + return true; + } + else if (strcmp(name, "language") == 0) + { + language = atoi(value); + return true; + } + else if (strcmp(name, "ocarina") == 0) + { + ocarina = atoi(value); + return true; + } + else if (strcmp(name, "hddinfo") == 0) + { + hddinfo = atoi(value); + return true; + } + else if (strcmp(name, "sinfo") == 0) + { + sinfo = atoi(value); + return true; + } + else if (strcmp(name, "rumble") == 0) + { + rumble = atoi(value); + return true; + } + else if (strcmp(name, "volume") == 0) + { + volume = atoi(value); + return true; + } + else if (strcmp(name, "sfxvolume") == 0) + { + sfxvolume = atoi(value); + return true; + } + else if (strcmp(name, "gamesoundvolume") == 0) + { + gamesoundvolume = atoi(value); + return true; + } + else if (strcmp(name, "tooltips") == 0) + { + tooltips = atoi(value); + return true; + } + else if (strcmp(name, "RememberUnlock") == 0) + { + RememberUnlock = atoi(value); + return true; + } + else if (strcmp(name, "password") == 0) + { + char EncryptedTxt[50]; + strlcpy(EncryptedTxt, value, sizeof(EncryptedTxt)); + DecryptString(EncryptedTxt, unlockCode); + + if(!RememberUnlock && strlen(unlockCode) > 0 && strcmp(unlockCode, "not set") != 0) + godmode = 0; + return true; + } + else if (strcmp(name, "GameSort") == 0) + { + GameSort = atoi(value); + return true; + } + else if (strcmp(name, "LoaderIOS") == 0) + { + LoaderIOS = atoi(value); + return true; + } + else if (strcmp(name, "cios") == 0) + { + cios = atoi(value); + return true; + } + else if (strcmp(name, "keyset") == 0) + { + keyset = atoi(value); + return true; + } + else if (strcmp(name, "xflip") == 0) + { + xflip = atoi(value); + return true; + } + else if (strcmp(name, "gridRows") == 0) + { + gridRows = atoi(value); + return true; + } + else if (strcmp(name, "quickboot") == 0) + { + quickboot = atoi(value); + return true; + } + else if (strcmp(name, "partition") == 0) + { + partition = atoi(value); + return true; + } + else if (strcmp(name, "wsprompt") == 0) + { + wsprompt = atoi(value); + return true; + } + else if (strcmp(name, "gameDisplay") == 0) + { + gameDisplay = atoi(value); + return true; + } + else if (strcmp(name, "parentalcontrol") == 0) + { + parentalcontrol = atoi(value); + return true; + } + else if (strcmp(name, "screensaver") == 0) + { + screensaver = atoi(value); + return true; + } + else if (strcmp(name, "titlesOverride") == 0) + { + titlesOverride = atoi(value); + return true; + } + else if (strcmp(name, "ForceDiscTitles") == 0) + { + ForceDiscTitles = atoi(value); + return true; + } + else if (strcmp(name, "musicloopmode") == 0) + { + musicloopmode = atoi(value); + return true; + } + else if (strcmp(name, "gamesound") == 0) + { + gamesound = atoi(value); + return true; + } + else if (strcmp(name, "wiilight") == 0) + { + wiilight = atoi(value); + return true; + } + else if (strcmp(name, "marknewtitles") == 0) + { + marknewtitles = atoi(value); + return true; + } + else if (strcmp(name, "ShowPlayCount") == 0) + { + ShowPlayCount = atoi(value); + return true; + } + else if (strcmp(name, "bannerFavIcon") == 0) + { + bannerFavIcon = atoi(value); + return true; + } + else if (strcmp(name, "ShowFreeSpace") == 0) + { + ShowFreeSpace = atoi(value); + return true; + } + else if (strcmp(name, "HomeMenu") == 0) + { + HomeMenu = atoi(value); + return true; + } + else if (strcmp(name, "MultiplePartitions") == 0) + { + MultiplePartitions = atoi(value); + return true; + } + else if (strcmp(name, "BlockIOSReload") == 0) + { + BlockIOSReload = atoi(value); + return true; + } + else if (strcmp(name, "USBPort") == 0) + { + USBPort = atoi(value); + return true; + } + else if (strcmp(name, "USBAutoMount") == 0) + { + USBAutoMount = atoi(value); + return true; + } + else if (strcmp(name, "CacheTitles") == 0) + { + CacheTitles = atoi(value); + return true; + } + else if (strcmp(name, "patchcountrystrings") == 0) + { + patchcountrystrings = atoi(value); + return true; + } + else if (strcmp(name, "discart") == 0) + { + discart = atoi(value); + return true; + } + else if (strcmp(name, "coversfull") == 0) + { + coversfull = atoi(value); + return true; + } + else if (strcmp(name, "autonetwork") == 0) + { + autonetwork = atoi(value); + return true; + } + else if (strcmp(name, "InstallToDir") == 0) + { + InstallToDir = atoi(value); + return true; + } + else if (strcmp(name, "GameSplit") == 0) + { + GameSplit = atoi(value); + return true; + } + else if (strcmp(name, "PlaylogUpdate") == 0) + { + PlaylogUpdate = atoi(value); + return true; + } + else if(strcmp(name, "Wiinnertag") == 0) + { + Wiinnertag = atoi(value); + } + else if(strcmp(name, "SelectedGame") == 0) + { + SelectedGame = atoi(value); + } + else if(strcmp(name, "GameListOffset") == 0) + { + GameListOffset = atoi(value); + } + else if(strcmp(name, "sneekVideoPatch") == 0) + { + sneekVideoPatch = atoi(value); + } + else if(strcmp(name, "UseSystemFont") == 0) + { + UseSystemFont = atoi(value); + } + else if(strcmp(name, "Hooktype") == 0) + { + Hooktype = atoi(value); + } + else if(strcmp(name, "WiirdDebugger") == 0) + { + WiirdDebugger = atoi(value); + } + else if(strcmp(name, "WiirdDebuggerPause") == 0) + { + WiirdDebuggerPause = atoi(value); + } + else if(strcmp(name, "NandEmuMode") == 0) + { + NandEmuMode = atoi(value); + } + else if(strcmp(name, "NandEmuChanMode") == 0) + { + NandEmuChanMode = atoi(value); + } + else if(strcmp(name, "LoaderMode") == 0) + { + LoaderMode = atoi(value); + } + else if(strcmp(name, "SearchMode") == 0) + { + SearchMode = atoi(value); + } + else if(strcmp(name, "GameAspectRatio") == 0) + { + GameAspectRatio = atoi(value); + } + else if(strcmp(name, "UseChanLauncher") == 0) + { + UseChanLauncher = atoi(value); + } + else if(strcmp(name, "AdjustOverscanX") == 0) + { + AdjustOverscanX = atoi(value); + } + else if(strcmp(name, "AdjustOverscanY") == 0) + { + AdjustOverscanY = atoi(value); + } + else if(strcmp(name, "TooltipDelay") == 0) + { + TooltipDelay = atoi(value); + } + else if(strcmp(name, "BannerZoomDuration") == 0) + { + BannerZoomDuration = atoi(value); + } + else if(strcmp(name, "GameWindowMode") == 0) + { + GameWindowMode = atoi(value); + } + else if(strcmp(name, "BannerAnimStart") == 0) + { + BannerAnimStart = atoi(value); + } + else if(strcmp(name, "CacheBNRFiles") == 0) + { + CacheBNRFiles = atoi(value); + } + else if (strcmp(name, "InstallPartitions") == 0) + { + InstallPartitions = strtoul(value, 0, 16); + return true; + } + else if (strcmp(name, "WSFactor") == 0) + { + WSFactor = atof(value); + return true; + } + else if (strcmp(name, "FontScaleFactor") == 0) + { + FontScaleFactor = atof(value); + return true; + } + else if (strcmp(name, "ClockFontScaleFactor") == 0) + { + ClockFontScaleFactor = atof(value); + return true; + } + else if (strcmp(name, "PointerSpeed") == 0) + { + PointerSpeed = atof(value); + return true; + } + else if (strcmp(name, "BannerGridSpeed") == 0) + { + BannerGridSpeed = atof(value); + return true; + } + else if (strcmp(name, "BannerProjectionOffsetX") == 0) + { + BannerProjectionOffsetX = atof(value); + return true; + } + else if (strcmp(name, "BannerProjectionOffsetY") == 0) + { + BannerProjectionOffsetY = atof(value); + return true; + } + else if (strcmp(name, "BannerProjectionWidth") == 0) + { + BannerProjectionWidth = atof(value); + return true; + } + else if (strcmp(name, "BannerProjectionHeight") == 0) + { + BannerProjectionHeight = atof(value); + return true; + } + else if (strcmp(name, "GCBannerScale") == 0) + { + GCBannerScale = atof(value); + return true; + } + else if (strcmp(name, "ParentalBlocks") == 0) + { + ParentalBlocks = strtoul(value, 0, 16); + return true; + } + else if (strcmp(name, "GameCubeMode") == 0) + { + GameCubeMode = atoi(value); + return true; + } + else if (strcmp(name, "GameCubeSource") == 0) + { + GameCubeSource = atoi(value); + return true; + } + else if (strcmp(name, "MultiDiscPrompt") == 0) + { + MultiDiscPrompt = atoi(value); + return true; + } + else if (strcmp(name, "DMLVideo") == 0) + { + DMLVideo = atoi(value); + return true; + } + else if (strcmp(name, "DMLProgPatch") == 0) + { + DMLProgPatch = atoi(value); + return true; + } + else if (strcmp(name, "DMLNMM") == 0) + { + DMLNMM = atoi(value); + return true; + } + else if (strcmp(name, "DMLActivityLED") == 0) + { + DMLActivityLED = atoi(value); + return true; + } + else if (strcmp(name, "DMLPADHOOK") == 0) + { + DMLPADHOOK = atoi(value); + return true; + } + else if (strcmp(name, "DMLNoDisc2") == 0) + { + DMLNoDisc2 = atoi(value); + return true; + } + else if (strcmp(name, "DMLWidescreen") == 0) + { + DMLWidescreen = atoi(value); + return true; + } + else if (strcmp(name, "DMLScreenshot") == 0) + { + DMLScreenshot = atoi(value); + return true; + } + else if (strcmp(name, "DMLJPNPatch") == 0) + { + DMLJPNPatch = atoi(value); + return true; + } + else if (strcmp(name, "DMLDebug") == 0) + { + DMLDebug = atoi(value); + return true; + } + else if (strcmp(name, "NINDeflicker") == 0) + { + NINDeflicker = atoi(value); + return true; + } + else if (strcmp(name, "NINPal50Patch") == 0) + { + NINPal50Patch = atoi(value); + return true; + } + else if (strcmp(name, "NINWiiUWide") == 0) + { + NINWiiUWide = atoi(value); + return true; + } + else if (strcmp(name, "NINVideoScale") == 0) + { + NINVideoScale = atoi(value); + return true; + } + else if (strcmp(name, "NINVideoOffset") == 0) + { + NINVideoOffset = atoi(value); + return true; + } + else if (strcmp(name, "NINRemlimit") == 0) + { + NINRemlimit = atoi(value); + return true; + } + else if (strcmp(name, "NINArcadeMode") == 0) + { + NINArcadeMode = atoi(value); + return true; + } + else if (strcmp(name, "NINCCRumble") == 0) + { + NINCCRumble = atoi(value); + return true; + } + else if (strcmp(name, "NINSkipIPL") == 0) + { + NINSkipIPL = atoi(value); + return true; + } + else if (strcmp(name, "NINBBA") == 0) // ASA + { + NINBBA = atoi(value); + return true; + } + else if (strcmp(name, "NINBBAPROF") == 0) // ASA + { + NINBBAPROF = atoi(value); + return true; + } + else if (strcmp(name, "NINMCEmulation") == 0) + { + NINMCEmulation = atoi(value); + return true; + } + else if (strcmp(name, "NINMCSize") == 0) + { + NINMCSize = atoi(value); + return true; + } + else if (strcmp(name, "NINAutoboot") == 0) + { + NINAutoboot = atoi(value); + return true; + } + else if (strcmp(name, "NINSettings") == 0) + { + NINSettings = atoi(value); + return true; + } + else if (strcmp(name, "NINUSBHID") == 0) + { + NINUSBHID = atoi(value); + return true; + } + else if (strcmp(name, "NINMaxPads") == 0) + { + NINMaxPads = atoi(value); + return true; + } + else if (strcmp(name, "NINNativeSI") == 0) + { + NINNativeSI = atoi(value); + return true; + } + else if (strcmp(name, "NINOSReport") == 0) + { + NINOSReport = atoi(value); + return true; + } + else if (strcmp(name, "NINLED") == 0) + { + NINLED = atoi(value); + return true; + } + else if (strcmp(name, "NINLog") == 0) + { + NINLog = atoi(value); + return true; + } + else if (strcmp(name, "DEVOMCEmulation") == 0) + { + DEVOMCEmulation = atoi(value); + return true; + } + else if (strcmp(name, "DEVOWidescreen") == 0) + { + DEVOWidescreen = atoi(value); + return true; + } + else if (strcmp(name, "DEVOActivityLED") == 0) + { + DEVOActivityLED = atoi(value); + return true; + } + else if (strcmp(name, "DEVOFZeroAX") == 0) + { + DEVOFZeroAX = atoi(value); + return true; + } + else if (strcmp(name, "DEVOTimerFix") == 0) + { + DEVOTimerFix = atoi(value); + return true; + } + else if (strcmp(name, "DEVODButtons") == 0) + { + DEVODButtons = atoi(value); + return true; + } + else if (strcmp(name, "DEVOCropOverscan") == 0) + { + DEVOCropOverscan = atoi(value); + return true; + } + else if (strcmp(name, "DEVODiscDelay") == 0) + { + DEVODiscDelay = atoi(value); + return true; + } + else if (strcmp(name, "DEVOLoaderPath") == 0) + { + strlcpy(DEVOLoaderPath, value, sizeof(DEVOLoaderPath)); + return true; + } + else if (strcmp(name, "NINLoaderPath") == 0) + { + strlcpy(NINLoaderPath, value, sizeof(NINLoaderPath)); + return true; + } + else if (strcmp(name, "GCInstallCompressed") == 0) + { + GCInstallCompressed = atoi(value); + return true; + } + else if (strcmp(name, "GCInstallAligned") == 0) + { + GCInstallAligned = atoi(value); + return true; + } + else if (strcmp(name, "covers_path") == 0) + { + strlcpy(covers_path, value, sizeof(covers_path)); + return true; + } + else if (strcmp(name, "covers2d_path") == 0) + { + strlcpy(covers2d_path, value, sizeof(covers2d_path)); + return true; + } + else if (strcmp(name, "coversFull_path") == 0) + { + strlcpy(coversFull_path, value, sizeof(coversFull_path)); + return true; + } + else if (strcmp(name, "theme_path") == 0) + { + strlcpy(theme_path, value, sizeof(theme_path)); + return true; + } + else if (strcmp(name, "theme") == 0) + { + strlcpy(theme, value, sizeof(theme)); + return true; + } + else if (strcmp(name, "disc_path") == 0) + { + strlcpy(disc_path, value, sizeof(disc_path)); + return true; + } + else if (strcmp(name, "language_path") == 0) + { + strlcpy(language_path, value, sizeof(language_path)); + return true; + } + else if (strcmp(name, "languagefiles_path") == 0) + { + strlcpy(languagefiles_path, value, sizeof(languagefiles_path)); + return true; + } + else if (strcmp(name, "TxtCheatcodespath") == 0) + { + strlcpy(TxtCheatcodespath, value, sizeof(TxtCheatcodespath)); + return true; + } + else if (strcmp(name, "titlestxt_path") == 0) + { + strlcpy(titlestxt_path, value, sizeof(titlestxt_path)); + return true; + } + else if (strcmp(name, "dolpath") == 0) + { + strlcpy(dolpath, value, sizeof(dolpath)); + return true; + } + else if (strcmp(name, "ogg_path") == 0) + { + strlcpy(ogg_path, value, sizeof(ogg_path)); + return true; + } + else if (strcmp(name, "update_path") == 0) + { + strlcpy(update_path, value, sizeof(update_path)); + return true; + } + else if (strcmp(name, "homebrewapps_path") == 0) + { + strlcpy(homebrewapps_path, value, sizeof(homebrewapps_path)); + return true; + } + else if (strcmp(name, "BNRCachePath") == 0) + { + strlcpy(BNRCachePath, value, sizeof(BNRCachePath)); + return true; + } + else if (strcmp(name, "Cheatcodespath") == 0) + { + strlcpy(Cheatcodespath, value, sizeof(Cheatcodespath)); + return true; + } + else if (strcmp(name, "BcaCodepath") == 0) + { + strlcpy(BcaCodepath, value, sizeof(BcaCodepath)); + return true; + } + else if (strcmp(name, "WipCodepath") == 0) + { + strlcpy(WipCodepath, value, sizeof(WipCodepath)); + return true; + } + else if (strcmp(name, "WDMpath") == 0) + { + strlcpy(WDMpath, value, sizeof(WDMpath)); + return true; + } + else if (strcmp(name, "returnTo") == 0) + { + strlcpy(returnTo, value, sizeof(returnTo)); + return true; + } + else if (strcmp(name, "WiinnertagPath") == 0) + { + strlcpy(WiinnertagPath, value, sizeof(WiinnertagPath)); + return true; + } + else if (strcmp(name, "NandEmuPath") == 0) + { + strlcpy(NandEmuPath, value, sizeof(NandEmuPath)); + return true; + } + else if (strcmp(name, "NandEmuChanPath") == 0) + { + strlcpy(NandEmuChanPath, value, sizeof(NandEmuChanPath)); + return true; + } + else if (strcmp(name, "GameCubePath") == 0) + { + strlcpy(GameCubePath, value, sizeof(GameCubePath)); + return true; + } + else if (strcmp(name, "GameCubeSDPath") == 0) + { + strlcpy(GameCubeSDPath, value, sizeof(GameCubeSDPath)); + return true; + } + else if (strcmp(name, "CustomBannersURL") == 0) + { + // update banner URL + if( strcmp(value, "http://dl.dropbox.com/u/101209384/") == 0 || + strcmp(value, "http://dl.dropboxusercontent.com/u/101209384/") == 0 || + strcmp(value, "http://copy.com/vRN3HgFVyk9u7YuB/Public/") == 0 || + strcmp(value, "http://nintendont.gxarena.com/banners/") == 0) // Thanks to AbdallahTerro for this one and previous URLs + strlcpy(CustomBannersURL, "http://banner.rc24.xyz/", sizeof(CustomBannersURL)); // Thanks to Larsenv + else + strlcpy(CustomBannersURL, value, sizeof(CustomBannersURL)); + return true; + } + else if(strcmp(name, "PrivateServer") == 0) + { + PrivateServer = atoi(value); + } + else if (strcmp(name, "EnabledCategories") == 0) + { + EnabledCategories.clear(); + char * strTok = strtok(value, ","); + while (strTok != NULL) + { + u32 id = atoi(strTok); + u32 i; + for(i = 0; i < EnabledCategories.size(); ++i) + { + if(EnabledCategories[i] == id) + break; + } + if(i == EnabledCategories.size()) + EnabledCategories.push_back(id); + strTok = strtok(NULL,","); + } + return true; + } + else if (strcmp(name, "RequiredCategories") == 0) + { + RequiredCategories.clear(); + char * strTok = strtok(value, ","); + while (strTok != NULL) + { + u32 id = atoi(strTok); + u32 i; + for(i = 0; i < RequiredCategories.size(); ++i) + { + if(RequiredCategories[i] == id) + break; + } + if(i == RequiredCategories.size()) + RequiredCategories.push_back(id); + strTok = strtok(NULL,","); + } + return true; + } + else if (strcmp(name, "ForbiddenCategories") == 0) + { + ForbiddenCategories.clear(); + char * strTok = strtok(value, ","); + while (strTok != NULL) + { + u32 id = atoi(strTok); + u32 i; + for(i = 0; i < ForbiddenCategories.size(); ++i) + { + if(ForbiddenCategories[i] == id) + break; + } + if(i == ForbiddenCategories.size()) + ForbiddenCategories.push_back(id); + strTok = strtok(NULL,","); + } + return true; + } + + return false; +} + +bool CSettings::FindConfig() +{ + bool found = false; + char CheckDevice[12]; + char CheckPath[300]; + + // Enumerate the devices supported by libogc. + for (int i = SD; (i < MAXDEVICES) && !found; ++i) + { + snprintf(CheckDevice, sizeof(CheckDevice), "%s:", DeviceName[i]); + + if(!found) + { + // Check for the config file in the apps directory. + strlcpy(BootDevice, CheckDevice, sizeof(BootDevice)); + snprintf(ConfigPath, sizeof(ConfigPath), "%s/apps/usbloader_gx/", BootDevice); + snprintf(CheckPath, sizeof(CheckPath), "%sGXGlobal.cfg", ConfigPath); + found = CheckFile(CheckPath); + } + if(!found) + { + // Check for the config file in the config directory. + strlcpy(BootDevice, CheckDevice, sizeof(BootDevice)); + snprintf(ConfigPath, sizeof(ConfigPath), "%s/config/", BootDevice); + snprintf(CheckPath, sizeof(CheckPath), "%sGXGlobal.cfg", ConfigPath); + found = CheckFile(CheckPath); + } + } + + FILE * testFp = NULL; + //! No existing config so try to find a place where we can write it too + for (int i = SD; (i < MAXDEVICES) && !found; ++i) + { + sprintf(CheckDevice, "%s:", DeviceName[i]); + + if (!found) + { + // Check if we can write to the apps directory. + strlcpy(BootDevice, CheckDevice, sizeof(BootDevice)); + snprintf(ConfigPath, sizeof(ConfigPath), "%s/apps/usbloader_gx/", BootDevice); + snprintf(CheckPath, sizeof(CheckPath), "%sGXGlobal.cfg", ConfigPath); + testFp = fopen(CheckPath, "wb"); + found = (testFp != NULL); + if(testFp) fclose(testFp); + } + if (!found) + { + // Check if we can write to the config directory. + strlcpy(BootDevice, CheckDevice, sizeof(BootDevice)); + snprintf(ConfigPath, sizeof(ConfigPath), "%s/config/", BootDevice); + CreateSubfolder(ConfigPath); + snprintf(CheckPath, sizeof(CheckPath), "%sGXGlobal.cfg", ConfigPath); + testFp = fopen(CheckPath, "wb"); + found = (testFp != NULL); + if(testFp) fclose(testFp); + } + } + + return found; +} + +void CSettings::ParseLine(char *line) +{ + char temp[1024], name[1024], value[1024]; + + strncpy(temp, line, sizeof(temp)); + + char * eq = strchr(temp, '='); + + if (!eq) return; + + *eq = 0; + + this->TrimLine(name, temp, sizeof(name)); + this->TrimLine(value, eq + 1, sizeof(value)); + + this->SetSetting(name, value); +} + +void CSettings::TrimLine(char *dest, char *src, int size) +{ + int len; + while (*src == ' ') + src++; + len = strlen(src); + while (len > 0 && strchr(" \r\n", src[len - 1])) + len--; + if (len >= size) len = size - 1; + strncpy(dest, src, len); + dest[len] = 0; +} + +//! Get language code from the selected language file +//! eg. german.lang = DE and default to EN +static inline const char * GetLangCode(const char * langpath) +{ + if(strcasestr(langpath, "japanese")) + return "JA"; + + else if(strcasestr(langpath, "german")) + return "DE"; + + else if(strcasestr(langpath, "french")) + return "FR"; + + else if(strcasestr(langpath, "spanish")) + return "ES"; + + else if(strcasestr(langpath, "italian")) + return "IT"; + + else if(strcasestr(langpath, "dutch")) + return "NL"; + + else if(strcasestr(langpath, "schinese")) + return "ZHCN"; + + else if(strcasestr(langpath, "tchinese")) + return "ZHTW"; + + else if(strcasestr(langpath, "korean")) + return "KO"; + + return "EN"; +} + +bool CSettings::LoadLanguage(const char *path, int lang) +{ + bool ret = false; + + if (path && strlen(path) > 3) + { + ret = gettextLoadLanguage(path); + if (ret) + { + strlcpy(language_path, path, sizeof(language_path)); + strlcpy(db_language, GetLangCode(language_path), sizeof(db_language)); + } + else + return LoadLanguage(NULL, CONSOLE_DEFAULT); + } + else if (lang >= 0) + { + char filepath[150]; + char langpath[150]; + strlcpy(langpath, languagefiles_path, sizeof(langpath)); + if (langpath[strlen(langpath) - 1] != '/') + { + char * ptr = strrchr(langpath, '/'); + if (ptr) + { + ptr++; + ptr[0] = '\0'; + } + } + + if (lang == CONSOLE_DEFAULT) + { + return LoadLanguage(NULL, CONF_GetLanguage()); + } + else if (lang == JAPANESE) + { + snprintf(filepath, sizeof(filepath), "%s/japanese.lang", langpath); + } + else if (lang == ENGLISH) + { + snprintf(filepath, sizeof(filepath), "%s/english.lang", langpath); + } + else if (lang == GERMAN) + { + snprintf(filepath, sizeof(filepath), "%s/german.lang", langpath); + } + else if (lang == FRENCH) + { + snprintf(filepath, sizeof(filepath), "%s/french.lang", langpath); + } + else if (lang == SPANISH) + { + snprintf(filepath, sizeof(filepath), "%s/spanish.lang", langpath); + } + else if (lang == ITALIAN) + { + snprintf(filepath, sizeof(filepath), "%s/italian.lang", langpath); + } + else if (lang == DUTCH) + { + snprintf(filepath, sizeof(filepath), "%s/dutch.lang", langpath); + } + else if (lang == S_CHINESE) + { + snprintf(filepath, sizeof(filepath), "%s/schinese.lang", langpath); + } + else if (lang == T_CHINESE) + { + snprintf(filepath, sizeof(filepath), "%s/tchinese.lang", langpath); + } + else if (lang == KOREAN) + { + snprintf(filepath, sizeof(filepath), "%s/korean.lang", langpath); + } + + strlcpy(db_language, GetLangCode(filepath), sizeof(db_language)); + ret = gettextLoadLanguage(filepath); + if (ret) + strlcpy(language_path, filepath, sizeof(language_path)); + } + + return ret; +} diff --git a/source/settings/CSettings.h b/source/settings/CSettings.h new file mode 100644 index 0000000..5f71668 --- /dev/null +++ b/source/settings/CSettings.h @@ -0,0 +1,240 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _CSETTINGS_H_ +#define _CSETTINGS_H_ + +#include +#include +#include +#include +#include "SettingsEnums.h" +#include "GameCube/DML_Config.h" +#include "GameCube/DEVO_Config.h" +#include "GameCube/NIN_Config.h" + +class CSettings +{ + public: + //!Constructor + CSettings(); + //!Destructor + ~CSettings(); + //!Set Default Settings + void SetDefault(); + //!Load Settings + bool Load(); + //!Save Settings + bool Save(); + //!Reset Settings + bool Reset(); + //!Load a languagefile + //!\param language + bool LoadLanguage(const char *path, int language = -1); + + //! System settings stuff + bool widescreen; + bool PAL50; + bool NTSC; + + /** Variables **/ + char BootDevice[10]; + char unlockCode[20]; + char db_language[20]; + char returnTo[20]; + char ConfigPath[80]; + char covers_path[100]; + char coversFull_path[100]; + char covers2d_path[100]; + char theme_path[100]; + char theme[100]; + char disc_path[100]; + char titlestxt_path[100]; + char language_path[100]; + char languagefiles_path[100]; + char ogg_path[150]; + char Cheatcodespath[100]; + char TxtCheatcodespath[100]; + char BcaCodepath[100]; + char WipCodepath[100]; + char dolpath[100]; + char update_path[100]; + char homebrewapps_path[100]; + char WDMpath[100]; + char WiinnertagPath[100]; + char NandEmuPath[50]; + char NandEmuChanPath[50]; + char BNRCachePath[50]; + char GameCubePath[100]; + char GameCubeSDPath[100]; + char DEVOLoaderPath[100]; + char NINLoaderPath[100]; + char CustomBannersURL[100]; + short videomode; + short language; + short ocarina; + short videopatch; + short videoPatchDol; + short patchFix480p; + short sinfo; + short hddinfo; + short rumble; + short xflip; + short volume; + short sfxvolume; + short gamesoundvolume; + short tooltips; + short parentalcontrol; + u8 LoaderIOS; + u8 cios; + short quickboot; + short wsprompt; + short keyset; + short GameSort; + short wiilight; + short gameDisplay; + short patchcountrystrings; + short screensaver; + short partition; + short musicloopmode; + short godmode; + short titlesOverride; // db_titles + short gridRows; + short autonetwork; + short discart; + short coversfull; + short gamesound; + short marknewtitles; + short InstallToDir; + short GameSplit; + short PlaylogUpdate; + short ShowFreeSpace; + short HomeMenu; + short MultiplePartitions; + short USBPort; + short USBAutoMount; + short CacheTitles; + short BlockIOSReload; + u32 InstallPartitions; + u32 ParentalBlocks; + f32 WSFactor; + f32 FontScaleFactor; + f32 ClockFontScaleFactor; + f32 PointerSpeed; + short Wiinnertag; + short SelectedGame; + short GameListOffset; + short sneekVideoPatch; + std::vector EnabledCategories; + std::vector RequiredCategories; + std::vector ForbiddenCategories; + u8 EntryIOS; + short UseArgumentIOS; + short NandEmuMode; + short NandEmuChanMode; + short UseSystemFont; + short Hooktype; + short WiirdDebugger; + short WiirdDebuggerPause; + short ShowPlayCount; + short bannerFavIcon; + short RememberUnlock; + short LoaderMode; + short SearchMode; + short GameAspectRatio; + short UseChanLauncher; + int AdjustOverscanX; + int AdjustOverscanY; + short ForceDiscTitles; + short TooltipDelay; + short GameWindowMode; + short CacheBNRFiles; + short BannerAnimStart; + float BannerGridSpeed; + short BannerZoomDuration; + float BannerProjectionOffsetX; + float BannerProjectionOffsetY; + float BannerProjectionWidth; + float BannerProjectionHeight; + float GCBannerScale; + short GameCubeMode; + short GameCubeSource; + short MultiDiscPrompt; + short DMLVideo; + short DMLProgPatch; + short DMLNMM; + short DMLActivityLED; + short DMLPADHOOK; + short DMLNoDisc2; + short DMLWidescreen; + short DMLScreenshot; + short DMLJPNPatch; + short DMLDebug; + short NINDeflicker; + short NINPal50Patch; + short NINWiiUWide; + short NINVideoScale; + short NINVideoOffset; + short NINRemlimit; + short NINArcadeMode; + short NINCCRumble; + short NINSkipIPL; + short NINBBA; // ASA + short NINBBAPROF; // ASA + s8 NINMCEmulation; + short NINMCSize; + short NINAutoboot; + short NINSettings; + short NINUSBHID; + short NINMaxPads; + short NINNativeSI; + short NINOSReport; + short NINLED; + short NINLog; + short DEVOMCEmulation; + short DEVOWidescreen; + short DEVOActivityLED; + short DEVOFZeroAX; + short DEVOTimerFix; + short DEVODButtons; + short DEVOCropOverscan; + short DEVODiscDelay; + short GCInstallCompressed; + short GCInstallAligned; + short PrivateServer; + + // This variable is not saved to the settings file + bool FirstTimeRun; + protected: + bool ValidVersion(FILE * file); + bool SetSetting(char *name, char *value); + //!Find the config file in the default paths + bool FindConfig(); + + void ParseLine(char *line); + void TrimLine(char *dest, char *src, int size); +}; + +extern CSettings Settings; + +#endif diff --git a/source/settings/GameTitles.cpp b/source/settings/GameTitles.cpp new file mode 100644 index 0000000..5c911fc --- /dev/null +++ b/source/settings/GameTitles.cpp @@ -0,0 +1,297 @@ +#include +#include "GameTitles.h" +#include "CSettings.h" +#include "usbloader/GameList.h" +#include "Channels/channels.h" +#include "xml/GameTDB.hpp" +#include "svnrev.h" +#include "gecko.h" + +#define VALID_CACHE_REVISION 1148 + +CGameTitles GameTitles; + +void CGameTitles::SetGameTitle(const char * id, const char * title) +{ + if(!id || !title) + return; + + for(u32 i = 0; i < TitleList.size(); ++i) + { + if(strncasecmp(id, TitleList[i].GameID, 6) == 0) + { + TitleList[i].Title = title; + return; + } + } + + GameTitle newTitle; + snprintf(newTitle.GameID, sizeof(newTitle.GameID), id); + newTitle.Title = title; + newTitle.ParentalRating = -1; + newTitle.PlayersCount = 1; + newTitle.FromWiiTDB = 0; + + TitleList.push_back(newTitle); +} + +const char * CGameTitles::GetTitle(const char * id) const +{ + if(!id) + return ""; + + for(u32 i = 0; i < TitleList.size(); ++i) + { + if(strncasecmp(id, TitleList[i].GameID, 6) == 0) + return TitleList[i].Title.c_str(); + } + + for(int i = 0; i < gameList.size(); ++i) + { + if(strncasecmp(id, (char *) gameList[i]->id, 6) == 0) + return gameList[i]->title; + + } + + return ""; +} + +const char * CGameTitles::GetTitle(const struct discHdr *header) const +{ + if(!header) + return ""; + + for(u32 i = 0; i < TitleList.size(); ++i) + { + if(strncasecmp((const char *) header->id, TitleList[i].GameID, 6) == 0) + return TitleList[i].Title.c_str(); + } + + return header->title; +} + +int CGameTitles::GetParentalRating(const char * id) const +{ + if(!id) + return -1; + + for(u32 i = 0; i < TitleList.size(); ++i) + { + if(strncasecmp(id, TitleList[i].GameID, 6) == 0) + return TitleList[i].ParentalRating; + } + + return -1; +} + + +int CGameTitles::GetPlayersCount(const char * id) const +{ + if(!id) + return 1; + + for(u32 i = 0; i < TitleList.size(); ++i) + { + if(strncasecmp(id, TitleList[i].GameID, 6) == 0) + return TitleList[i].PlayersCount; + } + + return 1; +} + +void CGameTitles::SetDefault() +{ + TitleList.clear(); + //! Free vector memory + std::vector().swap(TitleList); +} + +typedef struct _CacheTitle +{ + char GameID[7]; + char Title[100]; + char FromWiiTDB; + int ParentalRating; + int PlayersCount; + +} ATTRIBUTE_PACKED CacheTitle; + +u32 CGameTitles::ReadCachedTitles(const char * path) +{ + std::string Cachepath = path; + if(path[strlen(path)-1] != '/') + Cachepath += '/'; + Cachepath += "TitlesCache.bin"; + + //! Load cached least so that the titles are preloaded before reading list + FILE * f = fopen(Cachepath.c_str(), "rb"); + if(!f) return 0; + + u32 revision = 0; + + fread(&revision, 1, 4, f); + + if(revision < VALID_CACHE_REVISION) + { + fclose(f); + return 0; + } + + char LangCode[11]; + memset(LangCode, 0, sizeof(LangCode)); + + fread(LangCode, 1, 10, f); + + //! Check if cache has correct language code + if(strcmp(LangCode, Settings.db_language) != 0) + { + fclose(f); + return 0; + } + + u32 count = 0; + fread(&count, 1, 4, f); + + std::vector CachedList(count); + TitleList.resize(count); + + fread(&CachedList[0], 1, count*sizeof(CacheTitle), f); + fclose(f); + + for(u32 i = 0; i < count; ++i) + { + strcpy(TitleList[i].GameID, CachedList[i].GameID); + TitleList[i].Title = CachedList[i].Title; + TitleList[i].ParentalRating = CachedList[i].ParentalRating; + TitleList[i].PlayersCount = CachedList[i].PlayersCount; + TitleList[i].FromWiiTDB = CachedList[i].FromWiiTDB; + } + + return count; +} + +void CGameTitles::WriteCachedTitles(const char * path) +{ + std::string Cachepath = path; + if(path[strlen(path)-1] != '/') + Cachepath += '/'; + Cachepath += "TitlesCache.bin"; + + FILE *f = fopen(Cachepath.c_str(), "wb"); + if(!f) + return; + + CacheTitle Cache; + u32 count = TitleList.size(); + u32 revision = atoi(GetRev()); + fwrite(&revision, 1, 4, f); + fwrite(Settings.db_language, 1, 10, f); + fwrite(&count, 1, 4, f); + + for(u32 i = 0; i < count; ++i) + { + memset(&Cache, 0, sizeof(CacheTitle)); + + strncpy(Cache.GameID, TitleList[i].GameID, sizeof(Cache.GameID)-1); + strncpy(Cache.Title, TitleList[i].Title.c_str(), sizeof(Cache.Title)-1); + Cache.ParentalRating = TitleList[i].ParentalRating; + Cache.PlayersCount = TitleList[i].PlayersCount; + Cache.FromWiiTDB = TitleList[i].FromWiiTDB; + + fwrite(&Cache, 1, sizeof(CacheTitle), f); + } + + fclose(f); +} + +void CGameTitles::GetMissingTitles(std::vector &MissingTitles, bool removeUnused) +{ + std::vector &FullList = gameList.GetFilteredList(); + std::vector UsedCachedList(TitleList.size(), false); + + for(u32 i = 0; i < FullList.size(); ++i) + { + bool isCached = false; + + for(u32 n = 0; n < TitleList.size(); ++n) + { + if(strncasecmp(TitleList[n].GameID, (const char *) FullList[i]->id, 6) == 0) + { + UsedCachedList[n] = true; + //! If the title is not from WiiTDB, try to reload it + isCached = TitleList[n].FromWiiTDB; + break; + } + } + + if(!isCached) + { + char gameID[7]; + snprintf(gameID, sizeof(gameID), (const char *) FullList[i]->id); + MissingTitles.push_back(std::string(gameID)); + } + } + + if(!removeUnused) + return; + + for(u32 n = 0; n < TitleList.size(); ++n) + { + if(!UsedCachedList[n]) + { + TitleList.erase(TitleList.begin()+n); + n--; + } + } +} + +void CGameTitles::LoadTitlesFromGameTDB(const char * path, bool removeUnused) +{ + if(!path || !Settings.titlesOverride) + return; + + std::string Filepath = path; + if(path[strlen(path)-1] != '/') + Filepath += '/'; + + Filepath += "wiitdb.xml"; + + //! Read game list + gameList.LoadUnfiltered(); + + //! Removed unused cache titles and get the still missing ones + std::vector MissingTitles; + GetMissingTitles(MissingTitles, removeUnused); + + if(MissingTitles.size() == 0) + return; + + std::string Title; + + GameTDB XML_DB(Filepath.c_str()); + XML_DB.SetLanguageCode(Settings.db_language); + int Rating; + std::string RatValTxt; + + for(u32 i = 0; i < MissingTitles.size(); ++i) + { + if(!XML_DB.GetTitle(MissingTitles[i].c_str(), Title)) + continue; + + this->SetGameTitle(MissingTitles[i].c_str(), Title.c_str()); + //! Title is loaded from WiiTDB, remember that it's good + TitleList[TitleList.size()-1].FromWiiTDB = 1; + + Rating = XML_DB.GetRating(MissingTitles[i].c_str()); + if(Rating < 0) + continue; + + if(!XML_DB.GetRatingValue(MissingTitles[i].c_str(), RatValTxt)) + continue; + + TitleList[TitleList.size()-1].ParentalRating = GameTDB::ConvertRating(RatValTxt.c_str(), GameTDB::RatingToString(Rating), "PEGI"); + int ret = XML_DB.GetPlayers(MissingTitles[i].c_str()); + if(ret > 0) + TitleList[TitleList.size()-1].PlayersCount = ret; + } +} diff --git a/source/settings/GameTitles.h b/source/settings/GameTitles.h new file mode 100644 index 0000000..373f6a4 --- /dev/null +++ b/source/settings/GameTitles.h @@ -0,0 +1,55 @@ +#ifndef GAMETDB_TITLES_H_ +#define GAMETDB_TITLES_H_ + +#include +#include +#include +#include "usbloader/disc.h" + +typedef struct _GameTitle +{ + char GameID[7]; + std::string Title; + int ParentalRating; + int PlayersCount; + char FromWiiTDB; + +} GameTitle; + +class CGameTitles +{ + public: + //! Set a game title from GameTDB + void SetGameTitle(const char * id, const char * title); + //! Overload + void SetGameTitle(const u8 * id, const char * title) { SetGameTitle((const char *) id, title); }; + + //! Get a game title + const char * GetTitle(const char * id) const; + //! Overload + const char * GetTitle(const u8 * id) const { return GetTitle((const char *) id); }; + //! Overload + const char * GetTitle(const struct discHdr *header) const; + + //! Get game parental rating + int GetParentalRating(const char * id) const; + //! Get possible number of players for this game + int GetPlayersCount(const char * id) const; + //! Load Game Titles from GameTDB + void LoadTitlesFromGameTDB(const char * path, bool removeUnused = true); + //! Set default game titles + void SetDefault(); + //! Free memory and remove all titles - Same as SetDefault() + void Clear() { SetDefault(); } + //! Cache titles functions + u32 ReadCachedTitles(const char * path); + void WriteCachedTitles(const char * path); + protected: + void GetMissingTitles(std::vector &MissingTitles, bool removeUnused); + + std::vector TitleList; +}; + +extern CGameTitles GameTitles; + +#endif diff --git a/source/settings/SettingsEnums.h b/source/settings/SettingsEnums.h new file mode 100644 index 0000000..4909d92 --- /dev/null +++ b/source/settings/SettingsEnums.h @@ -0,0 +1,368 @@ +#ifndef SETTINGS_ENUMS_H_ +#define SETTINGS_ENUMS_H_ + +#include "libs/libwbfs/wiidisc.h" + +enum +{ + INHERIT = -1, + AUTO = 2 +}; + +enum +{ + TYPE_GAME_WII_IMG = 0x00, + TYPE_GAME_WII_DISC = 0x01, + TYPE_GAME_GC_IMG = 0x02, + TYPE_GAME_GC_DISC = 0x03, + TYPE_GAME_GC_EXTRACTED = 0x04, + TYPE_GAME_NANDCHAN = 0x05, + TYPE_GAME_EMUNANDCHAN = 0x06 +}; + +enum +{ + MODE_NONE = 0x00, + MODE_WIIGAMES = 0x01, + MODE_NANDCHANNELS = 0x02, + MODE_EMUCHANNELS = 0x04, + MODE_GCGAMES = 0x08, + MODE_ALL = 0xFF +}; + +enum +{ + EMUNAND_OFF, + EMUNAND_PARTIAL, + EMUNAND_FULL, + EMUNAND_NEEK, + EMUNAND_MAX +}; + +enum +{ + JAPANESE, + ENGLISH, + GERMAN, + FRENCH, + SPANISH, + ITALIAN, + DUTCH, + S_CHINESE, + T_CHINESE, + KOREAN, + CONSOLE_DEFAULT, + MAX_LANGUAGE +}; + +enum +{ + GC_ENGLISH, + GC_GERMAN, + GC_FRENCH, + GC_SPANISH, + GC_ITALIAN, + GC_DUTCH, + GC_LANG_CONSOLE_DEFAULT, + GC_MAX_LANGUAGE, +}; + +enum +{ + VIDEO_MODE_SYSDEFAULT, + VIDEO_MODE_DISCDEFAULT, + VIDEO_MODE_PAL50, + VIDEO_MODE_PAL60, + VIDEO_MODE_NTSC, + VIDEO_MODE_PATCH, + VIDEO_MODE_PAL480P, + VIDEO_MODE_NTSC480P, + VIDEO_MODE_MAX +}; + +enum +{ + VIDEO_PATCH_DOL_OFF, + VIDEO_PATCH_DOL_REGION, + VIDEO_PATCH_DOL_ON, + VIDEO_PATCH_DOL_ALL, + VIDEO_PATCH_DOL_MAX, +}; + +enum +{ + ASPECT_FORCE_4_3, + ASPECT_FORCE_16_9, + ASPECT_SYSTEM_DEFAULT, + ASPECT_MAX +}; + +enum +{ + GAMEWINDOW_BANNER, + GAMEWINDOW_DISC, + GAMEWINDOW_BOTH, + GAMEWINDOW_MAX +}; + +enum +{ + OFF, + ON, + MAX_ON_OFF +}; + +enum +{ + CLOCK_HR12 = 1, // use OFF for clock off + CLOCK_HR24, + CLOCK_MAX +}; + + +enum +{ + WIILIGHT_OFF, + WIILIGHT_ON, + WIILIGHT_INSTALL, + WIILIGHT_MAX + +}; + +enum +{ + GAMEINFO_ID, + GAMEINFO_REGION, + GAMEINFO_BOTH, + GAMEINFO_NONE, + GAMEINFO_MAX +}; + +enum +{ + SCREENSAVER_3_MIN = 1, + SCREENSAVER_5_MIN, + SCREENSAVER_10_MIN, + SCREENSAVER_20_MIN, + SCREENSAVER_30_MIN, + SCREENSAVER_60_MIN, + SCREENSAVER_MAX +}; + +enum +{ + XFLIP_NO, + XFLIP_YES, + XFLIP_SYSMENU, + XFLIP_WTF, + XFLIP_DISK3D, + XFLIP_MAX +}; + +enum +{ + //! Sorting should be used as AND to allow favorite ABC/RANK + SORT_ABC = 0x01, + SORT_PLAYCOUNT = 0x02, + SORT_RANKING = 0x04, + SORT_FAVORITE = 0x08, + SORT_PLAYERS = 0x10 +}; +enum +{ + KEYBOARD_QWERTY, + KEYBOARD_DVORAK, + KEYBOARD_QWERTZ, + KEYBOARD_AZERTY, + KEYBOARD_QWERTY2, + KEYBOARD_MAX +}; + +enum +{ + INSTALL_TO_NO_DIR, + INSTALL_TO_GAMEID_NAME, + INSTALL_TO_NAME_GAMEID, + INSTALL_TO_MAX +}; + +enum +{ + GAMESPLIT_NONE, + GAMESPLIT_2GB, + GAMESPLIT_4GB, + GAMESPLIT_MAX +}; + +enum +{ + LIST_MODE, + GRID_MODE, + CAROUSEL_MODE, + BANNERGRID_MODE +}; + +enum +{ + DISCARTS_ORIGINALS_CUSTOMS, + DISCARTS_CUSTOMS_ORIGINALS, + DISCARTS_ORIGINALS, + DISCARTS_CUSTOMS, + DISCARTS_MAX_CHOICE +}; + +enum +{ + BANNER_FAVICON_OFF, + BANNER_FAVICON_CIRC, + BANNER_FAVICON_SIN, + BANNER_FAVICON_MULTI_LINE, + BANNER_FAVICON_SINGLE_LINEA, + BANNER_FAVICON_SINGLE_LINEB, + BANNER_FAVICON_MAX_CHOICE +}; + +enum +{ + COVERSFULL_HQ, + COVERSFULL_LQ, + COVERSFULL_HQ_LQ, + COVERSFULL_LQ_HQ, + COVERSFULL_MAX_CHOICE +}; + +enum +{ + PARENTAL_LVL_EVERYONE, + PARENTAL_LVL_CHILD, + PARENTAL_LVL_TEEN, + PARENTAL_LVL_MATURE, + PARENTAL_LVL_ADULT +}; + +enum +{ + BLOCK_NONE = 0x00, + BLOCK_GLOBAL_SETTINGS = 0x01, + BLOCK_GUI_SETTINGS = 0x02, + BLOCK_LOADER_SETTINGS = 0x04, + BLOCK_PARENTAL_SETTINGS = 0x08, + BLOCK_SOUND_SETTINGS = 0x10, + BLOCK_CUSTOMPATH_SETTINGS = 0x20, + BLOCK_UPDATES = 0x40, + BLOCK_RESET_SETTINGS = 0x80, + BLOCK_THEME_DOWNLOADER = 0x0100, + BLOCK_THEME_MENU = 0x0200, + BLOCK_GAME_SETTINGS = 0x0400, + BLOCK_HBC_MENU = 0x0800, + BLOCK_TITLE_LAUNCHER_MENU = 0x1000, + BLOCK_COVER_DOWNLOADS = 0x2000, + BLOCK_GAME_INSTALL = 0x4000, + BLOCK_GAMEID_CHANGE = 0x8000, + BLOCK_CATEGORIES_MOD = 0x010000, + BLOCK_FEATURE_SETTINGS = 0x020000, + BLOCK_HARD_DRIVE_SETTINGS = 0x040000, + BLOCK_CATEGORIES_MENU = 0x080000, + BLOCK_SD_RELOAD_BUTTON = 0x100000, + BLOCK_PRIILOADER_OVERRIDE = 0x200000, + BLOCK_LOADER_MODE_BUTTON = 0x400000, + BLOCK_BANNER_SETTINGS = 0x800000, + BLOCK_LOADER_LAYOUT_BUTTON = 0x1000000, + BLOCK_ALL = 0xFFFFFFFF +}; + +enum +{ + ALT_DOL_OFF, + ALT_DOL_FROM_GAME, + ALT_DOL_FROM_SD_USB, + ALT_DOL_ON_LAUNCH, + ALT_DOL_DEFAULT, + ALT_DOL_MAX_CHOICE +}; + +enum +{ + HOME_MENU_SYSTEM, + HOME_MENU_FULL, + HOME_MENU_DEFAULT, + HOME_MENU_MAX_CHOICE +}; + +enum +{ + SEARCH_BEGINNING, + SEARCH_CONTENT, + SEARCH_MAX_CHOICE +}; + +enum +{ + BANNER_START_ON_ZOOM, + BANNER_START_AFTER_ZOOM +}; + +enum +{ + GC_MODE_MIOS, + GC_MODE_DEVOLUTION, + GC_MODE_NINTENDONT, + CG_MODE_MAX_CHOICE + +}; + +enum +{ + GC_SOURCE_MAIN, + GC_SOURCE_SD, + GC_SOURCE_AUTO, + GC_SOURCE_MAIN_SD, + GC_SOURCE_SD_MAIN, + CG_SOURCE_MAX_CHOICE + +}; + +enum +{ + DEVO_MC_OFF, + DEVO_MC_ON, + DEVO_MC_INDIVIDUAL, + // DEVO_MC_NAND, + DEVO_MC_MAX_CHOICE + +}; + +enum +{ + NIN_MC_OFF, + NIN_MC_ON, + NIN_MC_MULTI, + NIN_MC_MAX_CHOICE + +}; + +enum +{ + DML_VIDEO_AUTO, + DML_VIDEO_FORCE_SYSDEFAULT, // same modes as Wii, +1 + DML_VIDEO_FORCE_DISCDEFAULT, + DML_VIDEO_FORCE_PAL50, + DML_VIDEO_FORCE_PAL60, + DML_VIDEO_FORCE_NTSC, + DML_VIDEO_FORCE_PATCH, // unused + DML_VIDEO_FORCE_PAL480P, + DML_VIDEO_FORCE_NTSC480P, + DML_VIDEO_NONE, + DML_VIDEO_MAX_CHOICE +}; + +enum +{ + PRIVSERV_OFF, + PRIVSERV_NOSSL, + PRIVSERV_WIIMMFI, + PRIVSERV_MAX_CHOICE + +}; + +#endif diff --git a/source/settings/SettingsPrompts.cpp b/source/settings/SettingsPrompts.cpp new file mode 100644 index 0000000..4509812 --- /dev/null +++ b/source/settings/SettingsPrompts.cpp @@ -0,0 +1,323 @@ +#include +#include +#include + +#include "language/gettext.h" +#include "language/UpdateLanguage.h" +#include "prompts/PromptWindows.h" +#include "prompts/ProgressWindow.h" +#include "GUI/gui.h" +#include "GUI/gui_optionbrowser.h" +#include "settings/CSettings.h" +#include "settings/GameTitles.h" +#include "themes/CTheme.h" +#include "network/URL_List.h" +#include "FileOperations/fileops.h" +#include "FileOperations/DirList.h" +#include "main.h" +#include "prompts/filebrowser.h" +#include "sys.h" +#include "menu/menus.h" + +/*** Extern variables ***/ +extern u8 shutdown; +extern u8 reset; + + +/**************************************************************************** + * MenuOGG + ***************************************************************************/ +bool MenuBackgroundMusic() +{ + bool ret = false; + int result = -1; + char entered[1024]; + strlcpy(entered, Settings.ogg_path, sizeof(entered)); + + // Check the OGG path. + if (entered[0] == 0 ) + { + // OGG path is empty. + strlcpy(entered, Settings.BootDevice, sizeof(entered)); + } + else + { + char * pathptr = strrchr( entered, '/' ); + if ( pathptr ) + { + pathptr++; + int choice = WindowPrompt( tr( "Playing Music:" ), pathptr, tr( "Play Previous" ), tr( "Play Next" ), tr( "Change Play Path" ), tr( "Cancel" ) ); + if ( choice == 1 ) + { + return bgMusic->PlayPrevious(); + } + else if ( choice == 2 ) + { + return bgMusic->PlayNext(); + } + else if ( choice == 3 ) + { + pathptr[0] = 0; + } + else + return true; + } + else + strlcpy(entered, Settings.BootDevice, sizeof(entered)); + } + + result = BrowseDevice( entered, sizeof( entered ), FB_DEFAULT ); + + if ( result ) + { + if ( !bgMusic->Load( entered ) ) + { + WindowPrompt( tr( "Not supported format!" ), tr( "Loading standard music." ), tr( "OK" ) ); + } + else + ret = true; + bgMusic->Play(); + bgMusic->SetVolume( Settings.volume ); + } + + return ret; +} + +/**************************************************************************** + * MenuLanguageSelect + ***************************************************************************/ +int MenuLanguageSelect() +{ + int cnt = 0; + int ret = 0, choice = 0; + int returnhere = 0; + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData settingsbg(Resources::GetFile("settings_background.png"), Resources::GetFileSize("settings_background.png")); + + GuiTrigger trigA; + trigA.SetSimpleTrigger( -1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A ); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger( -1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B ); + + char fullpath[150]; + DirList Dir(Settings.languagefiles_path, ".lang"); + + // Check if a language is specified. + if (Settings.language_path[0] == 0) + strlcpy(fullpath, tr( "Default" ), sizeof(fullpath)); + else + strlcpy(fullpath, Settings.languagefiles_path, sizeof(fullpath)); + + GuiText titleTxt( fullpath, 24, ( GXColor ) {0, 0, 0, 255} ); + titleTxt.SetAlignment( ALIGN_CENTER, ALIGN_MIDDLE ); + titleTxt.SetPosition( 0, 0 ); + GuiButton pathBtn( 300, 50 ); + pathBtn.SetAlignment( ALIGN_CENTER, ALIGN_TOP ); + pathBtn.SetPosition( 0, 28 ); + pathBtn.SetLabel( &titleTxt ); + pathBtn.SetSoundOver( btnSoundOver ); + pathBtn.SetSoundClick( btnSoundClick2 ); + pathBtn.SetTrigger( &trigA ); + pathBtn.SetEffectGrow(); + + GuiImage oggmenubackground( &settingsbg ); + oggmenubackground.SetAlignment( ALIGN_LEFT, ALIGN_TOP ); + oggmenubackground.SetPosition( 0, 0 ); + + GuiText backBtnTxt( tr( "Back" ) , 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + backBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 ); + GuiImage backBtnImg( &btnOutline ); + if ( Settings.wsprompt == ON ) + { + backBtnTxt.SetWidescreen( Settings.widescreen ); + backBtnImg.SetWidescreen( Settings.widescreen ); + } + GuiButton backBtn( btnOutline.GetWidth(), btnOutline.GetHeight() ); + backBtn.SetAlignment( ALIGN_CENTER, ALIGN_TOP ); + backBtn.SetPosition( -190, 400 ); + backBtn.SetLabel( &backBtnTxt ); + backBtn.SetImage( &backBtnImg ); + backBtn.SetSoundOver( btnSoundOver ); + backBtn.SetSoundClick( btnSoundClick2 ); + backBtn.SetTrigger( &trigA ); + backBtn.SetTrigger( &trigB ); + backBtn.SetEffectGrow(); + + GuiText defaultBtnTxt( tr( "Default" ) , 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + defaultBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 ); + GuiImage defaultBtnImg( &btnOutline ); + if ( Settings.wsprompt == ON ) + { + defaultBtnTxt.SetWidescreen( Settings.widescreen ); + defaultBtnImg.SetWidescreen( Settings.widescreen ); + } + GuiButton defaultBtn( btnOutline.GetWidth(), btnOutline.GetHeight() ); + defaultBtn.SetAlignment( ALIGN_CENTER, ALIGN_TOP ); + defaultBtn.SetPosition( 190, 400 ); + defaultBtn.SetLabel( &defaultBtnTxt ); + defaultBtn.SetImage( &defaultBtnImg ); + defaultBtn.SetSoundOver( btnSoundOver ); + defaultBtn.SetSoundClick( btnSoundClick2 ); + defaultBtn.SetTrigger( &trigA ); + defaultBtn.SetEffectGrow(); + + GuiText updateBtnTxt( tr( "Update Files" ) , 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + updateBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 ); + GuiImage updateBtnImg( &btnOutline ); + if ( Settings.wsprompt == ON ) + { + updateBtnTxt.SetWidescreen( Settings.widescreen ); + updateBtnImg.SetWidescreen( Settings.widescreen ); + } + GuiButton updateBtn( btnOutline.GetWidth(), btnOutline.GetHeight() ); + updateBtn.SetAlignment( ALIGN_CENTER, ALIGN_TOP ); + updateBtn.SetPosition( 0, 400 ); + updateBtn.SetLabel( &updateBtnTxt ); + updateBtn.SetImage( &updateBtnImg ); + updateBtn.SetSoundOver( btnSoundOver ); + updateBtn.SetSoundClick( btnSoundClick2 ); + updateBtn.SetTrigger( &trigA ); + updateBtn.SetEffectGrow(); + + OptionList options2; + + for ( cnt = 0; cnt < Dir.GetFilecount(); cnt++ ) + { + if(!Dir.GetFilename( cnt )) + continue; + + char filename[64]; + strlcpy( filename, Dir.GetFilename( cnt ), sizeof( filename ) ); + char *dot = strchr( filename, '.' ); + if ( dot ) *dot = '\0'; + options2.SetName( cnt, "%s", filename ); + options2.SetValue( cnt, NULL ); + + } + + GuiOptionBrowser optionBrowser4( 396, 280, &options2, "bg_options_settings.png"); + optionBrowser4.SetPosition( 0, 90 ); + optionBrowser4.SetAlignment( ALIGN_CENTER, ALIGN_TOP ); + + HaltGui(); + GuiWindow w( screenwidth, screenheight ); + w.Append( &oggmenubackground ); + w.Append( &pathBtn ); + w.Append( &backBtn ); + w.Append( &defaultBtn ); + w.Append( &updateBtn ); + w.Append( &optionBrowser4 ); + mainWindow->Append( &w ); + + w.SetEffect( EFFECT_FADE, 20 ); + ResumeGui(); + + while ( w.GetEffect() > 0 ) usleep( 50 ); + + while ( !returnhere ) + { + usleep(100); + + if ( shutdown == 1 ) + Sys_Shutdown(); + else if ( reset == 1 ) + Sys_Reboot(); + + else if ( backBtn.GetState() == STATE_CLICKED ) + { + backBtn.ResetState(); + break; + } + + else if ( defaultBtn.GetState() == STATE_CLICKED ) + { + choice = WindowPrompt( tr( "Loading standard language." ), 0, tr( "OK" ), tr( "Cancel" ) ); + if ( choice == 1 ) + { + Settings.LoadLanguage(NULL, CONSOLE_DEFAULT); + Settings.Save(); + returnhere = 2; + } + defaultBtn.ResetState(); + //optionBrowser4.SetFocus(1); // commented out to prevent crash + } + + else if ( updateBtn.GetState() == STATE_CLICKED ) + { + choice = WindowPrompt( tr( "Update all Language Files" ), tr( "Do you wish to update/download all language files?" ), tr( "OK" ), tr( "Cancel" ) ); + if ( choice == 1 ) + { + if (IsNetworkInit() || NetworkInitPrompt()) + { + if(DownloadAllLanguageFiles() > 0) + WindowPrompt(tr("Update successfull"), 0, tr("OK")); + returnhere = 1; + break; + } + } + updateBtn.ResetState(); + //optionBrowser4.SetFocus(1); // commented out to prevent crash + } + + else if ( pathBtn.GetState() == STATE_CLICKED ) + { + w.Remove( &optionBrowser4 ); + w.Remove( &backBtn ); + w.Remove( &pathBtn ); + w.Remove( &defaultBtn ); + char entered[43] = ""; + strlcpy( entered, Settings.languagefiles_path, sizeof( entered ) ); + int result = OnScreenKeyboard( entered, 43, 0 ); + w.Append( &optionBrowser4 ); + w.Append( &pathBtn ); + w.Append( &backBtn ); + w.Append( &defaultBtn ); + if (result == 1) + { + if (entered[strlen(entered)-1] != '/') + strcat (entered, "/"); + snprintf(Settings.languagefiles_path, sizeof(Settings.languagefiles_path), entered); + WindowPrompt(tr("Languagepath changed."), 0, tr("OK")); + } + pathBtn.ResetState(); + } + + ret = optionBrowser4.GetClickedOption(); + + if (ret >= 0) + { + choice = WindowPrompt( tr( "Do you want to change language?" ), 0, tr( "Yes" ), tr( "Cancel" ) ); + if (choice == 1) + { + char newLangPath[150]; + snprintf(Settings.languagefiles_path, sizeof( Settings.languagefiles_path ), "%s", Dir.GetFilepath(ret)); + char * ptr = strrchr(Settings.languagefiles_path, '/'); + if(ptr) ptr[1] = 0; + snprintf(newLangPath, sizeof(newLangPath), "%s", Dir.GetFilepath(ret)); + if (!CheckFile(newLangPath)) + { + WindowPrompt(tr("File not found."), tr("Loading standard language."), tr("OK")); + Settings.LoadLanguage(NULL, CONSOLE_DEFAULT); + } + else + { + Settings.LoadLanguage(newLangPath); + } + Settings.Save(); + returnhere = 2; + break; + } + } + + } + + w.SetEffect( EFFECT_FADE, -20 ); + while ( w.GetEffect() > 0 ) usleep( 50 ); + + HaltGui(); + mainWindow->Remove( &w ); + ResumeGui(); + + return returnhere; +} diff --git a/source/settings/SettingsPrompts.h b/source/settings/SettingsPrompts.h new file mode 100644 index 0000000..d16a12a --- /dev/null +++ b/source/settings/SettingsPrompts.h @@ -0,0 +1,14 @@ +/**************************************************************************** + * SettingsPrompts + * USB Loader GX 2009 + * + * SettingsPrompts.h + ***************************************************************************/ + +#ifndef _SETTINGSPROMPTS_H_ +#define _SETTINGSPROMPTS_H_ + +bool MenuBackgroundMusic(); +int MenuLanguageSelect(); + +#endif diff --git a/source/settings/menus/BannerSettingsMenu.cpp b/source/settings/menus/BannerSettingsMenu.cpp new file mode 100644 index 0000000..27d30ea --- /dev/null +++ b/source/settings/menus/BannerSettingsMenu.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 "BannerSettingsMenu.hpp" +#include "settings/CSettings.h" +#include "settings/SettingsPrompts.h" +#include "prompts/PromptWindows.h" +#include "language/gettext.h" + +static const char * AnimStartText[] = +{ + trNOOP( "During zoom" ), + trNOOP( "After zoom" ), +}; + +static const char * OnOffText[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ) +}; + +BannerSettingsMenu::BannerSettingsMenu() + : SettingsMenu(tr("Banner Animation Settings"), &GuiOptions, MENU_NONE) +{ + int Idx = 0; + Options->SetName(Idx++, "%s", tr( "Cache BNR Files" )); + Options->SetName(Idx++, "%s", tr( "Animation Start" )); + Options->SetName(Idx++, "%s", tr( "Zoom Duration (Speed)" )); + Options->SetName(Idx++, "%s", tr( "Grid Scroll Speed" )); + Options->SetName(Idx++, "%s", tr( "Frame Projection X-Offset" )); + Options->SetName(Idx++, "%s", tr( "Frame Projection Y-Offset" )); + Options->SetName(Idx++, "%s", tr( "Frame Projection Width" )); + Options->SetName(Idx++, "%s", tr( "Frame Projection Height" )); + Options->SetName(Idx++, "%s", tr( "GC Banner Scale" )); + + SetOptionValues(); +} + +void BannerSettingsMenu::SetOptionValues() +{ + int Idx = 0; + + //! Settings: Cache BNR Files + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.CacheBNRFiles])); + + //! Settings: Animation Start + Options->SetValue(Idx++, "%s", tr(AnimStartText[Settings.BannerAnimStart])); + + //! Settings: Zoom Duration (Speed) + Options->SetValue(Idx++, "%i %s", Settings.BannerZoomDuration, tr("Frames")); + + //! Settings: Grid Scroll Speed + Options->SetValue(Idx++, "%g %s/%s", Settings.BannerGridSpeed, tr("Pixels"), tr("Frame")); + + //! Settings: Frame Projection X-Offset + Options->SetValue(Idx++, "%g %s", Settings.BannerProjectionOffsetX, tr("Pixels")); + + //! Settings: Frame Projection Y-Offset + Options->SetValue(Idx++, "%g %s", Settings.BannerProjectionOffsetY, tr("Pixels")); + + //! Settings: Frame Projection Width + Options->SetValue(Idx++, "%g %s", Settings.BannerProjectionWidth, tr("Pixels")); + + //! Settings: Frame Projection Height + Options->SetValue(Idx++, "%g %s", Settings.BannerProjectionHeight, tr("Pixels")); + + //! Settings: GC Banner Scale + Options->SetValue(Idx++, "%g", Settings.GCBannerScale); +} + +int BannerSettingsMenu::GetMenuInternal() +{ + int ret = optionBrowser->GetClickedOption(); + + if (ret < 0) + return MENU_NONE; + + int Idx = -1; + + //! Settings: Cache BNR Files + if (ret == ++Idx) + { + if (++Settings.CacheBNRFiles >= MAX_ON_OFF) Settings.CacheBNRFiles = 0; + } + + //! Settings: Animation Start + else if (ret == ++Idx) + { + if (++Settings.BannerAnimStart > 1) Settings.BannerAnimStart = 0; + } + + //! Settings: Zoom Duration (Speed) + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%i", Settings.BannerZoomDuration); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.BannerZoomDuration = atoi(entrie); + } + + //! Settings: Grid Scroll Speed + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%g", Settings.BannerGridSpeed); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.BannerGridSpeed = atof(entrie); + } + + //! Settings: Frame Projection X-Offset + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%g", Settings.BannerProjectionOffsetX); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.BannerProjectionOffsetX = atof(entrie); + } + + //! Settings: Frame Projection Y-Offset + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%g", Settings.BannerProjectionOffsetY); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.BannerProjectionOffsetY = atof(entrie); + } + + //! Settings: Frame Projection Width + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%g", Settings.BannerProjectionWidth); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.BannerProjectionWidth = atof(entrie); + } + + //! Settings: Frame Projection Height + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%g", Settings.BannerProjectionHeight); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.BannerProjectionHeight = atof(entrie); + } + + //! Settings: GC Banner Scale + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%g", Settings.GCBannerScale); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.GCBannerScale = atof(entrie); + } + + SetOptionValues(); + + return MENU_NONE; +} diff --git a/source/settings/menus/BannerSettingsMenu.hpp b/source/settings/menus/BannerSettingsMenu.hpp new file mode 100644 index 0000000..ddb0bd4 --- /dev/null +++ b/source/settings/menus/BannerSettingsMenu.hpp @@ -0,0 +1,34 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 BANNERSETTINGS_MENU_HPP_ +#define BANNERSETTINGS_MENU_HPP_ + +#include "SettingsMenu.hpp" + +class BannerSettingsMenu : public SettingsMenu +{ + public: + BannerSettingsMenu(); + protected: + void SetOptionValues(); + int GetMenuInternal(); + + OptionList GuiOptions; +}; + + +#endif diff --git a/source/settings/menus/CustomPathsSM.cpp b/source/settings/menus/CustomPathsSM.cpp new file mode 100644 index 0000000..cd76f99 --- /dev/null +++ b/source/settings/menus/CustomPathsSM.cpp @@ -0,0 +1,423 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "Channels/channels.h" +#include "Controls/DeviceHandler.hpp" +#include "GameCube/GCGames.h" +#include "CustomPathsSM.hpp" +#include "settings/SettingsPrompts.h" +#include "settings/CSettings.h" +#include "settings/SettingsEnums.h" +#include "settings/GameTitles.h" +#include "prompts/PromptWindows.h" +#include "prompts/ProgressWindow.h" +#include "language/gettext.h" +#include "prompts/filebrowser.h" +#include "themes/CTheme.h" +#include "FileOperations/fileops.h" +#include "gecko.h" + +CustomPathsSM::CustomPathsSM() + : SettingsMenu(tr("Custom Paths"), &GuiOptions, MENU_NONE) +{ + int Idx = 0; + Options->SetName(Idx++, tr("3D Cover Path")); + Options->SetName(Idx++, tr("2D Cover Path")); + Options->SetName(Idx++, tr("Full Cover Path")); + Options->SetName(Idx++, tr("Disc Artwork Path")); + Options->SetName(Idx++, tr("Theme Path")); + Options->SetName(Idx++, tr("Titles Path")); + Options->SetName(Idx++, tr("Update Path")); + Options->SetName(Idx++, tr("GCT Cheatcodes Path")); + Options->SetName(Idx++, tr("TXT Cheatcodes Path")); + Options->SetName(Idx++, tr("DOL Path")); + Options->SetName(Idx++, tr("Homebrew Apps Path")); + Options->SetName(Idx++, tr("BCA Codes Path")); + Options->SetName(Idx++, tr("WIP Patches Path")); + Options->SetName(Idx++, tr("Languagefiles Path")); + Options->SetName(Idx++, tr("WDM Files Path")); + Options->SetName(Idx++, tr("Wiinnertag Path")); + Options->SetName(Idx++, tr("Nand Emu Path")); + Options->SetName(Idx++, tr("Nand Emu Channel Path")); + Options->SetName(Idx++, tr("Main GameCube Path")); + Options->SetName(Idx++, tr("SD GameCube Path")); + Options->SetName(Idx++, tr("Devolution Loader Path")); + Options->SetName(Idx++, tr("Nintendont Loader Path")); + Options->SetName(Idx++, tr("Cache BNR Files Path")); + + SetOptionValues(); +} + +void CustomPathsSM::SetOptionValues() +{ + int Idx = 0; + + //! Settings: 3D Cover Path + Options->SetValue(Idx++, Settings.covers_path); + + //! Settings: 2D Cover Path + Options->SetValue(Idx++, Settings.covers2d_path); + + //! Settings: Full Cover Path + Options->SetValue(Idx++, Settings.coversFull_path); + + //! Settings: Disc Artwork Path + Options->SetValue(Idx++, Settings.disc_path); + + //! Settings: Theme Path + Options->SetValue(Idx++, Settings.theme_path); + + //! Settings: Titles Path + Options->SetValue(Idx++, Settings.titlestxt_path); + + //! Settings: Update Path + Options->SetValue(Idx++, Settings.update_path); + + //! Settings: GCT Cheatcodes Path + Options->SetValue(Idx++, Settings.Cheatcodespath); + + //! Settings: TXT Cheatcodes Path + Options->SetValue(Idx++, Settings.TxtCheatcodespath); + + //! Settings: DOL Path + Options->SetValue(Idx++, Settings.dolpath); + + //! Settings: Homebrew Apps Path + Options->SetValue(Idx++, Settings.homebrewapps_path); + + //! Settings: BCA Codes Path + Options->SetValue(Idx++, Settings.BcaCodepath); + + //! Settings: WIP Patches Path + Options->SetValue(Idx++, Settings.WipCodepath); + + //! Settings: Languagefiles Path + Options->SetValue(Idx++, Settings.languagefiles_path); + + //! Settings: WDM Files Path + Options->SetValue(Idx++, Settings.WDMpath); + + //! Settings: Wiinnertag Path + Options->SetValue(Idx++, Settings.WiinnertagPath); + + //! Settings: Nand Emu Path + Options->SetValue(Idx++, Settings.NandEmuPath); + + //! Settings: Nand Emu Channel Path + Options->SetValue(Idx++, Settings.NandEmuChanPath); + + //! Settings: GameCube Games Path + Options->SetValue(Idx++, Settings.GameCubePath); + + //! Settings: SD GameCube Games Path + Options->SetValue(Idx++, Settings.GameCubeSDPath); + + //! Settings: GameCube Devolution loader.bin Path + Options->SetValue(Idx++, Settings.DEVOLoaderPath); + + //! Settings: GameCube Nintendont boot.dol Path + Options->SetValue(Idx++, Settings.NINLoaderPath); + + //! Settings: Cache BNR Files Path + Options->SetValue(Idx++, Settings.BNRCachePath); +} + +int CustomPathsSM::GetMenuInternal() +{ + int ret = optionBrowser->GetClickedOption(); + + if (ret < 0) + return MENU_NONE; + + int Idx = -1; + + //! Settings: 3D Cover Path + if (ret == ++Idx) + { + titleTxt->SetText(tr( "3D Cover Path" )); + ChangePath(Settings.covers_path, sizeof(Settings.covers_path)); + } + + //! Settings: 2D Cover Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "2D Cover Path" )); + ChangePath(Settings.covers2d_path, sizeof(Settings.covers2d_path)); + } + + //! Settings: Full Cover Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Full Cover Path" )); + ChangePath(Settings.coversFull_path, sizeof(Settings.coversFull_path)); + } + + //! Settings: Disc Artwork Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Disc Artwork Path" )); + ChangePath(Settings.disc_path, sizeof(Settings.disc_path)); + } + + //! Settings: Theme Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Theme Path" )); + ChangePath(Settings.theme_path, sizeof(Settings.theme_path)); + } + + //! Settings: Titles Path + else if (ret == ++Idx) + { + char oldPath[100]; + strncpy(oldPath, Settings.titlestxt_path, sizeof(Settings.titlestxt_path)); + + titleTxt->SetText(tr("Titles Path")); + if (ChangePath(Settings.titlestxt_path, sizeof(Settings.titlestxt_path))) + { + if(strlen(oldPath) != strlen(Settings.titlestxt_path) || strcmp(oldPath, Settings.titlestxt_path) != 0) + { + if (WindowPrompt(tr("Move File"), tr("Do you want to move the file(s)? Any existing ones will be deleted!"), tr("Yes"), tr("Cancel")) == 1) + { + MoveDbFile(oldPath, Settings.titlestxt_path, "wiitdb.xml"); + MoveDbFile(oldPath, Settings.titlestxt_path, "TitlesCache.bin"); + MoveDbFile(oldPath, Settings.titlestxt_path, "wiitdb_offsets.bin"); + MoveDbFile(oldPath, Settings.titlestxt_path, "GameTimestamps.txt"); + + WindowPrompt(tr("Process finished."), 0, tr("OK")); + } + } + } + } + + //! Settings: Update Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Update Path" )); + ChangePath(Settings.update_path, sizeof(Settings.update_path)); + } + + //! Settings: GCT Cheatcodes Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "GCT Cheatcodes Path" )); + ChangePath(Settings.Cheatcodespath, sizeof(Settings.Cheatcodespath)); + } + + //! Settings: TXT Cheatcodes Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "TXT Cheatcodes Path" )); + ChangePath(Settings.TxtCheatcodespath, sizeof(Settings.TxtCheatcodespath)); + } + + //! Settings: DOL Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "DOL Path" )); + ChangePath(Settings.dolpath, sizeof(Settings.dolpath)); + } + + //! Settings: Homebrew Apps Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Homebrew Apps Path" )); + ChangePath(Settings.homebrewapps_path, sizeof(Settings.homebrewapps_path)); + } + + //! Settings: BCA Codes Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "BCA Codes Path" )); + ChangePath(Settings.BcaCodepath, sizeof(Settings.BcaCodepath)); + } + + //! Settings: WIP Patches Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "WIP Patches Path" )); + ChangePath(Settings.WipCodepath, sizeof(Settings.WipCodepath)); + } + + //! Settings: Languagefiles Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Languagefiles Path" )); + ChangePath(Settings.languagefiles_path, sizeof(Settings.languagefiles_path)); + } + + //! Settings: WDM Files Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "WDM Files Path" )); + ChangePath(Settings.WDMpath, sizeof(Settings.WDMpath)); + } + + //! Settings: Wiinnertag Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Wiinnertag Path" )); + ChangePath(Settings.WiinnertagPath, sizeof(Settings.WiinnertagPath)); + } + + //! Settings: Nand Emu Path + else if (ret == ++Idx) + { + char oldPath[sizeof(Settings.NandEmuPath)]; + snprintf(oldPath, sizeof(oldPath), Settings.NandEmuPath); + + titleTxt->SetText(tr( "Nand Emu Path" )); + ChangePath(Settings.NandEmuPath, sizeof(Settings.NandEmuPath)); + if(strncasecmp(DeviceHandler::PathToFSName(Settings.NandEmuPath), "FAT", 3) != 0) + { + snprintf(Settings.NandEmuPath, sizeof(Settings.NandEmuPath), oldPath); + WindowPrompt(tr("Error:"), tr("Nand Emulation only works on FAT/FAT32 partitions!"), tr("OK")); + } + } + + //! Settings: Nand Emu Channel Path + else if (ret == ++Idx) + { + char oldPath[sizeof(Settings.NandEmuChanPath)]; + snprintf(oldPath, sizeof(oldPath), Settings.NandEmuChanPath); + + titleTxt->SetText(tr( "Nand Emu Channel Path" )); + int result = ChangePath(Settings.NandEmuChanPath, sizeof(Settings.NandEmuChanPath)); + if(strncasecmp(DeviceHandler::PathToFSName(Settings.NandEmuChanPath), "FAT", 3) != 0) + { + snprintf(Settings.NandEmuChanPath, sizeof(Settings.NandEmuChanPath), oldPath); + WindowPrompt(tr("Error:"), tr("Nand Emulation only works on FAT/FAT32 partitions!"), tr("OK")); + } + else if(result == 1) + { + Channels::Instance()->GetEmuChannelList(); + GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path, false); + } + } + + //! Settings: GameCube Games Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Main GameCube Games Path" )); + if(ChangePath(Settings.GameCubePath, sizeof(Settings.GameCubePath))) + { + GCGames::Instance()->LoadAllGames(); + } + } + + //! Settings: SD GameCube Games Path + else if (ret == ++Idx) + { + char tmp_path[sizeof(Settings.GameCubeSDPath)]; + snprintf(tmp_path, sizeof(tmp_path), "%s", Settings.GameCubeSDPath); + + titleTxt->SetText(tr( "SD GameCube Games Path" )); + if(ChangePath(tmp_path, sizeof(tmp_path))) + { + if(strncmp(tmp_path, "sd", 2) != 0) + { + WindowPrompt(tr("Error:"), tr("This path must be on SD!"), tr("OK")); + } + else + { + snprintf(Settings.GameCubeSDPath, sizeof(Settings.GameCubeSDPath), "%s", tmp_path); + GCGames::Instance()->LoadAllGames(); + } + } + } + + //! Settings: GameCube Devolution loader.bin path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Devolution Loader Path" )); + ChangePath(Settings.DEVOLoaderPath, sizeof(Settings.DEVOLoaderPath)); + } + + //! Settings: GameCube Nintendont boot.dol path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Nintendont Loader Path" )); + ChangePath(Settings.NINLoaderPath, sizeof(Settings.NINLoaderPath)); + } + + //! Settings: Cache BNR Files Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Cache BNR Files Path" )); + ChangePath(Settings.BNRCachePath, sizeof(Settings.BNRCachePath)); + } + + //! Global set back of the titleTxt after a change + titleTxt->SetText(tr( "Custom Paths" )); + SetOptionValues(); + + return MENU_NONE; +} + +int CustomPathsSM::ChangePath(char * SettingsPath, int SizeOfPath) +{ + char entered[300]; + snprintf(entered, sizeof(entered), SettingsPath); + + HaltGui(); + GuiWindow * parent = (GuiWindow *) parentElement; + if(parent) parent->SetState(STATE_DISABLED); + this->SetState(STATE_DEFAULT); + this->Remove(optionBrowser); + ResumeGui(); + + int result = BrowseDevice(entered, sizeof(entered), FB_DEFAULT, noFILES); + + if(parent) parent->SetState(STATE_DEFAULT); + this->Append(optionBrowser); + + if (result == 1) + { + if (entered[strlen(entered)-1] != '/') + strcat(entered, "/"); + + snprintf(SettingsPath, SizeOfPath, entered); + WindowPrompt(tr( "Path Changed" ), 0, tr( "OK" )); + } + + return result; +} + +void CustomPathsSM::MoveDbFile(const char* oldPath, const char* newPath, const char* fileName) +{ + char srcPath[300], destPath[300]; + memset(srcPath, 0, 300); + memset(destPath, 0, 300); + + snprintf(srcPath, sizeof(srcPath), "%s/%s", oldPath, fileName); + snprintf(destPath, sizeof(destPath), "%s/%s", newPath, fileName); + + if (CheckFile(srcPath)) + { + if (CheckFile(destPath)) + RemoveFile(destPath); + + MoveFile(srcPath, destPath); + } +} diff --git a/source/settings/menus/CustomPathsSM.hpp b/source/settings/menus/CustomPathsSM.hpp new file mode 100644 index 0000000..ff77b2a --- /dev/null +++ b/source/settings/menus/CustomPathsSM.hpp @@ -0,0 +1,45 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef CUSTOMPATHS_MENU_HPP_ +#define CUSTOMPATHS_MENU_HPP_ + +#include "SettingsMenu.hpp" + +class CustomPathsSM : public SettingsMenu +{ + public: + CustomPathsSM(); + protected: + void SetOptionValues(); + int GetMenuInternal(); + int ChangePath(char * SettingsPath, int SizeOfPath); + + OptionList GuiOptions; + + private: + void MoveDbFile(const char* oldPath, const char* newPath, const char* fileName); +}; + + +#endif diff --git a/source/settings/menus/FeatureSettingsMenu.cpp b/source/settings/menus/FeatureSettingsMenu.cpp new file mode 100644 index 0000000..1a85e94 --- /dev/null +++ b/source/settings/menus/FeatureSettingsMenu.cpp @@ -0,0 +1,739 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include "FeatureSettingsMenu.hpp" +#include "Channels/channels.h" +#include "settings/CGameCategories.hpp" +#include "settings/GameTitles.h" +#include "settings/CSettings.h" +#include "settings/SettingsPrompts.h" +#include "network/Wiinnertag.h" +#include "network/networkops.h" +#include "FileOperations/fileops.h" +#include "FileOperations/DirList.h" +#include "utils/StringTools.h" +#include "prompts/PromptWindows.h" +#include "prompts/ProgressWindow.h" +#include "prompts/filebrowser.h" +#include "usbloader/GameList.h" +#include "usbloader/neek.hpp" +#include "language/gettext.h" +#include "wad/nandtitle.h" +#include "wad/wad.h" +#include "sys.h" + +static const char * OnOffText[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ) +}; + +static const char * WiilightText[WIILIGHT_MAX] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ), + trNOOP( "Only for Install" ) +}; + +FeatureSettingsMenu::FeatureSettingsMenu() + : SettingsMenu(tr("Features Settings"), &GuiOptions, MENU_NONE) +{ + int Idx = 0; + Options->SetName(Idx++, "%s", tr( "Titles from GameTDB" )); + Options->SetName(Idx++, "%s", tr( "Cache Titles" )); + Options->SetName(Idx++, "%s", tr( "Force Titles from Disc" )); + Options->SetName(Idx++, "%s", tr( "Wiilight" )); + Options->SetName(Idx++, "%s", tr( "Rumble" )); + Options->SetName(Idx++, "%s", tr( "AutoInit Network" )); + Options->SetName(Idx++, "%s", tr( "Messageboard Update" )); + Options->SetName(Idx++, "%s", tr( "Wiinnertag" )); + Options->SetName(Idx++, "%s", tr( "Import Categories" )); + Options->SetName(Idx++, "%s", tr( "Export All Saves to EmuNand" )); + Options->SetName(Idx++, "%s", tr( "Export Miis to EmuNand" )); + Options->SetName(Idx++, "%s", tr( "Export SYSCONF to EmuNand" )); + Options->SetName(Idx++, "%s", tr( "Dump NAND to EmuNand" )); + Options->SetName(Idx++, "%s", tr( "EmuNAND Wad Manager" )); +// Options->SetName(Idx++, "%s", tr( "Update Nintendont" )); + Options->SetName(Idx++, "%s", tr( "WiiU Widescreen" )); + Options->SetName(Idx++, "%s", tr( "Boot Neek System Menu" )); + + OldTitlesOverride = Settings.titlesOverride; + OldCacheTitles = Settings.CacheTitles; + OldForceDiscTitles = Settings.ForceDiscTitles; + + SetOptionValues(); +} + +FeatureSettingsMenu::~FeatureSettingsMenu() +{ + if ( Settings.titlesOverride != OldTitlesOverride + || Settings.CacheTitles != OldCacheTitles + || Settings.ForceDiscTitles != OldForceDiscTitles) + { + if(Settings.ForceDiscTitles) + Settings.titlesOverride = OFF; + + //! Remove cached titles and reload new titles + GameTitles.SetDefault(); + if(Settings.titlesOverride) { + GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path); + } + else + { + //! Don't override titles, in other words read them from disc header or directory names + gameList.ReadGameList(); + gameList.LoadUnfiltered(); + } + } +} + +void FeatureSettingsMenu::SetOptionValues() +{ + int Idx = 0; + + //! Settings: Titles from GameTDB + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.titlesOverride] )); + + //! Settings: Cache Titles + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.CacheTitles] )); + + //! Settings: Force Titles from Disc + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.ForceDiscTitles] )); + + //! Settings: Wiilight + Options->SetValue(Idx++, "%s", tr( WiilightText[Settings.wiilight] )); + + //! Settings: Rumble + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.rumble] )); + + //! Settings: AutoInit Network + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.autonetwork] )); + + //! Settings: Messageboard Update + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.PlaylogUpdate] )); + + //! Settings: Wiinnertag + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.Wiinnertag] )); + + //! Settings: Import categories from GameTDB + Options->SetValue(Idx++, " "); + + //! Settings: Export Savegames to EmuNand + Options->SetValue(Idx++, " "); + + //! Settings: Export Miis to EmuNand + Options->SetValue(Idx++, " "); + + //! Settings: Export SYSCONF to EmuNand + Options->SetValue(Idx++, " "); + + //! Settings: Dump NAND to EmuNand + Options->SetValue(Idx++, " "); + + //! Settings: EmuNand Wad Manager + Options->SetValue(Idx++, " "); + + //! Settings: Update Nintendont + //Options->SetValue(Idx++, " "); + + //! Settings: WiiU Widescreen + Options->SetValue(Idx++, " "); + + //! Settings: Neek boot + Options->SetValue(Idx++, " "); + +} + +int FeatureSettingsMenu::GetMenuInternal() +{ + int ret = optionBrowser->GetClickedOption(); + + if (ret < 0) + return MENU_NONE; + + int Idx = -1; + + + //! Settings: Titles from GameTDB + if (ret == ++Idx) + { + if (++Settings.titlesOverride >= MAX_ON_OFF) Settings.titlesOverride = 0; + } + + //! Settings: Cache Titles + else if (ret == ++Idx) + { + if (++Settings.CacheTitles >= MAX_ON_OFF) Settings.CacheTitles = 0; + } + + //! Settings: Force Titles from Disc + else if (ret == ++Idx) + { + if (++Settings.ForceDiscTitles >= MAX_ON_OFF) Settings.ForceDiscTitles = 0; + } + + //! Settings: Wiilight + else if (ret == ++Idx) + { + if (++Settings.wiilight >= WIILIGHT_MAX) Settings.wiilight = 0; + } + + //! Settings: Rumble + else if (ret == ++Idx) + { + if (++Settings.rumble >= MAX_ON_OFF) Settings.rumble = 0; //RUMBLE + } + + //! Settings: AutoInit Network + else if (ret == ++Idx) + { + if (++Settings.autonetwork >= MAX_ON_OFF) Settings.autonetwork = 0; + } + + //! Settings: Messageboard Update + else if (ret == ++Idx ) + { + if (++Settings.PlaylogUpdate >= MAX_ON_OFF) Settings.PlaylogUpdate = 0; + } + + //! Settings: Winnertag + else if (ret == ++Idx) + { + if (++Settings.Wiinnertag >= MAX_ON_OFF) Settings.Wiinnertag = 0; + + if(Settings.Wiinnertag == ON && !Settings.autonetwork) + { + int choice = WindowPrompt(tr("Warning"), tr("Wiinnertag requires you to enable automatic network connect on application start. Do you want to enable it now?"), tr("Yes"), tr("Cancel")); + if(choice) + { + Settings.autonetwork = ON; + if(!IsNetworkInit()) + Initialize_Network(); + } + } + + char filepath[200]; + snprintf(filepath, sizeof(filepath), "%sWiinnertag.xml", Settings.WiinnertagPath); + + if(Settings.Wiinnertag == ON && !CheckFile(filepath)) + { + int choice = WindowPrompt(tr("Warning"), tr("No Wiinnertag.xml found in the config path. Do you want an example file created?"), tr("Yes"), tr("No")); + if(choice) + { + if(Wiinnertag::CreateExample(Settings.WiinnertagPath)) + { + char text[200]; + snprintf(text, sizeof(text), "%s %s", tr("An example file was created here:"), filepath); + WindowPrompt(tr("Success"), text, tr("OK")); + } + else + { + char text[200]; + snprintf(text, sizeof(text), "%s %s", tr("Could not write to:"), filepath); + WindowPrompt(tr("Failed"), text, tr("OK")); + } + } + } + } + + //! Settings: Import categories from GameTDB + else if (ret == ++Idx) + { + int choice = WindowPrompt(tr("Import Categories"), tr("Are you sure you want to import game categories from GameTDB?"), tr("Yes"), tr("Cancel")); + if(choice) + { + char xmlpath[300]; + snprintf(xmlpath, sizeof(xmlpath), "%swiitdb.xml", Settings.titlestxt_path); + if(!GameCategories.ImportFromGameTDB(xmlpath)) + { + WindowPrompt(tr("Error"), tr("Could not open the WiiTDB.xml file."), tr("OK")); + } + else + { + GameCategories.Save(); + GameCategories.CategoryList.goToFirst(); + WindowPrompt(tr("Import Categories"), tr("Import operation successfully completed."), tr("OK")); + } + } + } + + //! Settings: Export Savegames to EmuNand + else if (ret == ++Idx) + { + int choice = WindowPrompt(tr( "Do you want to extract all the save games?" ), tr("The save games will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten."), tr( "Yes" ), tr( "Cancel" )); + if (choice == 1) + { + ProgressCancelEnable(true); + StartProgress(tr("Extracting files:"), 0, 0, true, false); + char filePath[512]; + char nandPath[ISFS_MAXPATH]; + bool noErrors = true; + bool skipErrors = false; + wString filter(gameList.GetCurrentFilter()); + gameList.LoadUnfiltered(); + + //! extract the Mii file + snprintf(nandPath, sizeof(nandPath), "/shared2/menu/FaceLib/RFL_DB.dat"); + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuChanPath, nandPath); + if(!CheckFile(filePath)) + NandTitle::ExtractDir(nandPath, filePath); + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuPath, nandPath); + if(!CheckFile(filePath)) + NandTitle::ExtractDir(nandPath, filePath); + + for(int i = 0; i < gameList.size(); ++i) + { + if( gameList[i]->type != TYPE_GAME_WII_IMG + && gameList[i]->type != TYPE_GAME_NANDCHAN) + continue; + + if(gameList[i]->tid != 0) //! Channels + { + snprintf(nandPath, sizeof(nandPath), "/title/%08x/%08x/data", (unsigned int) (gameList[i]->tid >> 32), (unsigned int) gameList[i]->tid ); + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuChanPath, nandPath); + } + else //! Wii games + { + snprintf(nandPath, sizeof(nandPath), "/title/00010000/%02x%02x%02x%02x", gameList[i]->id[0], gameList[i]->id[1], gameList[i]->id[2], gameList[i]->id[3]); + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuPath, nandPath); + } + + ShowProgress(tr("Extracting files:"), GameTitles.GetTitle(gameList[i]), 0, 0, -1, true, false); + + int ret = NandTitle::ExtractDir(nandPath, filePath); + if(ret == PROGRESS_CANCELED) + { + break; + } + else if(ret < 0) //! Games with installable channels: Mario Kart, Wii Fit, etc. + { + snprintf(nandPath, sizeof(nandPath), "/title/00010004/%02x%02x%02x%02x", gameList[i]->id[0], gameList[i]->id[1], gameList[i]->id[2], gameList[i]->id[3]); + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuPath, nandPath); + ret = NandTitle::ExtractDir(nandPath, filePath); + } + if(ret < 0 && !skipErrors) + { + noErrors = false; + char text[200]; + snprintf(text, sizeof(text), "%s %s. %s. %s", tr("Could not extract files for:"), GameTitles.GetTitle(gameList[i]), tr("Savegame might not exist for this game."), tr("Continue?")); + + ProgressStop(); + int ret = WindowPrompt(tr("Error"), text, tr("Yes"), tr("No"), tr("Skip Errors")); + if(ret == 0) + skipErrors = true; + else if(ret == 2) + break; + } + } + + ProgressStop(); + ProgressCancelEnable(false); + + if(ret != PROGRESS_CANCELED) + { + if(noErrors) + WindowPrompt(tr("Success."), tr("All files extracted."), tr("OK")); + else + WindowPrompt(tr("Process finished."), tr("Errors occured."), tr("OK")); + } + gameList.FilterList(filter.c_str()); + } + } + + //! Settings: Export Miis to EmuNand + else if (ret == ++Idx) + { + int choice = WindowPrompt(tr( "Extract Miis to the Emu NAND?" ), tr("The Miis will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten."), tr( "Yes" ), tr( "Cancel" )); + if (choice == 1) + { + char filePath[512]; + char nandPath[ISFS_MAXPATH]; + bool Error = false; + ProgressCancelEnable(true); + StartProgress(tr("Extracting file:"), 0, 0, true, false); + + //! extract the Mii file + snprintf(nandPath, sizeof(nandPath), "/shared2/menu/FaceLib/RFL_DB.dat"); + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuChanPath, nandPath); + if(NandTitle::ExtractFile(nandPath, filePath) < 0) + Error = true; + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuPath, nandPath); + if(NandTitle::ExtractFile(nandPath, filePath) < 0) + Error = true; + + ProgressStop(); + ProgressCancelEnable(false); + + if(Error) + WindowPrompt(tr("Process finished."), tr("Errors occured."), tr("OK")); + else + WindowPrompt(tr("Success."), tr("All files extracted."), tr("OK")); + } + } + + //! Settings: Export SYSCONF to EmuNand + else if (ret == ++Idx) + { + int choice = WindowPrompt(tr( "Extract SYSCONF to the Emu NAND?" ), tr("The SYSCONF file will be extracted to your emu nand path and emu nand channel path. Attention: All existing files will be overwritten."), tr( "Yes" ), tr( "Cancel" )); + if (choice == 1) + { + char filePath[512]; + char nandPath[ISFS_MAXPATH]; + bool Error = false; + ProgressCancelEnable(true); + StartProgress(tr("Extracting file:"), 0, 0, true, false); + + //! extract the Mii file + snprintf(nandPath, sizeof(nandPath), "/shared2/sys/SYSCONF"); + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuChanPath, nandPath); + if(NandTitle::ExtractFile(nandPath, filePath) < 0) + Error = true; + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuPath, nandPath); + if(NandTitle::ExtractFile(nandPath, filePath) < 0) + Error = true; + + ProgressStop(); + ProgressCancelEnable(false); + + if(Error) + WindowPrompt(tr("Process finished."), tr("Errors occured."), tr("OK")); + else + WindowPrompt(tr("Success."), tr("All files extracted."), tr("OK")); + } + } + + //! Settings: Dump NAND to EmuNand + else if (ret == ++Idx) + { + int choice = WindowPrompt(tr( "What to extract from NAND?" ), tr("The files will be extracted to your emu nand save and channel path. Attention: All existing files will be overwritten."), tr( "Everything" ), tr("Enter Path"), tr( "Cancel" )); + if (choice) + { + char filePath[255]; + char *nandPath = (char *) memalign(32, ISFS_MAXPATH); + if(!nandPath) + { + WindowPrompt(tr("Error"), tr("Not enough memory."), tr("OK")); + return MENU_NONE; + } + + strcpy(nandPath, "/"); + + if(choice == 2) + { + choice = OnScreenKeyboard(nandPath, ISFS_MAXPATH, 1); + + if(strlen(nandPath) > 1 && nandPath[strlen(nandPath)-1] == '/') + nandPath[strlen(nandPath)-1] = 0; + } + + char extractPath[255]; + snprintf(extractPath, sizeof(extractPath), "%s", Settings.NandEmuPath); + if( strlen(Settings.NandEmuPath) != strlen(Settings.NandEmuChanPath) || strcmp(Settings.NandEmuPath, Settings.NandEmuChanPath) != 0 ) + { + if(WindowPrompt(tr( "Where to dump NAND?" ), tr("Select the NAND Emu Path to use."), tr( "Nand Emu Path" ), tr("Nand Emu Channel Path")) == 0) + snprintf(extractPath, sizeof(extractPath), "%s", Settings.NandEmuChanPath); + } + snprintf(filePath, sizeof(filePath), "%s%s", extractPath, nandPath); + + if(choice) + { + u32 dummy; + int ret = -1; + ProgressCancelEnable(true); + StartProgress(tr("Extracting nand files:"), 0, 0, true, false); + ShowProgress(tr("Extracting nand files:"), 0, 0, -1, true, false); + + if(ISFS_ReadDir(nandPath, NULL, &dummy) < 0) + ret = NandTitle::ExtractFile(nandPath, filePath); + else + ret = NandTitle::ExtractDir(nandPath, filePath); + + ProgressStop(); + ProgressCancelEnable(false); + + if(ret != PROGRESS_CANCELED) + { + if(ret < 0) + WindowPrompt(tr("Process finished."), tr("Errors occured."), tr("OK")); + else + WindowPrompt(tr("Success."), tr("All files extracted."), tr("OK")); + } + } + free(nandPath); + } + } + + //! Settings: EmuNand Wad Manager + else if (ret == ++Idx) + { + GuiWindow * parent = (GuiWindow *) parentElement; + if(parent) parent->SetState(STATE_DISABLED); + this->SetState(STATE_DEFAULT); + this->Remove(optionBrowser); + + char wadpath[150]; + snprintf(wadpath, sizeof(wadpath), "%s/wad/", Settings.BootDevice); + + int choice = WindowPrompt(tr("EmuNAND Wad Manager"), tr("Which mode do you want to use?"), tr("File"), tr("Folder"), tr("Cancel")); + if(choice == 1) // File mode + { + int result = BrowseDevice(wadpath, sizeof(wadpath), FB_DEFAULT ); + if(result) + { + choice = WindowPrompt(tr("EmuNAND Wad Manager"), tr("What do you want to do?"), tr("Install"), tr("Uninstall"), tr("Cancel")); + if(choice == 1) // File install + { + Wad wadFile(wadpath); + if(!wadFile.Install(Settings.NandEmuChanPath)) + { + // install error - Try to cleanup any partially installed wad data + WindowPrompt(tr("EmuNAND Wad Manager"), tr("Install error - Cleaning incomplete data."), tr( "OK" )); + //gprintf("Error : %s\n", wadpath); + wadFile.UnInstall(Settings.NandEmuChanPath); + } + } + else if(choice == 2) // File uninstall + { + Wad wadFile(wadpath); + wadFile.UnInstall(Settings.NandEmuChanPath); + } + + // Refresh new EmuNAND content + Channels::Instance()->GetEmuChannelList(); + GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path); + } + } + else if(choice == 2) // Folder mode + { + int result = BrowseDevice(wadpath, sizeof(wadpath), FB_DEFAULT, noFILES ); + if(result) + { + DirList* wadList = new DirList(wadpath, ".wad", DirList::Files); + if(wadList->GetFilecount()) + { + char found[20]; + snprintf(found, sizeof(found), fmt(tr("%i wad found."), wadList->GetFilecount())); + choice = WindowPrompt(tr("EmuNAND Wad Manager"), fmt("%s %s", found, tr("What do you want to do?")), tr("Install"), tr("Uninstall"), tr("Cancel")); + if(choice == 1) // Folder install + { + for(int i = 0; i < wadList->GetFilecount(); i++) + { + Wad wadFile(wadList->GetFilepath(i), false); + if(wadFile.Install(Settings.NandEmuChanPath)) + { + //gprintf("Success : %s\n", wadList->GetFilepath(i)); + wadList->RemoveEntrie(i); + --i; + } + else // install error - Try to cleanup any partially installed wad data + { + //gprintf("Error : %s\n", wadList->GetFilepath(i)); + wadFile.UnInstall(Settings.NandEmuChanPath); + } + } + } + if(choice == 2) // Folder uninstall + { + if(WindowPrompt(tr("EmuNAND Wad Manager"), tr("Attention: All savegames will be deleted."), tr("Uninstall"), tr("Cancel"))) + { + for(int i = 0; i < wadList->GetFilecount(); i++) + { + Wad wadFile(wadList->GetFilepath(i), false); + if(wadFile.UnInstall(Settings.NandEmuChanPath)) + { + //gprintf("uninst. : %s\n", wadList->GetFilepath(i)); + wadList->RemoveEntrie(i); + --i; + } + } + } + else + choice = 0; + } + + // check if there is any remaining unprocessed wad + if(choice != 0) + { + if(wadList->GetFilecount() == 0) + WindowPrompt(tr("EmuNAND Wad Manager"), tr("All wad files processed successfully."), tr( "OK" )); + else + { + if(WindowPrompt(tr( "EmuNAND Wad Manager" ), fmt(tr("%i wad file(s) not processed!"), wadList->GetFilecount()), tr("Save List"), tr( "OK" ))) + { + char path[200]; + snprintf(path, sizeof(path), "%s/WadManager_errors.txt", Settings.update_path); + + FILE *f = fopen(path, "a"); + if(f) + { + time_t rawtime = time(NULL); + char theTime[11]; + theTime[0] = 0; + strftime(theTime, sizeof(theTime), "%Y-%m-%d", localtime(&rawtime)); + fprintf(f, "\r\n\r\nEmuNAND Wad Manager - %10s\r\n--------------------------------\r\n", theTime); + fprintf(f, "%s %s\r\n", choice == 1 ? "Error installing to" : "Error uninstalling from", Settings.NandEmuChanPath); + fprintf(f, "%s\r\n", choice == 1 ? "List of user canceled installation or bad wad files." : "Titles not on EmuNAND or weren't correctly installed."); + + for(int i = 0; i < wadList->GetFilecount(); i++) + { + fprintf(f, "%s\r\n", wadList->GetFilepath(i)); + //gprintf("%s\n", wadList->GetFilepath(i)); + } + + fclose(f); + } + else + WindowPrompt(tr( "EmuNAND Wad Manager" ), tr("Error writing the data."), tr( "OK" )); + } + } + } + + // Refresh new EmuNAND content + Channels::Instance()->GetEmuChannelList(); + GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path); + } + else + { + WindowPrompt(tr( "EmuNAND Wad Manager" ), tr("No wad file found in this folder."), tr( "OK" )); + } + + delete wadList; + } + } + + if(parent) parent->SetState(STATE_DEFAULT); + this->Append(optionBrowser); + } + +/* + //! Settings: Update Nintendont + else if (ret == ++Idx) + { + char NINUpdatePath[100]; + snprintf(NINUpdatePath, sizeof(NINUpdatePath), "%sboot.dol", Settings.NINLoaderPath); + char NINUpdatePathBak[100]; + snprintf(NINUpdatePathBak, sizeof(NINUpdatePathBak), "%sboot.bak", Settings.NINLoaderPath); + + int choice = WindowPrompt(tr( "Do you want to update this file?" ), NINUpdatePath, tr( "Yes" ), tr( "Cancel" )); + if (choice == 1) + { + if (!IsNetworkInit() && !NetworkInitPrompt()) + { + WindowPrompt(tr("Error:"), tr("Could not initialize network!"), tr("OK")); + } + else + { + // Rename existing boot.dol file to boot.bak + if(CheckFile(NINUpdatePath)) + RenameFile(NINUpdatePath, NINUpdatePathBak); + + // Download latest loader.dol as boot.dol + bool success = false; + displayDownloadProgress(true); // enable progress window for next download + struct block file = downloadfile("https://raw.githubusercontent.com/FIX94/Nintendont/master/loader/loader.dol"); + if (file.data != NULL) + { + FILE * pfile = fopen(NINUpdatePath, "wb"); + if(pfile) + { + fwrite(file.data, 1, file.size, pfile); + fclose(pfile); + WindowPrompt(tr( "Successfully Updated" ), 0, tr( "OK" )); + success = true; + } + else + WindowPrompt(tr( "Update failed" ), 0, tr( "OK" )); + + free(file.data); + } + + if(success) + { + //remove existing loader.dol file if found as it has priority over boot.dol, and boot.bak + snprintf(NINUpdatePath, sizeof(NINUpdatePath), "%s/loader.dol", Settings.NINLoaderPath); + RemoveFile(NINUpdatePath); + RemoveFile(NINUpdatePathBak); + } + else + { + // Restore backup file if found + RemoveFile(NINUpdatePath); + if(CheckFile(NINUpdatePathBak)) + RenameFile(NINUpdatePathBak, NINUpdatePath); + WindowPrompt(tr( "Update failed" ), 0, tr( "OK" )); + } + } + } + } +*/ + + // WiiU Aspect switcher (Thanks Tueidj) + else if (ret == ++Idx) + { + if(isWiiU()) // vWii only + { + if( read32(0xd8006a0) == 0x30000004) + { + write32(0xd8006a0, 0x30000002), mask32(0xd8006a8, 0, 2); // Set 4:3 + Settings.widescreen = OFF; + } + else + { + write32(0xd8006a0, 0x30000004), mask32(0xd8006a8, 0, 2); // Set 16:9 + Settings.widescreen = ON; + } + } + } + + // Neek: Boot neek system menu with current EmuNAND channel path + else if (ret == ++Idx) + { + if(neek2oSetNAND(Settings.NandEmuChanPath) < 0) // set current path as default + { + WindowPrompt(tr("Error:"), tr("Neek NAND path selection failed."), tr("OK")); + } + else + { + if(neekLoadKernel(Settings.NandEmuChanPath) == false) + { + WindowPrompt(tr("Error:"), tr("Neek kernel loading failed."), tr("OK")); + } + else + { + ExitApp(); + NEEK_CFG *neek_config = (NEEK_CFG *) NEEK_CONFIG_ADDRESS; + neek2oSetBootSettings(neek_config, 0 /* TitleID */ , 0 /* Magic */, 0 /* Returnto TitleID */, Settings.NandEmuChanPath /* Full EmuNAND path */); + + if(neekBoot() == -1) + Sys_BackToLoader(); + return MENU_NONE; + } + } + } + SetOptionValues(); + + return MENU_NONE; +} diff --git a/source/settings/menus/FeatureSettingsMenu.hpp b/source/settings/menus/FeatureSettingsMenu.hpp new file mode 100644 index 0000000..19b70c8 --- /dev/null +++ b/source/settings/menus/FeatureSettingsMenu.hpp @@ -0,0 +1,46 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef FEATURESETTINGS_MENU_HPP_ +#define FEATURESETTINGS_MENU_HPP_ + +#include "SettingsMenu.hpp" + +class FeatureSettingsMenu : public SettingsMenu +{ + public: + FeatureSettingsMenu(); + virtual ~FeatureSettingsMenu(); + protected: + void SetOptionValues(); + int GetMenuInternal(); + + int OldTitlesOverride; + int OldCacheTitles; + int OldForceDiscTitles; + + OptionList GuiOptions; +}; + + +#endif diff --git a/source/settings/menus/FlyingButtonsMenu.cpp b/source/settings/menus/FlyingButtonsMenu.cpp new file mode 100644 index 0000000..b438b62 --- /dev/null +++ b/source/settings/menus/FlyingButtonsMenu.cpp @@ -0,0 +1,479 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include + +#include "FlyingButtonsMenu.hpp" +#include "utils/StringTools.h" +#include "language/gettext.h" +#include "themes/CTheme.h" +#include "menu/menus.h" +#include "sys.h" + +#define FADE_SPEED 20 +#define SLIDE_SPEED 35 +#define DISPLAY_BUTTONS 4 +#define MAX_INDICATORS 5 + +FlyingButtonsMenu::FlyingButtonsMenu(const char * menu_title) + : GuiWindow(screenwidth, screenheight) + +{ + currentPage = 0; + returnMenu = MENU_NONE; + ParentMenu = MENU_DISCLIST; + CurrentMenu = NULL; + titleTxt = NULL; + GoLeftImg = NULL; + GoLeftBtn = NULL; + GoRightImg = NULL; + GoRightBtn = NULL; + MenuTitle = menu_title ? menu_title : " "; + + trigA = new GuiTrigger(); + trigHome = new GuiTrigger(); + trigB = new GuiTrigger(); + trigL = new GuiTrigger(); + trigR = new GuiTrigger(); + trigMinus = new GuiTrigger(); + trigPlus = new GuiTrigger(); + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + trigHome->SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, PAD_BUTTON_START); + trigB->SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + trigL->SetButtonOnlyTrigger(-1, WPAD_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_LEFT, PAD_BUTTON_LEFT); + trigR->SetButtonOnlyTrigger(-1, WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT, PAD_BUTTON_RIGHT); + trigMinus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, PAD_TRIGGER_L); + trigPlus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_PLUS | WPAD_CLASSIC_BUTTON_PLUS, PAD_TRIGGER_R); + + btnOutline = Resources::GetImageData("button_dialogue_box.png"); + settingsbg = Resources::GetImageData("settings_background.png"); + MainButtonImgData = Resources::GetImageData("settings_title.png"); + MainButtonImgOverData = Resources::GetImageData("settings_title_over.png"); + PageindicatorImgData = Resources::GetImageData("pageindicator.png"); + arrow_left = Resources::GetImageData("startgame_arrow_left.png"); + arrow_right = Resources::GetImageData("startgame_arrow_right.png"); + + settingsbackground = new GuiImage(settingsbg); + Append(settingsbackground); + + homeBtn = new GuiButton(1, 1); + homeBtn->SetTrigger(trigHome); + Append(homeBtn); + + backBtnTxt = new GuiText(tr( "Back" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + backBtnTxt->SetMaxWidth(btnOutline->GetWidth() - 30); + backBtnImg = new GuiImage(btnOutline); + if (Settings.wsprompt == ON) + { + backBtnTxt->SetWidescreen(Settings.widescreen); + backBtnImg->SetWidescreen(Settings.widescreen); + } + backBtn = new GuiButton(backBtnImg, backBtnImg, 2, 3, -195, 400, trigA, btnSoundOver, btnSoundClick2, 1); + backBtn->SetLabel(backBtnTxt); + backBtn->SetTrigger(trigB); + Append(backBtn); + + SetEffect(EFFECT_FADE, FADE_SPEED); +} + +FlyingButtonsMenu::~FlyingButtonsMenu() +{ + ResumeGui(); + + SetEffect(EFFECT_FADE, -FADE_SPEED); + while(parentElement && this->GetEffect() > 0) usleep(10000); + + HaltGui(); + if(parentElement) + ((GuiWindow *) parentElement)->Remove(this); + + RemoveAll(); + HideMenu(); + + delete trigA; + delete trigHome; + delete trigB; + delete trigL; + delete trigR; + delete trigMinus; + delete trigPlus; + delete settingsbackground; + delete homeBtn; + delete btnOutline; + delete settingsbg; + delete MainButtonImgData; + delete MainButtonImgOverData; + delete PageindicatorImgData; + delete arrow_left; + delete arrow_right; + delete backBtnTxt; + delete backBtnImg; + delete backBtn; + + ResumeGui(); +} + +void FlyingButtonsMenu::SetPageIndicators() +{ + HaltGui(); + + for(u32 i = 0; i < PageIndicatorBtn.size(); ++i) + { + Remove(PageIndicatorBtn[i]); + delete PageindicatorImg[i]; + delete PageindicatorTxt[i]; + delete PageIndicatorBtn[i]; + } + PageindicatorImg.clear(); + PageindicatorTxt.clear(); + PageIndicatorBtn.clear(); + + int IndicatorCount = ceil(MainButton.size()/(1.0f*DISPLAY_BUTTONS)); + + FirstIndicator = 0; + if(currentPage > (int) floor(MAX_INDICATORS/2.0f)) + { + if(IndicatorCount-MAX_INDICATORS < currentPage - (int) floor(MAX_INDICATORS/2.0f)) + FirstIndicator = IndicatorCount-MAX_INDICATORS; + else + FirstIndicator = currentPage - (int) floor(MAX_INDICATORS/2.0f); + + if(FirstIndicator < 0) + FirstIndicator = 0; + } + + int DisplayedIndicators = IndicatorCount > MAX_INDICATORS ? MAX_INDICATORS : IndicatorCount; + + for(int i = 0, n = FirstIndicator; i < MAX_INDICATORS && n < IndicatorCount; ++i, ++n) + { + PageindicatorImg.push_back(new GuiImage(PageindicatorImgData)); + PageindicatorTxt.push_back(new GuiText(fmt("%i", n+1), 22, ( GXColor ) {0, 0, 0, 255})); + PageIndicatorBtn.push_back(new GuiButton(PageindicatorImgData->GetWidth(), PageindicatorImgData->GetHeight())); + PageIndicatorBtn[i]->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + PageIndicatorBtn[i]->SetPosition(270-DisplayedIndicators*35+35*i, 400); + PageIndicatorBtn[i]->SetImage(PageindicatorImg[i]); + PageIndicatorBtn[i]->SetLabel(PageindicatorTxt[i]); + PageIndicatorBtn[i]->SetSoundOver(btnSoundOver); + PageIndicatorBtn[i]->SetSoundClick(btnSoundClick); + PageIndicatorBtn[i]->SetTrigger(trigA); + PageIndicatorBtn[i]->SetEffectGrow(); + PageIndicatorBtn[i]->SetAlpha(n == currentPage ? 255 : 50); + Append(PageIndicatorBtn[i]); + } +} + +void FlyingButtonsMenu::SetMainButton(int position, const char * ButtonText, GuiImageData * imageData, GuiImageData * imageOver) +{ + //! Don't allow operating gui mode while adding/setting the buttons + HaltGui(); + + if(position < (int) MainButton.size()) + { + delete MainButtonImg[position]; + delete MainButtonImgOver[position]; + delete MainButtonTxt[position]; + delete MainButton[position]; + } + else + { + MainButtonImg.resize(position+1); + MainButtonImgOver.resize(position+1); + MainButtonTxt.resize(position+1); + MainButton.resize(position+1); + } + + MainButtonImg[position] = new GuiImage(imageData); + MainButtonImgOver[position] = new GuiImage(imageOver); + + MainButtonTxt[position] = new GuiText(ButtonText, 22, ( GXColor ) {0, 0, 0, 255}); + MainButtonTxt[position]->SetMaxWidth(MainButtonImg[position]->GetWidth()); + + MainButton[position] = new GuiButton(imageData->GetWidth(), imageData->GetHeight()); + MainButton[position]->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + MainButton[position]->SetPosition(0, 90+(position % DISPLAY_BUTTONS)*70); + MainButton[position]->SetImage(MainButtonImg[position]); + MainButton[position]->SetImageOver(MainButtonImgOver[position]); + MainButton[position]->SetLabel(MainButtonTxt[position]); + MainButton[position]->SetSoundOver(btnSoundOver); + MainButton[position]->SetSoundClick(btnSoundClick); + MainButton[position]->SetEffectGrow(); + MainButton[position]->SetTrigger(trigA); +} + +void FlyingButtonsMenu::HideMenu() +{ + HaltGui(); + + if(titleTxt) + Remove(titleTxt); + if(GoLeftBtn) + Remove(GoLeftBtn); + if(GoRightBtn) + Remove(GoRightBtn); + + if(titleTxt) + delete titleTxt; + if(GoLeftImg) + delete GoLeftImg; + if(GoLeftBtn) + delete GoLeftBtn; + if(GoRightImg) + delete GoRightImg; + if(GoRightBtn) + delete GoRightBtn; + titleTxt = NULL; + GoLeftImg = NULL; + GoLeftBtn = NULL; + GoRightImg = NULL; + GoRightBtn = NULL; + + for(u32 i = 0; i < MainButton.size(); ++i) + { + Remove(MainButton[i]); + delete MainButtonImg[i]; + delete MainButtonImgOver[i]; + delete MainButtonTxt[i]; + delete MainButton[i]; + } + for(u32 i = 0; i < PageIndicatorBtn.size(); ++i) + { + Remove(PageIndicatorBtn[i]); + delete PageindicatorImg[i]; + delete PageindicatorTxt[i]; + delete PageIndicatorBtn[i]; + } + + PageindicatorImg.clear(); + PageindicatorTxt.clear(); + PageIndicatorBtn.clear(); + MainButtonImg.clear(); + MainButtonImgOver.clear(); + MainButtonTxt.clear(); + MainButton.clear(); +} + +void FlyingButtonsMenu::ShowMenu() +{ + //! Free memory if not done yet because new is allocated + HideMenu(); + + titleTxt = new GuiText(MenuTitle.c_str(), 28, thColor("r=0 g=0 b=0 a=255 - settings title text color")); + titleTxt->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + titleTxt->SetPosition(0, 40); + titleTxt->SetMaxWidth(310, SCROLL_HORIZONTAL); + Append(titleTxt); + + GoLeftImg = new GuiImage(arrow_left); + GoLeftBtn = new GuiButton(GoLeftImg->GetWidth(), GoLeftImg->GetHeight()); + GoLeftBtn->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + GoLeftBtn->SetPosition(25, -25); + GoLeftBtn->SetImage(GoLeftImg); + GoLeftBtn->SetSoundOver(btnSoundOver); + GoLeftBtn->SetSoundClick(btnSoundClick2); + GoLeftBtn->SetEffectGrow(); + GoLeftBtn->SetTrigger(trigA); + GoLeftBtn->SetTrigger(trigL); + GoLeftBtn->SetTrigger(trigMinus); + Append(GoLeftBtn); + + GoRightImg = new GuiImage(arrow_right); + GoRightBtn = new GuiButton(GoRightImg->GetWidth(), GoRightImg->GetHeight()); + GoRightBtn->SetAlignment(ALIGN_RIGHT, ALIGN_MIDDLE); + GoRightBtn->SetPosition(-25, -25); + GoRightBtn->SetImage(GoRightImg); + GoRightBtn->SetSoundOver(btnSoundOver); + GoRightBtn->SetSoundClick(btnSoundClick2); + GoRightBtn->SetEffectGrow(); + GoRightBtn->SetTrigger(trigA); + GoRightBtn->SetTrigger(trigR); + GoRightBtn->SetTrigger(trigPlus); + Append(GoRightBtn); + + SetupMainButtons(); + AddMainButtons(); + + ShowButtonsEffects(EFFECT_FADE, FADE_SPEED); +} + +void FlyingButtonsMenu::AddMainButtons() +{ + HaltGui(); + + for(u32 i = 0; i < MainButton.size(); ++i) + Remove(MainButton[i]); + + int FirstItem = currentPage*DISPLAY_BUTTONS; + + for(int i = FirstItem; i < (int) MainButton.size() && i < FirstItem+DISPLAY_BUTTONS; ++i) + { + Append(MainButton[i]); + } + + SetPageIndicators(); +} + +void FlyingButtonsMenu::ShowButtonsEffects(int effect, int effect_speed) +{ + int FirstItem = currentPage*DISPLAY_BUTTONS; + if(FirstItem < 0) + FirstItem = 0; + + HaltGui(); + + for(int i = FirstItem; i < (int) MainButton.size() && i < FirstItem+DISPLAY_BUTTONS; ++i) + { + MainButton[i]->StopEffect(); + MainButton[i]->SetEffect(effect, effect_speed); + } + + ResumeGui(); + + if(FirstItem < 0 || FirstItem >= (int) MainButton.size()) + return; + + //! Don't lock on fade in for initiation purpose + if((effect & EFFECT_FADE) && effect_speed > 0) + return; + + while (parentElement && MainButton[FirstItem]->GetEffect() > 0) + usleep(10000); + + //! Allow button grow only after slide animation is done + for(int i = FirstItem; i < (int) MainButton.size() && i < FirstItem+DISPLAY_BUTTONS; ++i) + MainButton[i]->SetEffectGrow(); +} + +void FlyingButtonsMenu::SlideButtons(int direction) +{ + int SlideEffectIN = 0; + + if(direction == SLIDE_LEFT) + { + ShowButtonsEffects(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, SLIDE_SPEED); + SlideEffectIN = EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN; + + currentPage--; + + if(currentPage < 0) + currentPage = MainButton.size() > 0 ? ceil(MainButton.size()/4.0f)-1 : 0; + } + else + { + ShowButtonsEffects(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, SLIDE_SPEED); + SlideEffectIN = EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN; + + currentPage++; + + if(currentPage >= ceil(MainButton.size()/4.0f)) + currentPage = 0; + } + + AddMainButtons(); + + ShowButtonsEffects(SlideEffectIN, SLIDE_SPEED); +} + +int FlyingButtonsMenu::MainLoop() +{ + usleep(50000); + + if(shutdown) + Sys_Shutdown(); + else if(reset) + Sys_Reboot(); + + if(backBtn->GetState() == STATE_CLICKED) + { + if(CurrentMenu) + { + DeleteSettingsMenu(); + ShowMenu(); + } + else + { + return ParentMenu; + } + backBtn->ResetState(); + } + else if(GoRightBtn && GoRightBtn->GetState() == STATE_CLICKED) + { + SlideButtons(SLIDE_RIGHT); + GoRightBtn->ResetState(); + } + else if(GoLeftBtn && GoLeftBtn->GetState() == STATE_CLICKED) + { + SlideButtons(SLIDE_LEFT); + GoLeftBtn->ResetState(); + } + else if(homeBtn->GetState() == STATE_CLICKED) + { + Settings.Save(); + if(CurrentMenu) CurrentMenu->SetState(STATE_DISABLED); + WindowExitPrompt(); + homeBtn->ResetState(); + if(CurrentMenu) CurrentMenu->SetState(STATE_DEFAULT); + } + else if(CurrentMenu) + { + int newMenu = CurrentMenu->GetMenu(); + if(newMenu != MENU_NONE) + return newMenu; + } + + for(u32 i = 0; i < PageIndicatorBtn.size(); ++i) + { + if(PageIndicatorBtn[i]->GetState() != STATE_CLICKED) + continue; + + if(FirstIndicator+i < (u32) currentPage) + { + ShowButtonsEffects(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, SLIDE_SPEED); + currentPage = FirstIndicator+i; + AddMainButtons(); + ShowButtonsEffects(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, SLIDE_SPEED); + } + else if(FirstIndicator+i > (u32) currentPage) + { + ShowButtonsEffects(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, SLIDE_SPEED); + currentPage = FirstIndicator+i; + AddMainButtons(); + ShowButtonsEffects(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, SLIDE_SPEED); + } + + PageIndicatorBtn[i]->ResetState(); + } + + for(u32 i = 0; i < MainButton.size(); ++i) + { + if(MainButton[i]->GetState() != STATE_CLICKED) + continue; + + MainButton[i]->ResetState(); + + CreateSettingsMenu(i); + break; + } + + return returnMenu; +} diff --git a/source/settings/menus/FlyingButtonsMenu.hpp b/source/settings/menus/FlyingButtonsMenu.hpp new file mode 100644 index 0000000..207ff7f --- /dev/null +++ b/source/settings/menus/FlyingButtonsMenu.hpp @@ -0,0 +1,105 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef FLYINGBUTTONSMENU_HPP_ +#define FLYINGBUTTONSMENU_HPP_ + +#include +#include +#include "GUI/gui.h" +#include "SettingsMenu.hpp" +#include "menu.h" + +class FlyingButtonsMenu : public GuiWindow +{ + public: + FlyingButtonsMenu(const char * menu_title); + virtual ~FlyingButtonsMenu(); + virtual int MainLoop(); + virtual void HideMenu(); + virtual void ShowMenu(); + protected: + virtual void CreateSettingsMenu(int index) { }; + virtual void DeleteSettingsMenu() { }; + virtual void SetupMainButtons() { }; + virtual void AddMainButtons(); + virtual void ShowButtonsEffects(int effect, int effect_speed); + virtual void SlideButtons(int slide_direction); + virtual void SetPageIndicators(); + virtual void SetMainButton(int position, const char * ButtonText, GuiImageData * imageData, GuiImageData * imageOver); + + int currentPage; + int returnMenu; + int ParentMenu; + int FirstIndicator; + std::string MenuTitle; + enum + { + SLIDE_LEFT, SLIDE_RIGHT + }; + + //!The main settings gui with browser + SettingsMenu * CurrentMenu; + + GuiImageData * btnOutline; + GuiImageData * settingsbg; + GuiImageData * MainButtonImgData; + GuiImageData * MainButtonImgOverData; + GuiImageData * PageindicatorImgData; + GuiImageData * arrow_left; + GuiImageData * arrow_right; + + GuiImage * settingsbackground; + GuiImage * backBtnImg; + GuiImage * PageindicatorImg2; + GuiImage * GoLeftImg; + GuiImage * GoRightImg; + + GuiTrigger * trigA; + GuiTrigger * trigHome; + GuiTrigger * trigB; + GuiTrigger * trigL; + GuiTrigger * trigR; + GuiTrigger * trigMinus; + GuiTrigger * trigPlus; + + GuiText * titleTxt; + GuiText * backBtnTxt; + GuiText * PageindicatorTxt1; + + GuiButton * backBtn; + GuiButton * homeBtn; + GuiButton * GoLeftBtn; + GuiButton * GoRightBtn; + + std::vectorPageindicatorImg; + std::vectorPageindicatorTxt; + std::vectorPageIndicatorBtn; + + std::vector MainButtonImg; + std::vector MainButtonImgOver; + std::vector MainButtonTxt; + std::vector MainButton; +}; + +#endif diff --git a/source/settings/menus/GCGameLoadSM.cpp b/source/settings/menus/GCGameLoadSM.cpp new file mode 100644 index 0000000..ea4b67c --- /dev/null +++ b/source/settings/menus/GCGameLoadSM.cpp @@ -0,0 +1,956 @@ +/**************************************************************************** + * Copyright (C) 2012-2014 by Cyan + * Copyright (C) 2012 Dimok + * + * 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 "settings/CSettings.h" +#include "settings/CGameStatistics.h" +#include "themes/CTheme.h" +#include "prompts/PromptWindows.h" +#include "prompts/DiscBrowser.h" +#include "prompts/filebrowser.h" +#include "usbloader/AlternateDOLOffsets.h" +#include "language/gettext.h" +#include "wad/nandtitle.h" +#include "system/IosLoader.h" +#include "GCGameLoadSM.hpp" +#include "utils/tools.h" + +static const char * OnOffText[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ), + trNOOP( "Auto" ) +}; + +static const char * LanguageText[] = +{ + trNOOP( "English" ), + trNOOP( "German" ), + trNOOP( "French" ), + trNOOP( "Spanish" ), + trNOOP( "Italian" ), + trNOOP( "Dutch" ), + trNOOP( "Console Default" ), +}; + +static const char * ParentalText[] = +{ + trNOOP( "0 (Everyone)" ), + trNOOP( "1 (Child 7+)" ), + trNOOP( "2 (Teen 12+)" ), + trNOOP( "3 (Mature 16+)" ), + trNOOP( "4 (Adults Only 18+)" ) +}; + +static const char * GCMode[] = +{ + trNOOP( "MIOS (Default & Customs)" ), + trNOOP( "Devolution" ), + trNOOP( "Nintendont" ), +}; + +static const char * DMLVideoText[] = +{ + trNOOP( "Auto" ), + trNOOP( "System Default" ), + trNOOP( "Disc Default" ), + trNOOP( "Force PAL50" ), + trNOOP( "Force PAL60" ), + trNOOP( "Force NTSC" ), + "", // unused + trNOOP( "Force PAL480p" ), + trNOOP( "Force NTSC480p" ), + trNOOP( "None" ), +}; + +static const char * DMLNMMMode[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ), + trNOOP( "Debug" ), +}; + +static const char * DMLDebug[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ), + trNOOP( "Debug Wait" ), +}; + +static const char * DEVOMCText[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ), + trNOOP( "Individual" ), +}; + +static const char * NINMCText[] = +{ + trNOOP( "OFF" ), + trNOOP( "Individual" ), + trNOOP( "ON (Multi)" ), +}; + +static int currentGCmode = 0; + +GCGameLoadSM::GCGameLoadSM(struct discHdr *hdr) + : SettingsMenu(tr("Game Load"), &GuiOptions, MENU_NONE), + Header(hdr) +{ + GameConfig = *GameSettings.GetGameCFG((const char *) Header->id); + + if(!btnOutline) + btnOutline = Resources::GetImageData("button_dialogue_box.png"); + if(!trigA) + trigA = new GuiTrigger(); + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + saveBtnTxt = new GuiText(tr( "Save" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + saveBtnTxt->SetMaxWidth(btnOutline->GetWidth() - 30); + saveBtnImg = new GuiImage (btnOutline); + if (Settings.wsprompt == ON) + { + saveBtnTxt->SetWidescreen(Settings.widescreen); + saveBtnImg->SetWidescreen(Settings.widescreen); + } + saveBtn = new GuiButton(saveBtnImg, saveBtnImg, 2, 3, 180, 400, trigA, btnSoundOver, btnSoundClick2, 1); + saveBtn->SetLabel(saveBtnTxt); + Append(saveBtn); + + currentGCmode = GameConfig.GameCubeMode == INHERIT ? Settings.GameCubeMode : GameConfig.GameCubeMode; + + SetOptionNames(); + SetOptionValues(); +} + +GCGameLoadSM::~GCGameLoadSM() +{ + HaltGui(); + //! The rest is destroyed in SettingsMenu.cpp + Remove(saveBtn); + delete saveBtnTxt; + delete saveBtnImg; + delete saveBtn; + ResumeGui(); +} + +void GCGameLoadSM::SetDefaultConfig() +{ + char id[7]; + snprintf(id, sizeof(id), GameConfig.id); + GameSettings.SetDefault(GameConfig); + snprintf(GameConfig.id, sizeof(GameConfig.id), id); +} + +void GCGameLoadSM::SetOptionNames() +{ + int Idx = 0; + + Options->SetName(Idx++, "%s", tr( "Game Lock" )); + Options->SetName(Idx++, "%s", tr( "Favorite Level" )); + Options->SetName(Idx++, "%s", tr( "Game Language" )); + Options->SetName(Idx++, "%s", tr( "Parental Control" )); + Options->SetName(Idx++, "%s", tr( "GameCube Mode" )); + if(currentGCmode == GC_MODE_MIOS &&IosLoader::GetMIOSInfo() > DEFAULT_MIOS) + { + Options->SetName(Idx++, "%s", tr( "--== DIOS MIOS (Lite) " )); + Options->SetName(Idx++, "%s", tr( "Video Mode" )); + Options->SetName(Idx++, "%s", tr( "Progressive Patch" )); + if(IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_1) + Options->SetName(Idx++, "%s", tr( "Force Widescreen" )); + Options->SetName(Idx++, "%s", tr( "Ocarina" )); + Options->SetName(Idx++, "%s", tr( "NMM Mode" )); + Options->SetName(Idx++, "%s", tr( "Debug" )); + Options->SetName(Idx++, "%s", tr( "LED Activity" )); + Options->SetName(Idx++, "%s", tr( "PAD Hook" )); + if(IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_2_2 && IosLoader::GetDMLVersion() <= DML_VERSION_DML_2_2_1) + Options->SetName(Idx++, "%s", tr( "No Disc+" )); + if(IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_5) + Options->SetName(Idx++, "%s", tr( "Screenshot" )); + Options->SetName(Idx++, "%s", tr( "Japanese Patch" )); + } + if(currentGCmode == GC_MODE_NINTENDONT) + { + Options->SetName(Idx++, "%s", tr( "--== Nintendont" )); + Options->SetName(Idx++, "%s", tr( "Video Mode" )); + Options->SetName(Idx++, "%s", tr( "Progressive Patch" )); + Options->SetName(Idx++, "%s", tr( "Video Deflicker" )); + Options->SetName(Idx++, "%s", tr( "PAL50 Patch" )); + Options->SetName(Idx++, "%s", tr( "Force Widescreen" )); + Options->SetName(Idx++, "%s", tr( "WiiU Widescreen" )); + Options->SetName(Idx++, "%s", tr( "Video scale" )); + if(GameConfig.NINVideoScale == 1) + Options->SetName(Idx++, "%s", tr( "Video Scale Value" )); + Options->SetName(Idx++, "%s", tr( "Video offset" )); + Options->SetName(Idx++, "%s", tr( "Ocarina" )); + Options->SetName(Idx++, "%s", tr( "Remove Read Speed Limit" )); + Options->SetName(Idx++, "%s", tr( "Triforce Arcade Mode" )); + Options->SetName(Idx++, "%s", tr("CC Rumble")); + Options->SetName(Idx++, "%s", tr("Skip IPL")); + Options->SetName(Idx++, "%s", tr( "BBA Emulation")); // ASA + Options->SetName(Idx++, "%s", tr( "BBA Network Profile")); // ASA + Options->SetName(Idx++, "%s", tr( "Memory Card Emulation" )); + Options->SetName(Idx++, "%s", tr( "Memory Card Blocks Size" )); + Options->SetName(Idx++, "%s", tr( "USB-HID Controller" )); + Options->SetName(Idx++, "%s", tr( "GameCube Controller" )); + Options->SetName(Idx++, "%s", tr( "Native Controller" )); + Options->SetName(Idx++, "%s", tr( "LED Activity" )); + Options->SetName(Idx++, "%s", tr( "Debug" )); + Options->SetName(Idx++, "%s", tr( "OSReport" )); + Options->SetName(Idx++, "%s", tr( "Log to file" )); + Options->SetName(Idx++, "%s", tr( "Nintendont Loader Path" )); + } + if(currentGCmode == GC_MODE_DEVOLUTION) + { + Options->SetName(Idx++, "%s", tr( "--== Devolution" )); + Options->SetName(Idx++, "%s", tr( "Memory Card Emulation" )); + Options->SetName(Idx++, "%s", tr( "Force Widescreen" )); + Options->SetName(Idx++, "%s", tr( "LED Activity" )); + Options->SetName(Idx++, "%s", tr( "F-Zero AX" )); + Options->SetName(Idx++, "%s", tr( "Timer Fix" )); + Options->SetName(Idx++, "%s", tr( "D Buttons" )); + Options->SetName(Idx++, "%s", tr( "Crop Overscan" )); + Options->SetName(Idx++, "%s", tr( "Disc Read Delay" )); + } +} + +void GCGameLoadSM::SetOptionValues() +{ + int Idx = 0; + + //! Settings: Game Lock + Options->SetValue(Idx++, "%s", tr( OnOffText[GameConfig.Locked] )); + + //! Settings: Favorite Level + Options->SetValue(Idx++, "%i", GameStatistics.GetFavoriteRank(Header->id)); + + //! Settings: Game Language + if(GameConfig.language == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(LanguageText[GameConfig.language])); + + //! Settings: Parental Control + Options->SetValue(Idx++, "%s", tr(ParentalText[GameConfig.parentalcontrol])); + + //! Settings: GameCube Mode + if(GameConfig.GameCubeMode == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(GCMode[GameConfig.GameCubeMode])); + + if(currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS) + { + + //! Settings: GameCube TITLE : DIOS MIOS (Lite) + Nintendont + Options->SetValue(Idx++, "==-- "); + + //! Settings: DML + NIN Video Mode + if(GameConfig.DMLVideo == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(DMLVideoText[GameConfig.DMLVideo])); + + //! Settings: DML + NIN Progressive Patch + if(GameConfig.DMLProgPatch == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DMLProgPatch])); + + //! Settings: DML + NIN Force Widescreen + if(IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_1) + { + if(GameConfig.DMLWidescreen == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DMLWidescreen])); + } + + //! Settings: Ocarina + if(GameConfig.ocarina == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.ocarina])); + + //! Settings: DML + NIN NMM Mode + if(GameConfig.DMLNMM == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(DMLNMMMode[GameConfig.DMLNMM])); + + //! Settings: DML + NIN Debug + if(GameConfig.DMLDebug == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(DMLDebug[GameConfig.DMLDebug])); + + //! Settings: DML LED Activity + if(GameConfig.DMLActivityLED == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DMLActivityLED])); + + //! Settings: DML PAD Hook + if(GameConfig.DMLPADHOOK == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DMLPADHOOK])); + + //! Settings: DML Extended No Disc + if(IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_2_2 && IosLoader::GetDMLVersion() <= DML_VERSION_DML_2_2_1) + { + if(GameConfig.DMLNoDisc2 == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DMLNoDisc2])); + } + + //! Settings: DML Screenshot + if(IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_5) + { + if(GameConfig.DMLScreenshot == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DMLScreenshot])); + } + + //! Settings: DML Japanese Patch + if(GameConfig.DMLJPNPatch == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DMLJPNPatch])); + } + + if(currentGCmode == GC_MODE_NINTENDONT) + { + + //! Settings: GameCube TITLE : DIOS MIOS (Lite) + Nintendont + Options->SetValue(Idx++, "==-- "); + + //! Settings: DML + NIN Video Mode + if(GameConfig.DMLVideo == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(DMLVideoText[GameConfig.DMLVideo])); + + //! Settings: DML + NIN Progressive Patch + if(GameConfig.DMLProgPatch == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DMLProgPatch])); + + //! Settings: NIN Video Deflicker + if(GameConfig.NINDeflicker == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINDeflicker])); + + //! Settings: NIN PAL50 Patch + if(GameConfig.NINPal50Patch == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINPal50Patch])); + + //! Settings: DML + NIN Force Widescreen + if(GameConfig.DMLWidescreen == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DMLWidescreen])); + + //! Settings: WiiU Widescreen + if(GameConfig.NINWiiUWide == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINWiiUWide])); + + //! Settings: NIN VideoScale + if(GameConfig.NINVideoScale == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else if(GameConfig.NINVideoScale == 0) + Options->SetValue(Idx++, tr("Auto")); + else + Options->SetValue(Idx++, "Manual (40~120)"); + + if(GameConfig.NINVideoScale > 0) + Options->SetValue(Idx++, "%d", GameConfig.NINVideoScale); + + //! Settings: NIN VideoOffset + if(GameConfig.NINVideoOffset == INHERIT-20) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%d (-20~20)", GameConfig.NINVideoOffset); + + //! Settings: Ocarina + if(GameConfig.ocarina == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.ocarina])); + + //! Settings: Remove Read Speed Limiter + if(GameConfig.NINRemlimit == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINRemlimit])); + + //! Settings: NIN Arcade Mode + if(GameConfig.NINArcadeMode == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINArcadeMode])); + + //! Settings: NIN CC Rumble + if (GameConfig.NINCCRumble == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINCCRumble])); + + //! Settings: NIN Skip IPL + if (GameConfig.NINSkipIPL == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINSkipIPL])); + + //! Settings NIN BBA // ASA + if (GameConfig.NINBBA == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINBBA])); + + //! Settings NIN BBA Profile // ASA + if (GameConfig.NINBBAPROF == INHERIT) + Options->SetValue(Idx++, "%s", tr("Use global")); + else if (GameConfig.NINBBAPROF == 0) + Options->SetValue(Idx++, "%s", tr("Auto")); + else + Options->SetValue(Idx++, "%hi", GameConfig.NINBBAPROF); + + //! Settings: NIN Memory Card Emulation + if(GameConfig.NINMCEmulation == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(NINMCText[GameConfig.NINMCEmulation])); + + //! Settings: NIN Memory Card Blocks Size + if(GameConfig.NINMCSize == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%d", MEM_CARD_BLOCKS(GameConfig.NINMCSize)); + + //! Settings: NIN USB-HID Controller + if(GameConfig.NINUSBHID == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINUSBHID])); + + //! Settings: NIN MaxPads - Number of GameCube Controllers + if(GameConfig.NINMaxPads == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%i", GameConfig.NINMaxPads); + + //! Settings: NIN Native Controller + if(GameConfig.NINNativeSI == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINNativeSI])); + + //! Settings: NIN LED Activity + if(GameConfig.NINLED == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINLED])); + + //! Settings: DML + NIN Debug + if(GameConfig.DMLDebug == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(DMLDebug[GameConfig.DMLDebug])); + + //! Settings: NIN OS Report + if(GameConfig.NINOSReport == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINOSReport])); + + //! Settings: NIN Log to file + if(GameConfig.NINLog == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.NINLog])); + + //! Settings: NIN Individual Loader path setting + if(GameConfig.NINLoaderPath.size() == 0) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", GameConfig.NINLoaderPath.c_str()); + + } + + if(currentGCmode == GC_MODE_DEVOLUTION) + { + + //! Settings: GameCube TITLE : Devolution + Options->SetValue(Idx++, "==-- "); + + //! Settings: DEVO Memory Card Emulation + if(GameConfig.DEVOMCEmulation == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(DEVOMCText[GameConfig.DEVOMCEmulation])); + + //! Settings: DEVO Widescreen Patch + if(GameConfig.DEVOWidescreen == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DEVOWidescreen])); + + //! Settings: DEVO Activity LED + if(GameConfig.DEVOActivityLED == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DEVOActivityLED])); + + //! Settings: DEVO F-Zero AX unlock patch + if(GameConfig.DEVOFZeroAX == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DEVOFZeroAX])); + + //! Settings: DEVO Timer Fix + if(GameConfig.DEVOTimerFix == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DEVOTimerFix])); + + //! Settings: DEVO Direct Button Mapping + if(GameConfig.DEVODButtons == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DEVODButtons])); + + //! Settings: DEVO Crop Overscan + if(GameConfig.DEVOCropOverscan == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DEVOCropOverscan])); + + //! Settings: DEVO Disc Read Delay + if(GameConfig.DEVODiscDelay == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.DEVODiscDelay])); + + } +} + +int GCGameLoadSM::GetMenuInternal() +{ + if (saveBtn->GetState() == STATE_CLICKED) + { + if (GameSettings.AddGame(GameConfig) && GameSettings.Save()) + { + WindowPrompt(tr( "Successfully Saved" ), 0, tr( "OK" )); + } + else + WindowPrompt(tr( "Save Failed. No device inserted?" ), 0, tr( "OK" )); + + saveBtn->ResetState(); + } + + int ret = optionBrowser->GetClickedOption(); + + if (ret < 0) + return MENU_NONE; + + int Idx = -1; + + //! Settings: Game Lock + if (ret == ++Idx) + { + if (++GameConfig.Locked >= MAX_ON_OFF) GameConfig.Locked = 0; + } + + //! Settings: Favorite Level + else if (ret == ++Idx) + { + int Level = GameStatistics.GetFavoriteRank(Header->id); + if (++Level > 5) Level = 0; + + GameStatistics.SetFavoriteRank(Header->id, Level); + GameStatistics.Save(); + } + + //! Settings: Game Language + else if (ret == ++Idx) + { + if (++GameConfig.language >= GC_MAX_LANGUAGE) GameConfig.language = INHERIT; + } + + //! Settings: Parental Control + else if (ret == ++Idx) + { + if (++GameConfig.parentalcontrol >= 5) GameConfig.parentalcontrol = 0; + } + + //! Settings: GameCube Mode + else if (ret == ++Idx) + { + if (++GameConfig.GameCubeMode >= CG_MODE_MAX_CHOICE) GameConfig.GameCubeMode = INHERIT; + currentGCmode = GameConfig.GameCubeMode == INHERIT ? Settings.GameCubeMode : GameConfig.GameCubeMode; + Options->ClearList(); + SetOptionNames(); + SetOptionValues(); + } + + //! Settings: GameCube TITLE : DIOS MIOS (Lite) + Nintendont + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && ret == ++Idx) + { + // This one is a category title + } + + //! Settings: DML Video Mode + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && ret == ++Idx) + { + GameConfig.DMLVideo++; + if(GameConfig.DMLVideo == DML_VIDEO_FORCE_PATCH) // Skip Force Patch + GameConfig.DMLVideo++; + if(GameConfig.DMLVideo >= DML_VIDEO_MAX_CHOICE) GameConfig.DMLVideo = INHERIT; + } + + //! Settings: DML Progressive Patch + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && ret == ++Idx) + { + if (++GameConfig.DMLProgPatch >= MAX_ON_OFF) GameConfig.DMLProgPatch = INHERIT; + } + + //! Settings: DML Force Widescreen + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_1 && ret == ++Idx) + { + if (++GameConfig.DMLWidescreen >= MAX_ON_OFF) GameConfig.DMLWidescreen = INHERIT; + } + + //! Settings: Ocarina + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && ret == ++Idx) + { + if (++GameConfig.ocarina >= MAX_ON_OFF) GameConfig.ocarina = INHERIT; + } + + //! Settings: DML NMM Mode + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && ret == ++Idx) + { + if (++GameConfig.DMLNMM >= 3) GameConfig.DMLNMM = INHERIT; + } + + //! Settings: DML Debug + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && ret == ++Idx) + { + if (++GameConfig.DMLDebug >= 3) GameConfig.DMLDebug = INHERIT; + } + + //! Settings: DML LED Activity + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && ret == ++Idx) + { + if (++GameConfig.DMLActivityLED >= MAX_ON_OFF) GameConfig.DMLActivityLED = INHERIT; + } + + //! Settings: DML PAD Hook + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && ret == ++Idx) + { + if (++GameConfig.DMLPADHOOK >= MAX_ON_OFF) GameConfig.DMLPADHOOK = INHERIT; + } + + //! Settings: DML Extended No Disc + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_2_2 && IosLoader::GetDMLVersion() <= DML_VERSION_DML_2_2_1 && ret == ++Idx) + { + if (++GameConfig.DMLNoDisc2 >= MAX_ON_OFF) GameConfig.DMLNoDisc2 = INHERIT; + } + + //! Settings: DML Screenshot + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_5 && ret == ++Idx) + { + if (++GameConfig.DMLScreenshot >= MAX_ON_OFF) GameConfig.DMLScreenshot = INHERIT; + } + + //! Settings: DML Japanese Patch + else if (currentGCmode == GC_MODE_MIOS && IosLoader::GetMIOSInfo() > DEFAULT_MIOS && ret == ++Idx) + { + if (++GameConfig.DMLJPNPatch >= MAX_ON_OFF) GameConfig.DMLJPNPatch = INHERIT; + } + + //! Settings: GameCube TITLE : DIOS MIOS (Lite) + Nintendont + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + // This one is a category title + } + + //! Settings: NIN Video Mode + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + GameConfig.DMLVideo++; + if(GameConfig.DMLVideo == DML_VIDEO_FORCE_PATCH) // Skip Force Patch + GameConfig.DMLVideo++; + if(GameConfig.DMLVideo >= DML_VIDEO_MAX_CHOICE) GameConfig.DMLVideo = INHERIT; + } + + //! Settings: NIN Progressive Patch + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.DMLProgPatch >= MAX_ON_OFF) GameConfig.DMLProgPatch = INHERIT; + } + + //! Settings: NIN Video Deflicker + if(currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINDeflicker >= MAX_ON_OFF) GameConfig.NINDeflicker = INHERIT; + } + + //! Settings: NIN PAL50 Patch + if(currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINPal50Patch >= MAX_ON_OFF) GameConfig.NINPal50Patch = INHERIT; + } + + //! Settings: NIN Force Widescreen + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.DMLWidescreen >= MAX_ON_OFF) GameConfig.DMLWidescreen = INHERIT; + } + + //! Settings: WiiU Widescreen + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINWiiUWide >= MAX_ON_OFF) GameConfig.NINWiiUWide = INHERIT; + } + + //! Settings: NIN VideoScale + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (GameConfig.NINVideoScale == INHERIT) GameConfig.NINVideoScale = 0; + else if (GameConfig.NINVideoScale == 0) GameConfig.NINVideoScale = 40; + else if (GameConfig.NINVideoScale >= 0) GameConfig.NINVideoScale = INHERIT; + Options->ClearList(); + SetOptionNames(); + SetOptionValues(); + } + + else if (currentGCmode == GC_MODE_NINTENDONT && GameConfig.NINVideoScale > 0 && ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%i", GameConfig.NINVideoScale); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + { + GameConfig.NINVideoScale = LIMIT(atoi(entrie), 40, 120); + } + } + + //! Settings: NIN VideoOffset + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%i", GameConfig.NINVideoOffset); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + GameConfig.NINVideoOffset = LIMIT(atoi(entrie), -21, 20); + } + + //! Settings: Ocarina + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.ocarina >= MAX_ON_OFF) GameConfig.ocarina = INHERIT; + } + + //! Settings: Remove Read Speed Limiter + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINRemlimit >= MAX_ON_OFF) GameConfig.NINRemlimit = INHERIT; + } + + //! Settings: NIN Arcade Mode + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINArcadeMode >= MAX_ON_OFF) GameConfig.NINArcadeMode = INHERIT; + } + + //! Settings: NIN CC Rumble + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINCCRumble >= MAX_ON_OFF) GameConfig.NINCCRumble = INHERIT; + } + + //! Settings: NIN Skip IPL + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINSkipIPL >= MAX_ON_OFF) GameConfig.NINSkipIPL = INHERIT; + } + + //! Settings: NIN BBA // ASA + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINBBA >= MAX_ON_OFF) GameConfig.NINBBA = INHERIT; + } + + //! Settings: NIN BAA Profile // ASA + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINBBAPROF >= 4) GameConfig.NINBBAPROF = INHERIT; + } + + //! Settings: NIN Memory Card Emulation + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINMCEmulation >= NIN_MC_MAX_CHOICE) GameConfig.NINMCEmulation = INHERIT; + } + + //! Settings: NIN Memory Card Blocks Size + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINMCSize >= 6) GameConfig.NINMCSize = INHERIT; + if (GameConfig.NINMCSize == 5) + WindowPrompt(tr("Warning:"), tr("Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk."), tr("Ok")); + } + + //! Settings: NIN USB-HID Controller + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINUSBHID >= MAX_ON_OFF) GameConfig.NINUSBHID = INHERIT; + } + + //! Settings: NIN MaxPads - Number of GameCube Controllers + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINMaxPads >= 5) GameConfig.NINMaxPads = INHERIT; + } + + //! Settings: NIN Native Controller + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINNativeSI >= MAX_ON_OFF) GameConfig.NINNativeSI = INHERIT; + } + + //! Settings: NIN LED Activity + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINLED >= MAX_ON_OFF) GameConfig.NINLED = INHERIT; + } + + //! Settings: NIN Debug + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.DMLDebug >= 3) GameConfig.DMLDebug = INHERIT; + } + + //! Settings: NIN OS Report + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINOSReport >= MAX_ON_OFF) GameConfig.NINOSReport = INHERIT; + } + + //! Settings: NIN Log to file + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + if (++GameConfig.NINLog >= MAX_ON_OFF) GameConfig.NINLog = INHERIT; + } + + //! Settings: NIN Individual Loader path setting + else if (currentGCmode == GC_MODE_NINTENDONT && ret == ++Idx) + { + char entered[100]; + snprintf(entered, sizeof(entered), GameConfig.NINLoaderPath.c_str()); + + HaltGui(); + GuiWindow * parent = (GuiWindow *) parentElement; + if(parent) parent->SetState(STATE_DISABLED); + this->SetState(STATE_DEFAULT); + this->Remove(optionBrowser); + ResumeGui(); + + int result = BrowseDevice(entered, sizeof(entered), FB_DEFAULT, noFILES); + + if(parent) parent->SetState(STATE_DEFAULT); + this->Append(optionBrowser); + + if (result == 1) + { + if (entered[strlen(entered)-1] != '/') + strcat(entered, "/"); + + GameConfig.NINLoaderPath = entered; + WindowPrompt(tr( "Path Changed" ), 0, tr( "OK" )); + } + } + + //! Settings: GameCube TITLE : Devolution + else if (currentGCmode == GC_MODE_DEVOLUTION && ret == ++Idx) + { + // This one is a category title + } + + //! Settings: DEVO MemCard emulation + else if (currentGCmode == GC_MODE_DEVOLUTION && ret == ++Idx) + { + if (++GameConfig.DEVOMCEmulation >= DEVO_MC_MAX_CHOICE) GameConfig.DEVOMCEmulation = INHERIT; + } + + //! Settings: DEVO Widescreen Patch + else if (currentGCmode == GC_MODE_DEVOLUTION && ret == ++Idx) + { + if (++GameConfig.DEVOWidescreen >= MAX_ON_OFF) GameConfig.DEVOWidescreen = INHERIT; + } + + //! Settings: DEVO Activity LED + else if (currentGCmode == GC_MODE_DEVOLUTION && ret == ++Idx) + { + if (++GameConfig.DEVOActivityLED >= MAX_ON_OFF) GameConfig.DEVOActivityLED = INHERIT; + } + + //! Settings: DEVO F-Zero AX unlock patch + else if (currentGCmode == GC_MODE_DEVOLUTION && ret == ++Idx) + { + if (++GameConfig.DEVOFZeroAX >= MAX_ON_OFF) GameConfig.DEVOFZeroAX = INHERIT; + } + + //! Settings: DEVO Timer Fix + else if (currentGCmode == GC_MODE_DEVOLUTION && ret == ++Idx) + { + if (++GameConfig.DEVOTimerFix >= MAX_ON_OFF) GameConfig.DEVOTimerFix = INHERIT; + } + + //!Settings: DEVO Direct Button Mapping + else if (currentGCmode == GC_MODE_DEVOLUTION && ret == ++Idx) + { + if (++GameConfig.DEVODButtons >= MAX_ON_OFF) GameConfig.DEVODButtons = INHERIT; + } + + //!Settings: DEVO Crop Overscan + else if (currentGCmode == GC_MODE_DEVOLUTION && ret == ++Idx) + { + if (++GameConfig.DEVOCropOverscan >= MAX_ON_OFF) GameConfig.DEVOCropOverscan = INHERIT; + } + + //!Settings: DEVO Disc Read Delay + else if (currentGCmode == GC_MODE_DEVOLUTION && ret == ++Idx) + { + if (++GameConfig.DEVODiscDelay >= MAX_ON_OFF) GameConfig.DEVODiscDelay = INHERIT; + } + + SetOptionValues(); + + return MENU_NONE; +} + diff --git a/source/settings/menus/GCGameLoadSM.hpp b/source/settings/menus/GCGameLoadSM.hpp new file mode 100644 index 0000000..e4eb035 --- /dev/null +++ b/source/settings/menus/GCGameLoadSM.hpp @@ -0,0 +1,44 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 GCGAMELOAD_SM_HPP +#define GCGAMELOAD_SM_HPP + +#include "SettingsMenu.hpp" +#include "settings/CGameSettings.h" + +class GCGameLoadSM : public SettingsMenu +{ + public: + GCGameLoadSM(struct discHdr *Header); + virtual ~GCGameLoadSM(); + protected: + void SetDefaultConfig(); + void SetOptionNames(); + void SetOptionValues(); + int GetMenuInternal(); + + struct discHdr *Header; + GameCFG GameConfig; + OptionList GuiOptions; + + GuiText * saveBtnTxt; + GuiImage * saveBtnImg; + GuiButton * saveBtn; +}; + + +#endif diff --git a/source/settings/menus/GUISettingsMenu.cpp b/source/settings/menus/GUISettingsMenu.cpp new file mode 100644 index 0000000..07c4bd6 --- /dev/null +++ b/source/settings/menus/GUISettingsMenu.cpp @@ -0,0 +1,491 @@ + /**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "GUISettingsMenu.hpp" +#include "Controls/DeviceHandler.hpp" +#include "settings/CSettings.h" +#include "prompts/PromptWindows.h" +#include "language/gettext.h" +#include "settings/SettingsPrompts.h" +#include "settings/GameTitles.h" +#include "settings/CGameCategories.hpp" +#include "SystemMenu/SystemMenuResources.h" +#include "system/IosLoader.h" +#include "usbloader/wbfs.h" +#include "themes/CTheme.h" +#include "utils/tools.h" + +static const char * OnOffText[MAX_ON_OFF] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ) +}; + +static const char * GameInfoText[GAMEINFO_MAX] = +{ + trNOOP( "Game ID" ), + trNOOP( "Game Region" ), + trNOOP( "Both" ), + trNOOP( "Neither" ) +}; + +static const char * FlipXText[XFLIP_MAX][3] = +{ + { trNOOP( "Right" ), "/", trNOOP( "Next" ) }, + { trNOOP( "Left" ), "/", trNOOP( "Prev" ) }, + { trNOOP( "Like SysMenu" ), "", "" }, + { trNOOP( "Right" ), "/", trNOOP( "Prev" ) }, + { trNOOP( "DiskFlip" ), "", "" } +}; + +static const char * PromptButtonsText[MAX_ON_OFF] = +{ + trNOOP( "Normal" ), + trNOOP( "Widescreen Fix" ), +}; + +static const char * GameWindowText[3] = +{ + trNOOP( "Banner Animation" ), + trNOOP( "Rotating Disc" ), + trNOOP( "Banner On Channels" ), +}; + +static const char * KeyboardText[KEYBOARD_MAX] = +{ + "QWERTY", + "DVORAK", + "QWERTZ", + "AZERTY", + "QWERTY 2" +}; + +static const char * DiscArtDownloadText[DISCARTS_MAX_CHOICE] = +{ + trNOOP( "Original/Customs" ), + trNOOP( "Customs/Original" ), + trNOOP( "Original" ), + trNOOP( "Customs" ) +}; + +static const char * CoversFullDownloadText[COVERSFULL_MAX_CHOICE] = +{ + trNOOP( "High Quality" ), + trNOOP( "Low Quality" ), + trNOOP( "High/Low" ), + trNOOP( "Low/High" ) +}; + +static const char *ScreensaverText[SCREENSAVER_MAX] = +{ + trNOOP( "OFF" ), + trNOOP( "3 min" ), + trNOOP( "5 min" ), + trNOOP( "10 min" ), + trNOOP( "20 min" ), + trNOOP( "30 min" ), + trNOOP( "1 hour" ) +}; + +static const char * BannerFavIconText[BANNER_FAVICON_MAX_CHOICE] = +{ + trNOOP( "OFF" ), + trNOOP( "Round" ), + trNOOP( "/\\/\\" ), + trNOOP( "Two Lines" ), + trNOOP( "One Line A" ), + trNOOP( "One Line B" ) +}; + +static const char * HomeMenuText[HOME_MENU_MAX_CHOICE] = +{ + trNOOP( "System Default" ), + trNOOP( "Full Menu" ), + trNOOP( "Default" ) +}; + +GuiSettingsMenu::GuiSettingsMenu() + : SettingsMenu(tr("GUI Settings"), &GuiOptions, MENU_NONE) +{ + int Idx = 0; + Options->SetName(Idx++, "%s", tr( "App Language" )); + Options->SetName(Idx++, "%s", tr( "Display" )); + Options->SetName(Idx++, "%s", tr( "Clock" )); + Options->SetName(Idx++, "%s", tr( "Clock Scale Factor" )); + Options->SetName(Idx++, "%s", tr( "Tooltips" )); + Options->SetName(Idx++, "%s", tr( "Tooltip Delay" )); + Options->SetName(Idx++, "%s", tr( "Flip-X" )); + Options->SetName(Idx++, "%s", tr( "Game Window Mode" )); + Options->SetName(Idx++, "%s", tr( "Prompts Buttons" )); + Options->SetName(Idx++, "%s", tr( "Widescreen Factor" )); + Options->SetName(Idx++, "%s", tr( "Font Scale Factor" )); + Options->SetName(Idx++, "%s", tr( "Keyboard" )); + Options->SetName(Idx++, "%s", tr( "Disc Artwork Download" )); + Options->SetName(Idx++, "%s", tr( "Full covers Download" )); + Options->SetName(Idx++, "%s", tr( "Screensaver" )); + Options->SetName(Idx++, "%s", tr( "Mark new games" )); + Options->SetName(Idx++, "%s", tr( "Show Play Count" )); + Options->SetName(Idx++, "%s", tr( "Show Favorite on banner" )); + Options->SetName(Idx++, "%s", tr( "Show Free Space" )); + Options->SetName(Idx++, "%s", tr( "HOME Menu" )); + Options->SetName(Idx++, "%s", tr( "Use System Font" )); + Options->SetName(Idx++, "%s", tr( "Virtual Pointer Speed" )); + Options->SetName(Idx++, "%s", tr( "Adjust Overscan X" )); + Options->SetName(Idx++, "%s", tr( "Adjust Overscan Y" )); + + SetOptionValues(); +} + +void GuiSettingsMenu::SetOptionValues() +{ + int Idx = 0; + + //! Settings: App Language + const char * language = strrchr(Settings.language_path, '/'); + if(language) + language += 1; + if (!language || strcmp(Settings.language_path, "") == 0) + Options->SetValue(Idx++, "%s", tr( "Default" )); + else + Options->SetValue(Idx++, "%s", language); + + //! Settings: Display + Options->SetValue(Idx++, "%s", tr( GameInfoText[Settings.sinfo] )); + + //! Settings: Clock + if (Settings.hddinfo == CLOCK_HR12) + Options->SetValue(Idx++, "12 %s", tr( "Hour" )); + else if (Settings.hddinfo == CLOCK_HR24) + Options->SetValue(Idx++, "24 %s", tr( "Hour" )); + else if (Settings.hddinfo == OFF) + Options->SetValue(Idx++, "%s", tr( "OFF" )); + + //! Settings: Clock Font Scale Factor + Options->SetValue(Idx++, "%g", Settings.ClockFontScaleFactor); + + //! Settings: Tooltips + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.tooltips])); + + //! Settings: Tooltip Delay + Options->SetValue(Idx++, "%i %s", Settings.TooltipDelay, tr("ms")); + + //! Settings: Flip-X + Options->SetValue(Idx++, "%s%s%s", tr(FlipXText[Settings.xflip][0]), + FlipXText[Settings.xflip][1], tr( FlipXText[Settings.xflip][2] )); + + //! Settings: Game Window Mode + Options->SetValue(Idx++, "%s", tr( GameWindowText[Settings.GameWindowMode] )); + + //! Settings: Prompts Buttons + Options->SetValue(Idx++, "%s", tr( PromptButtonsText[Settings.wsprompt] )); + + //! Settings: Widescreen Factor + Options->SetValue(Idx++, "%g", Settings.WSFactor); + + //! Settings: Font Scale Factor + Options->SetValue(Idx++, "%g", Settings.FontScaleFactor); + + //! Settings: Keyboard + Options->SetValue(Idx++, "%s", KeyboardText[Settings.keyset]); + + //! Settings: Disc Artwork Download + Options->SetValue(Idx++, "%s", tr( DiscArtDownloadText[Settings.discart] )); + + //! Settings: Covers Full Artwork Download + Options->SetValue(Idx++, "%s", tr( CoversFullDownloadText[Settings.coversfull] )); + + //! Settings: Screensaver + Options->SetValue(Idx++, "%s", tr( ScreensaverText[Settings.screensaver] )); + + //! Settings: Mark new games + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.marknewtitles] )); + + //! Settings: Show Play Count + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.ShowPlayCount] )); + + //! Settings: Show Favorite on banner window + Options->SetValue(Idx++, "%s", tr( BannerFavIconText[Settings.bannerFavIcon] )); + + //! Settings: Show Free Space + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.ShowFreeSpace] )); + + //! Settings: Home Menu style + Options->SetValue(Idx++, "%s", tr( HomeMenuText[Settings.HomeMenu] )); + + //! Settings: Use System Font + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.UseSystemFont] )); + + //! Settings: Virtual Pointer Speed + Options->SetValue(Idx++, "%g", Settings.PointerSpeed); + + //! Settings: Adjust Overscan X + Options->SetValue(Idx++, "%i", Settings.AdjustOverscanX); + + //! Settings: Adjust Overscan Y + Options->SetValue(Idx++, "%i", Settings.AdjustOverscanY); +} + +int GuiSettingsMenu::GetMenuInternal() +{ + int ret = optionBrowser->GetClickedOption(); + + if (ret < 0) + return MENU_NONE; + + int Idx = -1; + + //! Settings: App Language + if (ret == ++Idx) + { + if (!Settings.godmode) + { + WindowPrompt(tr( "Language change:" ), tr( "Console should be unlocked to modify it." ), tr( "OK" )); + return MENU_NONE; + } + SetEffect(EFFECT_FADE, -20); + while (GetEffect() > 0) usleep(100); + HaltGui(); + if(parentElement) + { + ((GuiWindow *) parentElement)->Remove(this); + ((GuiWindow *) parentElement)->SetState(STATE_DISABLED); + } + ResumeGui(); + + int returnhere = 1; + while (returnhere == 1) + returnhere = MenuLanguageSelect(); + + if (returnhere == 2) + { + //! Language changed. Reload game titles with new lang code. + GameTitles.SetDefault(); + GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path); + return MENU_SETTINGS; + } + + HaltGui(); + if(parentElement) + { + ((GuiWindow *) parentElement)->Append(this); + ((GuiWindow *) parentElement)->SetState(STATE_DEFAULT); + } + SetEffect(EFFECT_FADE, 20); + ResumeGui(); + while (GetEffect() > 0) usleep(100); + } + + //! Settings: Display + else if (ret == ++Idx) + { + if (++Settings.sinfo >= GAMEINFO_MAX) Settings.sinfo = 0; + } + + //! Settings: Clock + else if (ret == ++Idx) + { + if (++Settings.hddinfo >= CLOCK_MAX) Settings.hddinfo = 0; //CLOCK + } + + //! Settings: Clock Font Scale Factor + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%g", Settings.ClockFontScaleFactor); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.ClockFontScaleFactor = LIMIT(atof(entrie), 0.01f, 1.5f); + } + + //! Settings: Tooltips + else if (ret == ++Idx) + { + if (++Settings.tooltips >= MAX_ON_OFF) Settings.tooltips = 0; + } + + //! Settings: Tooltip Delay + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%i", Settings.TooltipDelay); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.TooltipDelay = atoi(entrie); + } + + //! Settings: Flip-X + else if (ret == ++Idx) + { + if (++Settings.xflip >= XFLIP_MAX) Settings.xflip = 0; + } + + //! Settings: Game Window Mode + else if (ret == ++Idx) + { + if (++Settings.GameWindowMode >= 3) Settings.GameWindowMode = 0; + + if(Settings.GameWindowMode != GAMEWINDOW_DISC && !SystemMenuResources::Instance()->IsLoaded()) { + WindowPrompt(tr( "Error:" ), tr( "Banner window is only available with AHBPROT! Please consider installing new HBC version." ), tr( "OK" )); + Settings.GameWindowMode = GAMEWINDOW_DISC; + } + } + + //! Settings: Prompts Buttons + else if (ret == ++Idx) + { + if (++Settings.wsprompt >= MAX_ON_OFF) Settings.wsprompt = 0; + } + + //! Settings: Widescreen Factor + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%g", Settings.WSFactor); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.WSFactor = LIMIT(atof(entrie), 0.01f, 1.5f); + } + + //! Settings: Font Scale Factor + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%g", Settings.FontScaleFactor); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.FontScaleFactor = LIMIT(atof(entrie), 0.01f, 1.5f); + } + + //! Settings: Keyboard + else if (ret == ++Idx) + { + if (++Settings.keyset >= KEYBOARD_MAX) Settings.keyset = 0; + } + + //! Settings: Disc Artwork Download + else if (ret == ++Idx) + { + if (++Settings.discart >= DISCARTS_MAX_CHOICE) Settings.discart = 0; + } + + //! Settings: Covers Full Artwork Download + else if (ret == ++Idx) + { + if (++Settings.coversfull >= COVERSFULL_MAX_CHOICE) Settings.coversfull = 0; + } + + //! Settings: Screensaver + else if (ret == ++Idx) + { + if (++Settings.screensaver >= SCREENSAVER_MAX) Settings.screensaver = 0; + + SetWPADTimeout(); + } + + //! Settings: Mark new games + else if (ret == ++Idx) + { + if (++Settings.marknewtitles >= MAX_ON_OFF) Settings.marknewtitles = 0; + } + + //! Settings: Show Play Count + else if (ret == ++Idx) + { + if (++Settings.ShowPlayCount >= MAX_ON_OFF) Settings.ShowPlayCount = 0; + } + + //! Settings: Show favorite on banner window + else if (ret == ++Idx) + { + if (++Settings.bannerFavIcon >= BANNER_FAVICON_MAX_CHOICE) Settings.bannerFavIcon = 0; + } + + //! Settings: Show Free Space + else if (ret == ++Idx) + { + if (++Settings.ShowFreeSpace >= MAX_ON_OFF) Settings.ShowFreeSpace = 0; + } + + //! Settings: Home Menu Style + else if (ret == ++Idx) + { + if (++Settings.HomeMenu >= HOME_MENU_MAX_CHOICE) Settings.HomeMenu = 0; + } + + //! Settings: Use System Font + else if (ret == ++Idx) + { + if (++Settings.UseSystemFont >= MAX_ON_OFF) Settings.UseSystemFont = 0; + + HaltGui(); + Theme::LoadFont(Settings.ConfigPath); + ResumeGui(); + + if(Settings.FontScaleFactor == 1.0f && Settings.UseSystemFont == ON) + Settings.FontScaleFactor = 0.8f; + else if(Settings.FontScaleFactor == 0.8f && Settings.UseSystemFont == OFF) + Settings.FontScaleFactor = 1.0f; + } + + //! Settings: Virtual Pointer Speed + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%g", Settings.PointerSpeed); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.PointerSpeed = atof(entrie); + } + + //! Settings: Adjust Overscan X + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%i", Settings.AdjustOverscanX); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + { + Settings.AdjustOverscanX = atoi(entrie); + AdjustOverscan(Settings.AdjustOverscanX, Settings.AdjustOverscanY); + } + } + + //! Settings: Adjust Overscan Y + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%i", Settings.AdjustOverscanY); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + { + Settings.AdjustOverscanY = atoi(entrie); + AdjustOverscan(Settings.AdjustOverscanX, Settings.AdjustOverscanY); + } + } + + + SetOptionValues(); + + return MENU_NONE; +} diff --git a/source/settings/menus/GUISettingsMenu.hpp b/source/settings/menus/GUISettingsMenu.hpp new file mode 100644 index 0000000..dea94e1 --- /dev/null +++ b/source/settings/menus/GUISettingsMenu.hpp @@ -0,0 +1,41 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GUISETTINGS_MENU_HPP_ +#define GUISETTINGS_MENU_HPP_ + +#include "SettingsMenu.hpp" + +class GuiSettingsMenu : public SettingsMenu +{ + public: + GuiSettingsMenu(); + protected: + void SetOptionValues(); + int GetMenuInternal(); + + OptionList GuiOptions; +}; + + +#endif diff --git a/source/settings/menus/GameLoadSM.cpp b/source/settings/menus/GameLoadSM.cpp new file mode 100644 index 0000000..7a440ff --- /dev/null +++ b/source/settings/menus/GameLoadSM.cpp @@ -0,0 +1,641 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include "settings/CSettings.h" +#include "settings/CGameStatistics.h" +#include "themes/CTheme.h" +#include "prompts/PromptWindows.h" +#include "prompts/DiscBrowser.h" +#include "prompts/filebrowser.h" +#include "usbloader/AlternateDOLOffsets.h" +#include "language/gettext.h" +#include "wad/nandtitle.h" +#include "system/IosLoader.h" +#include "GameLoadSM.hpp" + +static const char * OnOffText[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ), + trNOOP( "Auto" ) +}; + +static const char * VideoModeText[] = +{ + trNOOP( "System Default" ), + trNOOP( "Disc Default" ), + trNOOP( "Force PAL50" ), + trNOOP( "Force PAL60" ), + trNOOP( "Force NTSC" ), + trNOOP( "Region Patch" ), + trNOOP( "Force PAL480p" ), + trNOOP( "Force NTSC480p" ), +}; + +static const char * VideoPatchDolText[] = +{ + trNOOP( "OFF" ), + trNOOP( "Region Patch" ), + trNOOP( "ON" ), + trNOOP( "All" ), +}; + +static const char * AspectText[] = +{ + trNOOP( "Force 4:3" ), + trNOOP( "Force 16:9" ), + trNOOP( "System Default" ) +}; + +static const char * LanguageText[] = +{ + trNOOP( "Japanese" ), + trNOOP( "English" ), + trNOOP( "German" ), + trNOOP( "French" ), + trNOOP( "Spanish" ), + trNOOP( "Italian" ), + trNOOP( "Dutch" ), + trNOOP( "SChinese" ), + trNOOP( "TChinese" ), + trNOOP( "Korean" ), + trNOOP( "Console Default" ), +}; + +static const char * ParentalText[] = +{ + trNOOP( "0 (Everyone)" ), + trNOOP( "1 (Child 7+)" ), + trNOOP( "2 (Teen 12+)" ), + trNOOP( "3 (Mature 16+)" ), + trNOOP( "4 (Adults Only 18+)" ) +}; + +static const char * AlternateDOLText[] = +{ + trNOOP( "OFF" ), + trNOOP( "Select a DOL from Game" ), + trNOOP( "Load From SD/USB" ), + trNOOP( "List on Gamelaunch" ), + trNOOP( "Default" ), +}; + +static const char * NandEmuText[] = +{ + trNOOP( "OFF" ), + trNOOP( "Partial" ), + trNOOP( "Full" ), + trNOOP( "Neek" ) +}; + +static const char * HooktypeText[] = +{ + trNOOP( "None" ), + trNOOP( "VBI (Default)" ), + trNOOP( "KPAD Read" ), + trNOOP( "Joypad" ), + trNOOP( "GXDraw" ), + trNOOP( "GXFlush" ), + trNOOP( "OSSleepThread" ), + trNOOP( "AXNextFrame" ), +}; + +static const char * PrivServText[] = +{ + trNOOP( "OFF" ), + trNOOP( "NoSSL only" ), + trNOOP( "Wiimmfi.de" ), +}; + +GameLoadSM::GameLoadSM(struct discHdr *hdr) + : SettingsMenu(tr("Game Load"), &GuiOptions, MENU_NONE), + Header(hdr) +{ + GameConfig = *GameSettings.GetGameCFG((const char *) Header->id); + + if(!btnOutline) + btnOutline = Resources::GetImageData("button_dialogue_box.png"); + if(!trigA) + trigA = new GuiTrigger(); + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + saveBtnTxt = new GuiText(tr( "Save" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + saveBtnTxt->SetMaxWidth(btnOutline->GetWidth() - 30); + saveBtnImg = new GuiImage (btnOutline); + if (Settings.wsprompt == ON) + { + saveBtnTxt->SetWidescreen(Settings.widescreen); + saveBtnImg->SetWidescreen(Settings.widescreen); + } + saveBtn = new GuiButton(saveBtnImg, saveBtnImg, 2, 3, 180, 400, trigA, btnSoundOver, btnSoundClick2, 1); + saveBtn->SetLabel(saveBtnTxt); + Append(saveBtn); + + SetOptionNames(); + SetOptionValues(); +} + +GameLoadSM::~GameLoadSM() +{ + HaltGui(); + //! The rest is destroyed in SettingsMenu.cpp + Remove(saveBtn); + delete saveBtnTxt; + delete saveBtnImg; + delete saveBtn; + ResumeGui(); +} + +void GameLoadSM::SetDefaultConfig() +{ + char id[7]; + snprintf(id, sizeof(id), GameConfig.id); + GameSettings.SetDefault(GameConfig); + snprintf(GameConfig.id, sizeof(GameConfig.id), id); +} + +void GameLoadSM::SetOptionNames() +{ + int Idx = 0; + + Options->SetName(Idx++, "%s", tr( "Game Lock" )); + Options->SetName(Idx++, "%s", tr( "Favorite Level" )); + Options->SetName(Idx++, "%s", tr( "Video Mode" )); + Options->SetName(Idx++, "%s", tr( "Dol Video Patch" )); + Options->SetName(Idx++, "%s", tr( "480p Pixel Fix Patch" )); + Options->SetName(Idx++, "%s", tr( "Sneek Video Patch" )); + Options->SetName(Idx++, "%s", tr( "VIDTV Patch" )); + Options->SetName(Idx++, "%s", tr( "Aspect Ratio" )); + Options->SetName(Idx++, "%s", tr( "Patch Country Strings" )); + Options->SetName(Idx++, "%s", tr( "Game Language" )); + Options->SetName(Idx++, "%s", tr( "Ocarina" )); + Options->SetName(Idx++, "%s", tr( "Private Server" )); + Options->SetName(Idx++, "%s", tr( "Parental Control" )); + Options->SetName(Idx++, "%s", tr( "Hooktype" )); + Options->SetName(Idx++, "%s", tr( "Wiird Debugger" )); + Options->SetName(Idx++, "%s", tr( "Game IOS" )); + Options->SetName(Idx++, "%s", tr( "Return To" )); + Options->SetName(Idx++, "%s", tr( "Block IOS Reload" )); + + //! Only wii games and emu nand channels + if( Header->type == TYPE_GAME_WII_IMG + || Header->type == TYPE_GAME_WII_DISC + || Header->type == TYPE_GAME_EMUNANDCHAN) + { + Options->SetName(Idx++, "%s", tr( "Nand Emulation" )); + Options->SetName(Idx++, "%s", tr( "Nand Emu Path" )); + } + + //! Only on Wii games + if(Header->type == TYPE_GAME_WII_IMG || Header->type == TYPE_GAME_WII_DISC) + { + Options->SetName(Idx++, "%s", tr( "Alternate DOL" )); + Options->SetName(Idx++, "%s", tr( "Select DOL Offset" )); + } +} + +void GameLoadSM::SetOptionValues() +{ + int Idx = 0; + + //! Settings: Game Lock + Options->SetValue(Idx++, "%s", tr( OnOffText[GameConfig.Locked] )); + + //! Settings: Favorite Level + Options->SetValue(Idx++, "%i", GameStatistics.GetFavoriteRank(Header->id)); + + //! Settings: Video Mode + if(GameConfig.video == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(VideoModeText[GameConfig.video])); + + //! Settings: Dol Video Patch + if(GameConfig.videoPatchDol == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(VideoPatchDolText[GameConfig.videoPatchDol])); + + //! Settings: 480p Pixel Fix Patch + if(GameConfig.patchFix480p == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.patchFix480p])); + + //! Settings: Sneek Video Patch + if(GameConfig.sneekVideoPatch == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.sneekVideoPatch])); + + //! Settings: VIDTV Patch + if(GameConfig.vipatch == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.vipatch])); + + //! Settings: Aspect Ratio + if(GameConfig.aspectratio == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(AspectText[GameConfig.aspectratio])); + + //! Settings: Patch Country Strings + if(GameConfig.patchcountrystrings == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.patchcountrystrings])); + + //! Settings: Game Language + if(GameConfig.language == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(LanguageText[GameConfig.language])); + + //! Settings: Ocarina + if(GameConfig.ocarina == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(OnOffText[GameConfig.ocarina])); + + //! Settings: Private Server + if(GameConfig.PrivateServer == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr(PrivServText[GameConfig.PrivateServer])); + + //! Settings: Parental Control + Options->SetValue(Idx++, "%s", tr(ParentalText[GameConfig.parentalcontrol])); + + //! Settings: Hooktype + if(GameConfig.Hooktype == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr( HooktypeText[GameConfig.Hooktype] )); + + //! Settings: Wiird Debugger + if(GameConfig.WiirdDebugger == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr( OnOffText[GameConfig.WiirdDebugger] )); + + //! Settings: Game IOS + if(GameConfig.ios == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%i", GameConfig.ios); + + //! Settings: Return To + if(Header->type == TYPE_GAME_EMUNANDCHAN && EMUNAND_NEEK == (GameConfig.NandEmuMode == INHERIT ? Settings.NandEmuChanMode : GameConfig.NandEmuMode)) + { + Options->SetValue(Idx++, "%s", tr( OnOffText[GameConfig.returnTo] )); + } + else if(GameConfig.returnTo) + { + const char* TitleName = NULL; + u64 tid = NandTitles.FindU32(Settings.returnTo); + if (tid > 0) + TitleName = NandTitles.NameOf(tid); + Options->SetValue(Idx++, "%s", TitleName ? TitleName : strlen(Settings.returnTo) > 0 ? + Settings.returnTo : tr( OnOffText[0] )); + } + else + { + Options->SetValue(Idx++, "%s", tr( OnOffText[0] )); + } + + //! Settings: Block IOS Reload + if(GameConfig.iosreloadblock == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr( OnOffText[GameConfig.iosreloadblock]) ); + + //! Only wii games and emu nand channels + if( Header->type == TYPE_GAME_WII_IMG + || Header->type == TYPE_GAME_WII_DISC + || Header->type == TYPE_GAME_EMUNANDCHAN) + { + //! Settings: Nand Emulation + if(GameConfig.NandEmuMode == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", tr( NandEmuText[GameConfig.NandEmuMode] )); + + //! Settings: Nand Emu Path + if(GameConfig.NandEmuPath.size() == 0) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%s", GameConfig.NandEmuPath.c_str()); + } + + //! Only on Wii games + if(Header->type == TYPE_GAME_WII_IMG || Header->type == TYPE_GAME_WII_DISC) + { + //! Settings: Alternate DOL + Options->SetValue(Idx++, "%s", tr( AlternateDOLText[GameConfig.loadalternatedol] )); + + //! Settings: Select DOL Offset + if(GameConfig.loadalternatedol != 1) + Options->SetValue(Idx++, tr("Not required")); + else + { + if(GameConfig.alternatedolname.size() != 0) + Options->SetValue(Idx++, "%i <%s>", (int)GameConfig.alternatedolstart, GameConfig.alternatedolname.c_str()); + else + Options->SetValue(Idx++, "%i", (int)GameConfig.alternatedolstart); + } + } +} + +int GameLoadSM::GetMenuInternal() +{ + if (saveBtn->GetState() == STATE_CLICKED) + { + if (GameSettings.AddGame(GameConfig) && GameSettings.Save()) + { + WindowPrompt(tr( "Successfully Saved" ), 0, tr( "OK" )); + } + else + WindowPrompt(tr( "Save Failed. No device inserted?" ), 0, tr( "OK" )); + + saveBtn->ResetState(); + } + + int ret = optionBrowser->GetClickedOption(); + + if (ret < 0) + return MENU_NONE; + + int Idx = -1; + + //! Settings: Game Lock + if (ret == ++Idx) + { + if (++GameConfig.Locked >= MAX_ON_OFF) GameConfig.Locked = 0; + } + + //! Settings: Favorite Level + else if (ret == ++Idx) + { + int Level = GameStatistics.GetFavoriteRank(Header->id); + if (++Level > 5) Level = 0; + + GameStatistics.SetFavoriteRank(Header->id, Level); + GameStatistics.Save(); + } + + //! Settings: Video Mode + else if (ret == ++Idx) + { + if (++GameConfig.video >= VIDEO_MODE_MAX) GameConfig.video = INHERIT; + } + + //! Settings: Dol Video Patch + else if (ret == ++Idx) + { + if (++GameConfig.videoPatchDol >= VIDEO_PATCH_DOL_MAX) GameConfig.videoPatchDol = INHERIT; + } + + //! Settings: 480p Pixel Fix Patch + else if (ret == ++Idx) + { + if (++GameConfig.patchFix480p >= MAX_ON_OFF) GameConfig.patchFix480p = INHERIT; + } + + //! Settings: Sneek Video Patch + else if (ret == ++Idx) + { + if (++GameConfig.sneekVideoPatch >= MAX_ON_OFF) GameConfig.sneekVideoPatch = INHERIT; + } + + //! Settings: VIDTV Patch + if (ret == ++Idx) + { + if (++GameConfig.vipatch >= MAX_ON_OFF) GameConfig.vipatch = INHERIT; + } + + //! Settings: Aspect Ratio + else if (ret == ++Idx) + { + if (++GameConfig.aspectratio >= ASPECT_MAX) GameConfig.aspectratio = INHERIT; + } + + //! Settings: Patch Country Strings + if (ret == ++Idx) + { + if (++GameConfig.patchcountrystrings >= MAX_ON_OFF) GameConfig.patchcountrystrings = INHERIT; + } + + //! Settings: Game Language + if (ret == ++Idx) + { + if (++GameConfig.language >= MAX_LANGUAGE) GameConfig.language = INHERIT; + } + + //! Settings: Ocarina + else if (ret == ++Idx) + { + if (++GameConfig.ocarina >= MAX_ON_OFF) GameConfig.ocarina = INHERIT; + } + + //! Settings: Private Server + else if (ret == ++Idx) + { + if (++GameConfig.PrivateServer >= PRIVSERV_MAX_CHOICE) GameConfig.PrivateServer = INHERIT; + } + + //! Settings: Parental Control + else if (ret == ++Idx) + { + if (++GameConfig.parentalcontrol >= 5) GameConfig.parentalcontrol = 0; + } + + //! Settings: Hooktype + if (ret == ++Idx) + { + if (++GameConfig.Hooktype >= 8) GameConfig.Hooktype = INHERIT; + } + + //! Settings: Wiird Debugger + else if (ret == ++Idx) + { + if (++GameConfig.WiirdDebugger >= MAX_ON_OFF) GameConfig.WiirdDebugger = INHERIT; + } + + //! Settings: Game IOS + else if (ret == ++Idx) + { + char entered[4]; + snprintf(entered, sizeof(entered), "%i", GameConfig.ios); + if(OnScreenNumpad(entered, sizeof(entered))) + { + int newIOS = atoi(entered); + + if(newIOS != INHERIT && (newIOS < 200 || newIOS > 255)) { + WindowPrompt(tr("Error:"), tr("Invalid IOS number entered. Number must be -1 for inherit or 200 - 255."), tr("OK")); + } + else + { + GameConfig.ios = newIOS; + + if(GameConfig.ios != INHERIT && NandTitles.IndexOf(TITLE_ID(1, GameConfig.ios)) < 0) + { + WindowPrompt(tr("Warning:"), tr("This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning."), tr("OK")); + } + else if(GameConfig.ios == 254) + { + WindowPrompt(tr("Warning:"), tr("This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning."), tr("OK")); + } + } + } + } + + //! Settings: Return To + else if (ret == ++Idx) + { + if (++GameConfig.returnTo >= MAX_ON_OFF) GameConfig.returnTo = 0; + } + + //! Settings: Block IOS Reload + if (ret == ++Idx) + { + if(++GameConfig.iosreloadblock >= 3) GameConfig.iosreloadblock = INHERIT; + } + + //! Only wii games and emu nand channels + if( Header->type == TYPE_GAME_WII_IMG + || Header->type == TYPE_GAME_WII_DISC + || Header->type == TYPE_GAME_EMUNANDCHAN) + { + //! Settings: Nand Emulation + if (ret == ++Idx) + { + if (++GameConfig.NandEmuMode >= EMUNAND_MAX) GameConfig.NandEmuMode = INHERIT; + + // neek available only for EmuNAND Channels + if(Header->type != TYPE_GAME_EMUNANDCHAN && GameConfig.NandEmuMode >= EMUNAND_NEEK) + GameConfig.NandEmuMode = INHERIT; + + //! On titles from emulated nand path disabling the nand emu mode is not allowed + if(Header->type == TYPE_GAME_EMUNANDCHAN && GameConfig.NandEmuMode == OFF) + GameConfig.NandEmuMode = 1; + } + + //! Settings: Nand Emu Path + else if (ret == ++Idx) + { + // If NandEmuPath is on root of the first FAT32 partition, allow rev17-21 cIOS for EmuNAND Channels + bool NandEmu_compatible = false; + if(Header->type == TYPE_GAME_EMUNANDCHAN) + { + NandEmu_compatible = IosLoader::is_NandEmu_compatible(NULL, GameConfig.ios == INHERIT ? Settings.cios : GameConfig.ios); + } + + if(!IosLoader::IsD2X(GameConfig.ios == INHERIT ? Settings.cios : GameConfig.ios) && !NandEmu_compatible) + WindowPrompt(tr("Error:"), tr("Nand Emulation is only available on D2X cIOS!"), tr("OK")); + else + { + char entered[300]; + snprintf(entered, sizeof(entered), GameConfig.NandEmuPath.c_str()); + + HaltGui(); + GuiWindow * parent = (GuiWindow *) parentElement; + if(parent) parent->SetState(STATE_DISABLED); + this->SetState(STATE_DEFAULT); + this->Remove(optionBrowser); + ResumeGui(); + + int result = BrowseDevice(entered, sizeof(entered), FB_DEFAULT, noFILES); + + if(parent) parent->SetState(STATE_DEFAULT); + this->Append(optionBrowser); + + if (result == 1) + { + if (entered[strlen(entered)-1] != '/') + strcat(entered, "/"); + + GameConfig.NandEmuPath = entered; + WindowPrompt(tr( "Path Changed" ), 0, tr( "OK" )); + } + } + } + } + + //! Only on Wii games + if(Header->type == TYPE_GAME_WII_IMG || Header->type == TYPE_GAME_WII_DISC) + { + //! Settings: Alternate DOL + if (ret == ++Idx) + { + if (++GameConfig.loadalternatedol >= ALT_DOL_MAX_CHOICE) + GameConfig.loadalternatedol = 0; + } + + //! Settings: Select DOL Offset from Game + else if ( (ret == ++Idx) + && (GameConfig.loadalternatedol == 1)) + { + GuiWindow * parentWindow = (GuiWindow *) parentElement; + if(parentWindow) parentWindow->SetState(STATE_DISABLED); + //alt dol menu for games that require more than a single alt dol + int autodol = autoSelectDolPrompt((char *) GameConfig.id); + if(autodol == 0) + { + if(parentWindow) parentWindow->SetState(STATE_DEFAULT); + return MENU_NONE; //Cancel Button pressed + } + + char tmp[170]; + + if (autodol > 0) + { + GameConfig.alternatedolstart = autodol; + snprintf(tmp, sizeof(tmp), "%s <%i>", tr( "AUTO" ), autodol); + GameConfig.alternatedolname = tmp; + SetOptionValues(); + if(parentWindow) parentWindow->SetState(STATE_DEFAULT); + return MENU_NONE; + } + + int res = DiscBrowse(GameConfig.id, tmp, sizeof(tmp)); + if (res >= 0) + { + GameConfig.alternatedolname = tmp; + GameConfig.alternatedolstart = res; + snprintf(tmp, sizeof(tmp), "%s %.6s - %i", tr( "It seems that you have some information that will be helpful to us. Please pass this information along to the DEV team." ), (char *) GameConfig.id, (int)GameConfig.alternatedolstart); + WindowPrompt(0, tmp, tr( "OK" )); + } + + if(GameConfig.alternatedolstart == 0) + GameConfig.loadalternatedol = 0; + if(parentWindow) parentWindow->SetState(STATE_DEFAULT); + } + } + + SetOptionValues(); + + return MENU_NONE; +} diff --git a/source/settings/menus/GameLoadSM.hpp b/source/settings/menus/GameLoadSM.hpp new file mode 100644 index 0000000..3764360 --- /dev/null +++ b/source/settings/menus/GameLoadSM.hpp @@ -0,0 +1,51 @@ + /**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GAMELOAD_SM_HPP +#define GAMELOAD_SM_HPP + +#include "SettingsMenu.hpp" +#include "settings/CGameSettings.h" + +class GameLoadSM : public SettingsMenu +{ + public: + GameLoadSM(struct discHdr *Header); + virtual ~GameLoadSM(); + protected: + void SetDefaultConfig(); + void SetOptionNames(); + void SetOptionValues(); + int GetMenuInternal(); + + struct discHdr *Header; + GameCFG GameConfig; + OptionList GuiOptions; + + GuiText * saveBtnTxt; + GuiImage * saveBtnImg; + GuiButton * saveBtn; +}; + + +#endif diff --git a/source/settings/menus/GameSettingsMenu.cpp b/source/settings/menus/GameSettingsMenu.cpp new file mode 100644 index 0000000..9c2b0c2 --- /dev/null +++ b/source/settings/menus/GameSettingsMenu.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "GameSettingsMenu.hpp" +#include "themes/CTheme.h" +#include "FileOperations/fileops.h" +#include "prompts/PromptWindows.h" +#include "prompts/ProgressWindow.h" +#include "prompts/CategorySelectPrompt.hpp" +#include "settings/GameTitles.h" +#include "usbloader/GameList.h" +#include "language/gettext.h" +#include "wad/nandtitle.h" +#include "cheats/cheatmenu.h" +#include "GameLoadSM.hpp" +#include "GCGameLoadSM.hpp" +#include "UninstallSM.hpp" + +GameSettingsMenu::GameSettingsMenu(GameBrowseMenu *parent, struct discHdr * header) + : FlyingButtonsMenu(GameTitles.GetTitle(header)), browserMenu(parent) +{ + DiscHeader = header; + //! Don't switch menu's by default but return to disc window. + ParentMenu = -2; +} + +GameSettingsMenu::~GameSettingsMenu() +{ +} + +int GameSettingsMenu::Execute(GameBrowseMenu *parent, struct discHdr * header) +{ + GameSettingsMenu * Menu = new GameSettingsMenu(parent, header); + mainWindow->Append(Menu); + + Menu->ShowMenu(); + + int returnMenu = MENU_NONE; + + while((returnMenu = Menu->MainLoop()) == MENU_NONE); + + delete Menu; + + return returnMenu; +} + +void GameSettingsMenu::SetupMainButtons() +{ + int pos = 0; + + SetMainButton(pos++, tr( "Game Load" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Ocarina" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Categories" ), MainButtonImgData, MainButtonImgOverData); + if( DiscHeader->type == TYPE_GAME_WII_IMG + || DiscHeader->type == TYPE_GAME_WII_DISC + || DiscHeader->type == TYPE_GAME_NANDCHAN) + { + SetMainButton(pos++, tr( "Extract Save to EmuNand" ), MainButtonImgData, MainButtonImgOverData); + } + SetMainButton(pos++, tr( "Default Gamesettings" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Uninstall Menu" ), MainButtonImgData, MainButtonImgOverData); +} + +void GameSettingsMenu::CreateSettingsMenu(int menuNr) +{ + if(CurrentMenu) + return; + + int Idx = 0; + + //! Game Load + if(menuNr == Idx++) + { + HideMenu(); + ResumeGui(); + if( DiscHeader->type == TYPE_GAME_GC_IMG + || DiscHeader->type == TYPE_GAME_GC_DISC + || DiscHeader->type == TYPE_GAME_GC_EXTRACTED) + { + CurrentMenu = new GCGameLoadSM(DiscHeader); + } + else + { + CurrentMenu = new GameLoadSM(DiscHeader); + } + Append(CurrentMenu); + } + + //! Ocarina + else if(menuNr == Idx++) + { + char ID[7]; + snprintf(ID, sizeof(ID), "%s", (char *) DiscHeader->id); + CheatMenu(ID); + } + + //! Categories + else if(menuNr == Idx++) + { + if (!Settings.godmode && (Settings.ParentalBlocks & BLOCK_CATEGORIES_MENU)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + HideMenu(); + Remove(backBtn); + ResumeGui(); + mainWindow->SetState(STATE_DISABLED); + CategorySelectPrompt promptMenu(DiscHeader); + promptMenu.SetAlignment(thAlign("center - category game prompt align hor"), thAlign("middle - category game prompt align ver")); + promptMenu.SetPosition(thInt("0 - category game prompt pos x"), thInt("0 - category game prompt pos y")); + promptMenu.SetEffect(EFFECT_FADE, 20); + mainWindow->Append(&promptMenu); + + promptMenu.Show(); + + promptMenu.SetEffect(EFFECT_FADE, -20); + while(promptMenu.GetEffect() > 0) usleep(100); + mainWindow->Remove(&promptMenu); + if(promptMenu.categoriesChanged()) + { + gameList.FilterList(); + browserMenu->ReloadBrowser(); + } + mainWindow->SetState(STATE_DEFAULT); + Append(backBtn); + ShowMenu(); + } + + //! Extract Save to EmuNand + else if( (DiscHeader->type == TYPE_GAME_WII_IMG + || DiscHeader->type == TYPE_GAME_WII_DISC + || DiscHeader->type == TYPE_GAME_NANDCHAN) + && menuNr == Idx++) + { + int choice = WindowPrompt(tr( "Do you want to extract the save game?" ), tr("The save game will be extracted to your emu nand path."), tr( "Yes" ), tr( "Cancel" )); + if (choice == 1) + { + char filePath[512]; + char nandPath[512]; + if(DiscHeader->tid != 0) //! Channels + { + snprintf(nandPath, sizeof(nandPath), "/title/%08x/%08x/data", (unsigned int) (DiscHeader->tid >> 32), (unsigned int) DiscHeader->tid); + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuChanPath, nandPath); + } + else //! Wii games + { + snprintf(nandPath, sizeof(nandPath), "/title/00010000/%02x%02x%02x%02x", DiscHeader->id[0], DiscHeader->id[1], DiscHeader->id[2], DiscHeader->id[3]); + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuPath, nandPath); + } + + ProgressCancelEnable(true); + StartProgress(tr("Extracting file:"), 0, 0, true, false); + int ret = NandTitle::ExtractDir(nandPath, filePath); + + if(ret < 0) //! Games with installable channels: Mario Kart, Wii Fit, etc. + { + snprintf(nandPath, sizeof(nandPath), "/title/00010004/%02x%02x%02x%02x", DiscHeader->id[0], DiscHeader->id[1], DiscHeader->id[2], DiscHeader->id[3]); + snprintf(filePath, sizeof(filePath), "%s%s", Settings.NandEmuPath, nandPath); + ret = NandTitle::ExtractDir(nandPath, filePath); + } + + //! extract the Mii file if not yet done + snprintf(nandPath, sizeof(nandPath), "/shared2/menu/FaceLib/RFL_DB.dat"); + snprintf(filePath, sizeof(filePath), "%s%s", (DiscHeader->tid != 0) ? Settings.NandEmuChanPath : Settings.NandEmuPath, nandPath); + if(!CheckFile(filePath)) + NandTitle::ExtractDir(nandPath, filePath); + + ProgressStop(); + ProgressCancelEnable(false); + + if(ret < 0) + WindowPrompt(tr("Error:"), tr("Failed to extract all files. Savegame might not exist."), tr("OK")); + else + WindowPrompt(tr("Files extracted successfully."), 0, tr("OK")); + } + } + + //! Default Gamesettings + else if(menuNr == Idx++) + { + int choice = WindowPrompt(tr( "Are you sure?" ), 0, tr( "Yes" ), tr( "Cancel" )); + if (choice == 1) + { + GameSettings.Remove(DiscHeader->id); + GameSettings.Save(); + } + } + + //! Uninstall Menu + else if(menuNr == Idx++) + { + HideMenu(); + ResumeGui(); + CurrentMenu = new UninstallSM(DiscHeader); + Append(CurrentMenu); + } +} + +void GameSettingsMenu::DeleteSettingsMenu() +{ + delete CurrentMenu; + CurrentMenu = NULL; +} diff --git a/source/settings/menus/GameSettingsMenu.hpp b/source/settings/menus/GameSettingsMenu.hpp new file mode 100644 index 0000000..683f9ab --- /dev/null +++ b/source/settings/menus/GameSettingsMenu.hpp @@ -0,0 +1,47 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GAMESETTINGSMENU_HPP_ +#define GAMESETTINGSMENU_HPP_ + +#include "FlyingButtonsMenu.hpp" +#include "settings/CGameSettings.h" +#include "menu/GameBrowseMenu.hpp" +#include "usbloader/disc.h" + +class GameSettingsMenu : public FlyingButtonsMenu +{ + public: + GameSettingsMenu(GameBrowseMenu *parent, struct discHdr * header); + virtual ~GameSettingsMenu(); + static int Execute(GameBrowseMenu *parent, struct discHdr *header); + protected: + virtual void CreateSettingsMenu(int index); + virtual void DeleteSettingsMenu(); + virtual void SetupMainButtons(); + + GameBrowseMenu *browserMenu; + struct discHdr * DiscHeader; +}; + +#endif diff --git a/source/settings/menus/GlobalSettings.cpp b/source/settings/menus/GlobalSettings.cpp new file mode 100644 index 0000000..a603383 --- /dev/null +++ b/source/settings/menus/GlobalSettings.cpp @@ -0,0 +1,285 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "GlobalSettings.hpp" +#include "themes/CTheme.h" +#include "prompts/PromptWindows.h" +#include "network/update.h" +#include "language/gettext.h" +#include "GUISettingsMenu.hpp" +#include "LoaderSettings.hpp" +#include "ParentalControlSM.hpp" +#include "SoundSettingsMenu.hpp" +#include "CustomPathsSM.hpp" +#include "FeatureSettingsMenu.hpp" +#include "HardDriveSM.hpp" +#include "BannerSettingsMenu.hpp" + +GlobalSettings::GlobalSettings() + : FlyingButtonsMenu(tr("Global Settings")) +{ + creditsImgData = Resources::GetImageData("credits_button.png"); + creditsImgOverData = Resources::GetImageData("credits_button_over.png"); +} + +GlobalSettings::~GlobalSettings() +{ + Settings.Save(); + + delete creditsImgData; + delete creditsImgOverData; +} + +int GlobalSettings::Execute() +{ + GlobalSettings * Menu = new GlobalSettings(); + mainWindow->Append(Menu); + + Menu->ShowMenu(); + + int returnMenu = MENU_NONE; + + while((returnMenu = Menu->MainLoop()) == MENU_NONE); + + delete Menu; + + return returnMenu; +} + +void GlobalSettings::SetupMainButtons() +{ + int pos = 0; + + SetMainButton(pos++, tr( "GUI Settings" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Loader Settings" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Hard Drive Settings" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Features" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Banner Animation Settings" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Sound" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Parental Control" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Custom Paths" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Theme Menu" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Theme Downloader" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Update" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Default Settings" ), MainButtonImgData, MainButtonImgOverData); + SetMainButton(pos++, tr( "Credits" ), creditsImgData, creditsImgOverData); +} + +void GlobalSettings::CreateSettingsMenu(int menuNr) +{ + if(CurrentMenu) + return; + + int Idx = 0; + + //! GUI Settings + if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_GUI_SETTINGS)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + HideMenu(); + ResumeGui(); + CurrentMenu = new GuiSettingsMenu(); + Append(CurrentMenu); + } + //! Loader Settings + else if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_LOADER_SETTINGS)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + HideMenu(); + ResumeGui(); + CurrentMenu = new LoaderSettings(); + Append(CurrentMenu); + } + //! Hard Drive Settings + else if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_HARD_DRIVE_SETTINGS)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + HideMenu(); + ResumeGui(); + CurrentMenu = new HardDriveSM(); + Append(CurrentMenu); + } + //! Feature + else if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_FEATURE_SETTINGS)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + HideMenu(); + ResumeGui(); + CurrentMenu = new FeatureSettingsMenu(); + Append(CurrentMenu); + } + //! Banner Animation Settings + else if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_BANNER_SETTINGS)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + HideMenu(); + ResumeGui(); + CurrentMenu = new BannerSettingsMenu(); + Append(CurrentMenu); + } + //! Sound + else if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_SOUND_SETTINGS)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + HideMenu(); + ResumeGui(); + CurrentMenu = new SoundSettingsMenu(); + Append(CurrentMenu); + } + //! Parental Control + else if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_PARENTAL_SETTINGS)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + HideMenu(); + ResumeGui(); + CurrentMenu = new ParentalControlSM(); + Append(CurrentMenu); + } + //! Custom Paths + else if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_CUSTOMPATH_SETTINGS)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + HideMenu(); + ResumeGui(); + CurrentMenu = new CustomPathsSM(); + Append(CurrentMenu); + } + //! Theme Menu + else if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_THEME_MENU)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + returnMenu = MENU_THEMEMENU; + } + //! Theme Downloader + else if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_THEME_DOWNLOADER)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + WindowPrompt(tr( "Warning:" ), tr( "Sorry, the theme downloader menu is not working anymore because http://wii.spiffy360.com now requires user registration." ), tr( "OK" )); + return; + + // returnMenu = MENU_THEMEDOWNLOADER; + } + //! Update + else if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_UPDATES)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + HideMenu(); + Remove(backBtn); + ResumeGui(); + int ret = UpdateApp(); + if (ret < 0) + WindowPrompt(tr( "Update failed" ), 0, tr( "OK" )); + Append(backBtn); + ShowMenu(); + } + //! Default Settings + else if(menuNr == Idx++) + { + if(!Settings.godmode && (Settings.ParentalBlocks & BLOCK_RESET_SETTINGS)) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + return; + } + + int choice = WindowPrompt(tr( "Are you sure you want to reset?" ), 0, tr( "Yes" ), tr( "Cancel" )); + if (choice == 1) + { + HaltGui(); + gettextCleanUp(); + Settings.Reset(); + returnMenu = MENU_SETTINGS; + ResumeGui(); + } + } + //! Credits + else if(menuNr == Idx++) + { + HideMenu(); + Remove(backBtn); + ResumeGui(); + WindowCredits(); + Append(backBtn); + ShowMenu(); + } +} + +void GlobalSettings::DeleteSettingsMenu() +{ + delete CurrentMenu; + CurrentMenu = NULL; +} diff --git a/source/settings/menus/GlobalSettings.hpp b/source/settings/menus/GlobalSettings.hpp new file mode 100644 index 0000000..fee461e --- /dev/null +++ b/source/settings/menus/GlobalSettings.hpp @@ -0,0 +1,44 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GLOBAL_SETTINGS_HPP_ +#define GLOBAL_SETTINGS_HPP_ + +#include "FlyingButtonsMenu.hpp" + +class GlobalSettings : public FlyingButtonsMenu +{ + public: + GlobalSettings(); + virtual ~GlobalSettings(); + static int Execute(); + protected: + virtual void CreateSettingsMenu(int index); + virtual void DeleteSettingsMenu(); + virtual void SetupMainButtons(); + + GuiImageData * creditsImgData; + GuiImageData * creditsImgOverData; +}; + +#endif diff --git a/source/settings/menus/HardDriveSM.cpp b/source/settings/menus/HardDriveSM.cpp new file mode 100644 index 0000000..ccea76a --- /dev/null +++ b/source/settings/menus/HardDriveSM.cpp @@ -0,0 +1,323 @@ +/**************************************************************************** + * Copyright (C) 2014 Cyan + * Copyright (C) 2011 Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include "HardDriveSM.hpp" +#include "Controls/DeviceHandler.hpp" +#include "settings/CSettings.h" +#include "settings/meta.h" +#include "prompts/PromptWindows.h" +#include "language/gettext.h" +#include "usbloader/GameList.h" +#include "usbloader/wbfs.h" +#include "prompts/ProgressWindow.h" +#include "settings/GameTitles.h" +#include "system/IosLoader.h" +#include "wad/nandtitle.h" +#include "utils/tools.h" + +static const char * OnOffText[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ) +}; + +static const char * InstallToText[] = +{ + trNOOP( "None" ), + trNOOP( "GAMEID_Gamename" ), + trNOOP( "Gamename [GAMEID]" ) +}; + +static const char * SplitSizeText[] = +{ + trNOOP( "No Splitting" ), + trNOOP( "Split each 2GB" ), + trNOOP( "Split each 4GB" ), +}; + +static inline bool IsValidPartition(int fs_type, int cios) +{ + if (IosLoader::IsWaninkokoIOS(cios) && NandTitles.VersionOf(TITLE_ID(1, cios)) < 18) + { + return fs_type == PART_FS_WBFS; + } + else + { + return fs_type == PART_FS_WBFS || fs_type == PART_FS_FAT || fs_type == PART_FS_NTFS || fs_type == PART_FS_EXT; + } +} + +HardDriveSM::HardDriveSM() + : SettingsMenu(tr("Hard Drive Settings"), &GuiOptions, MENU_NONE) +{ + int Idx = 0; + Options->SetName(Idx++, "%s", tr( "Game/Install Partition" )); + Options->SetName(Idx++, "%s", tr( "Multiple Partitions" )); + Options->SetName(Idx++, "%s", tr( "USB Port" )); + Options->SetName(Idx++, "%s", tr( "Mount USB at launch" )); + Options->SetName(Idx++, "%s", tr( "Install Directories" )); + Options->SetName(Idx++, "%s", tr( "Game Split Size" )); + Options->SetName(Idx++, "%s", tr( "Install Partitions" )); + Options->SetName(Idx++, "%s", tr( "GC Install Compressed" )); + Options->SetName(Idx++, "%s", tr( "GC Install 32K Aligned" )); + Options->SetName(Idx++, "%s", tr( "Sync FAT32 FS Info" )); + + OldSettingsPartition = Settings.partition; + OldSettingsMultiplePartitions = Settings.MultiplePartitions; + NewSettingsUSBPort = Settings.USBPort; + oldSettingsUSBAutoMount = Settings.USBAutoMount; + + SetOptionValues(); +} + +HardDriveSM::~HardDriveSM() +{ + //! if partition has changed, Reinitialize it + if (Settings.partition != OldSettingsPartition || + Settings.MultiplePartitions != OldSettingsMultiplePartitions || + Settings.USBPort != NewSettingsUSBPort || + Settings.USBAutoMount != oldSettingsUSBAutoMount) + { + WBFS_CloseAll(); + + if(Settings.USBPort != NewSettingsUSBPort) + { + DeviceHandler::Instance()->UnMountAllUSB(); + Settings.USBPort = NewSettingsUSBPort; + DeviceHandler::Instance()->MountAllUSB(); + + if(Settings.partition >= DeviceHandler::GetUSBPartitionCount()) + Settings.partition = 0; + + // set -1 to edit meta.xml arguments + NewSettingsUSBPort = -1; + } + + WBFS_Init(WBFS_DEVICE_USB); + if(Settings.MultiplePartitions) + WBFS_OpenAll(); + else + WBFS_OpenPart(Settings.partition); + + //! Reload the new game titles + gameList.ReadGameList(); + gameList.LoadUnfiltered(); + GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path, false); + + if(oldSettingsUSBAutoMount != Settings.USBAutoMount || NewSettingsUSBPort == -1) + { + // edit meta.xml arguments + editMetaArguments(); + } + } +} + +void HardDriveSM::SetOptionValues() +{ + int Idx = 0; + + //! Settings: Game/Install Partition + PartitionHandle * usbHandle = DeviceHandler::Instance()->GetUSBHandleFromPartition(Settings.partition); + int checkPart = DeviceHandler::PartitionToPortPartition(Settings.partition); + + //! Get the partition name and it's size in GB's + if(usbHandle) + Options->SetValue(Idx++, "%s (%.2fGB)", usbHandle->GetFSName(checkPart), usbHandle->GetSize(checkPart)/GB_SIZE); + else + Options->SetValue(Idx++, tr("Not Initialized")); + + //! Settings: Multiple Partitions + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.MultiplePartitions] )); + + //! Settings: USB Port + if(NewSettingsUSBPort == 2) + Options->SetValue(Idx++, tr("Both Ports")); + else + Options->SetValue(Idx++, "%i", NewSettingsUSBPort); + + //! Settings: Auto Mount USB at launch + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.USBAutoMount] )); + + //! Settings: Install directories + Options->SetValue(Idx++, "%s", tr( InstallToText[Settings.InstallToDir] )); + + //! Settings: Game Split Size + Options->SetValue(Idx++, "%s", tr( SplitSizeText[Settings.GameSplit] )); + + //! Settings: Install partitions + if(Settings.InstallPartitions == ONLY_GAME_PARTITION) + Options->SetValue(Idx++, "%s", tr("Only Game Partition")); + else if(Settings.InstallPartitions == ALL_PARTITIONS) + Options->SetValue(Idx++, "%s", tr("All Partitions")); + else if(Settings.InstallPartitions == REMOVE_UPDATE_PARTITION) + Options->SetValue(Idx++, "%s", tr("Remove update")); + + //! Settings: GC Install Compressed + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.GCInstallCompressed] )); + + //! Settings: GC Install 32K Aligned + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.GCInstallAligned] )); + + //! Settings: Sync FAT32 FS Info + Options->SetValue(Idx++, " "); +} + +int HardDriveSM::GetMenuInternal() +{ + int ret = optionBrowser->GetClickedOption(); + + if (ret < 0) + return MENU_NONE; + + int Idx = -1; + + //! Settings: Game/Install Partition + if (ret == ++Idx) + { + // Init the USB device if mounted after launch. + PartitionHandle * usbHandle = DeviceHandler::Instance()->GetUSBHandleFromPartition(Settings.partition); + if(usbHandle == NULL) + DeviceHandler::Instance()->MountAllUSB(true); + + // Select the next valid partition, even if that's the same one + int fs_type = 0; + int ios = IOS_GetVersion(); + int retries = 20; + do + { + Settings.partition = (Settings.partition + 1) % DeviceHandler::GetUSBPartitionCount(); + fs_type = DeviceHandler::GetFilesystemType(USB1+Settings.partition); + } + while (!IsValidPartition(fs_type, ios) && --retries > 0); + + if(fs_type == PART_FS_FAT && Settings.GameSplit == GAMESPLIT_NONE) + Settings.GameSplit = GAMESPLIT_4GB; + } + + //! Settings: Multiple Partitions + else if (ret == ++Idx) + { + if (++Settings.MultiplePartitions >= MAX_ON_OFF) Settings.MultiplePartitions = 0; + } + + //! Settings: USB Port + else if (ret == ++Idx) + { + if(!IosLoader::IsHermesIOS() && !IosLoader::IsD2X()) + { + WindowPrompt(tr("ERROR:"), tr("USB Port changing is only supported on Hermes cIOS."), tr("OK")); + NewSettingsUSBPort = 0; + Settings.USBPort = 0; + } + + else if (++NewSettingsUSBPort >= 3) // 2 = both ports + NewSettingsUSBPort = 0; + } + + //! Settings: Auto mount USB at launch + else if (ret == ++Idx) + { + if (++Settings.USBAutoMount >= MAX_ON_OFF) Settings.USBAutoMount = 0; + } + + //! Settings: Install directories + else if (ret == ++Idx) + { + if (++Settings.InstallToDir >= INSTALL_TO_MAX) Settings.InstallToDir = 0; + } + + //! Settings: Game Split Size + else if (ret == ++Idx) + { + if (++Settings.GameSplit >= GAMESPLIT_MAX) + { + if(DeviceHandler::GetFilesystemType(USB1+Settings.partition) == PART_FS_FAT) + Settings.GameSplit = GAMESPLIT_2GB; + else + Settings.GameSplit = GAMESPLIT_NONE; + } + } + + //! Settings: Install partitions + else if (ret == ++Idx) + { + switch(Settings.InstallPartitions) + { + case ONLY_GAME_PARTITION: + Settings.InstallPartitions = ALL_PARTITIONS; + break; + case ALL_PARTITIONS: + Settings.InstallPartitions = REMOVE_UPDATE_PARTITION; + break; + default: + case REMOVE_UPDATE_PARTITION: + Settings.InstallPartitions = ONLY_GAME_PARTITION; + break; + } + } + + //! Settings: GC Install Compressed + else if (ret == ++Idx) + { + if (++Settings.GCInstallCompressed >= MAX_ON_OFF) Settings.GCInstallCompressed = 0; + } + + //! Settings: GC Install 32K Aligned + else if (ret == ++Idx) + { + if (++Settings.GCInstallAligned >= MAX_ON_OFF) Settings.GCInstallAligned = 0; + } + + //! Settings: Sync FAT32 FS Info + else if (ret == ++Idx ) + { + int choice = WindowPrompt(0, tr("Do you want to sync free space info sector on all FAT32 partitions?"), tr("Yes"), tr("Cancel")); + if(choice) + { + StartProgress(tr("Synchronizing..."), tr("Please wait..."), 0, false, false); + int partCount = DeviceHandler::GetUSBPartitionCount(); + for(int i = 0; i < partCount; ++i) + { + ShowProgress(i, partCount); + if(DeviceHandler::GetFilesystemType(USB1+i) == PART_FS_FAT) + { + PartitionHandle *usb = DeviceHandler::Instance()->GetUSBHandleFromPartition(i); + if(!usb) continue; + struct statvfs stats; + char drive[20]; + snprintf(drive, sizeof(drive), "%s:/", usb->MountName(i)); + memset(&stats, 0, sizeof(stats)); + memcpy(&stats.f_flag, "SCAN", 4); + statvfs(drive, &stats); + } + } + ProgressStop(); + } + } + + SetOptionValues(); + + return MENU_NONE; +} diff --git a/source/settings/menus/HardDriveSM.hpp b/source/settings/menus/HardDriveSM.hpp new file mode 100644 index 0000000..ad97f90 --- /dev/null +++ b/source/settings/menus/HardDriveSM.hpp @@ -0,0 +1,47 @@ +/**************************************************************************** + * Copyright (C) 2014 Cyan + * Copyright (C) 2011 Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef HARDDRIVE_MENU_HPP_ +#define HARDDRIVE_MENU_HPP_ + +#include "SettingsMenu.hpp" + +class HardDriveSM : public SettingsMenu +{ + public: + HardDriveSM(); + virtual ~HardDriveSM(); + protected: + void SetOptionValues(); + int GetMenuInternal(); + + int OldSettingsPartition; + int OldSettingsMultiplePartitions; + int oldSettingsUSBAutoMount; + int NewSettingsUSBPort; + + OptionList GuiOptions; +}; + + +#endif diff --git a/source/settings/menus/LoaderSettings.cpp b/source/settings/menus/LoaderSettings.cpp new file mode 100644 index 0000000..1e83005 --- /dev/null +++ b/source/settings/menus/LoaderSettings.cpp @@ -0,0 +1,1023 @@ +/**************************************************************************** + * Copyright (C) 2012-2014 Cyan + * Copyright (C) 2010 by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "LoaderSettings.hpp" +#include "usbloader/usbstorage2.h" +#include "settings/CSettings.h" +#include "settings/GameTitles.h" +#include "settings/meta.h" +#include "prompts/PromptWindows.h" +#include "language/gettext.h" +#include "wad/nandtitle.h" +#include "prompts/TitleBrowser.h" +#include "system/IosLoader.h" +#include "usbloader/wbfs.h" +#include "usbloader/GameList.h" +#include "utils/tools.h" +#include "menu.h" +#include "GameCube/GCGames.h" + +static const char * OnOffText[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ), + trNOOP( "Auto" ) +}; + +static const char * AspectText[] = +{ + trNOOP( "Force 4:3" ), + trNOOP( "Force 16:9" ), + trNOOP( "System Default" ) +}; + +static const char * VideoModeText[] = +{ + trNOOP( "System Default" ), + trNOOP( "Disc Default" ), + trNOOP( "Force PAL50" ), + trNOOP( "Force PAL60" ), + trNOOP( "Force NTSC" ), + trNOOP( "Region Patch" ), + trNOOP( "Force PAL480p" ), + trNOOP( "Force NTSC480p" ), +}; + +static const char * VideoPatchDolText[] = +{ + trNOOP( "OFF" ), + trNOOP( "Region Patch" ), + trNOOP( "ON" ), + trNOOP( "All" ), +}; + +static const char * LanguageText[] = +{ + trNOOP( "Japanese" ), + trNOOP( "English" ), + trNOOP( "German" ), + trNOOP( "French" ), + trNOOP( "Spanish" ), + trNOOP( "Italian" ), + trNOOP( "Dutch" ), + trNOOP( "SChinese" ), + trNOOP( "TChinese" ), + trNOOP( "Korean" ), + trNOOP( "Console Default" ) +}; + +static const char * NandEmuText[] = +{ + trNOOP( "OFF" ), + trNOOP( "Partial" ), + trNOOP( "Full" ), + trNOOP( "Neek" ) +}; + +static const char * HooktypeText[] = +{ + trNOOP( "None" ), + trNOOP( "VBI (Default)" ), + trNOOP( "KPAD Read" ), + trNOOP( "Joypad" ), + trNOOP( "GXDraw" ), + trNOOP( "GXFlush" ), + trNOOP( "OSSleepThread" ), + trNOOP( "AXNextFrame" ), +}; + +static const char * ChannelLaunchText[] = +{ + trNOOP( "Main DOL" ), + trNOOP( "Boot Content" ), +}; + +static const char * GCMode[] = +{ + trNOOP( "MIOS (Default & Customs)" ), + trNOOP( "Devolution" ), + trNOOP( "Nintendont" ), +}; + +static const char * GCSourceText[][3] = +{ + { trNOOP( "Main Path" ), "", "" }, + { trNOOP( "SD Path" ), "", "" }, + { trNOOP( "Auto" ), "", "" }, + { trNOOP( "Main Path" ), "/", trNOOP( "SD Path" ) }, + { trNOOP( "SD Path" ), "/", trNOOP( "Main Path" ) }, +}; + +static const char * DMLVideoText[] = +{ + trNOOP( "Auto" ), + trNOOP( "System Default" ), + trNOOP( "Disc Default" ), + trNOOP( "Force PAL50" ), + trNOOP( "Force PAL60" ), + trNOOP( "Force NTSC" ), + "", // unused + trNOOP( "Force PAL480p" ), + trNOOP( "Force NTSC480p" ), + trNOOP( "None" ), +}; + +static const char * DMLNMMMode[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ), + trNOOP( "Debug" ), +}; + +static const char * DMLDebug[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ), + trNOOP( "Debug Wait" ), +}; + +static const char * DEVOMCText[] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ), + trNOOP( "Individual" ), +}; + +static const char * NINMCText[] = +{ + trNOOP( "OFF" ), + trNOOP( "Individual" ), + trNOOP( "ON (Multi)" ), +}; + +static const char * NINCfgText[] = +{ + trNOOP( "Delete" ), + trNOOP( "Create" ), + trNOOP( "No change" ), +}; + +static const char * PrivServText[] = +{ + trNOOP( "OFF" ), + trNOOP( "NoSSL only" ), + trNOOP( "Wiimmfi.de" ), +}; + +LoaderSettings::LoaderSettings() + : SettingsMenu(tr("Loader Settings"), &GuiOptions, MENU_NONE) +{ + + SetOptionNames(); + SetOptionValues(); + + oldLoaderMode = Settings.LoaderMode; + oldGameCubeSource = Settings.GameCubeSource; + oldLoaderIOS = Settings.LoaderIOS; +} + +LoaderSettings::~LoaderSettings() +{ + if(oldLoaderMode != Settings.LoaderMode) + { + if(Settings.LoaderMode & MODE_WIIGAMES && (gameList.GameCount() == 0)) + { + WBFS_ReInit(WBFS_DEVICE_USB); + gameList.ReadGameList(); + } + + gameList.LoadUnfiltered(); + GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path, false); + } + + if(oldGameCubeSource != Settings.GameCubeSource) + { + GCGames::Instance()->LoadAllGames(); + } + + if(oldLoaderIOS != Settings.LoaderIOS) + { + // edit meta.xml arguments + editMetaArguments(); + } +} + +void LoaderSettings::SetOptionNames() +{ + int Idx = 0; + + Options->SetName(Idx++, "%s", tr( "Video Mode" )); + Options->SetName(Idx++, "%s", tr( "Dol Video Patch" )); + Options->SetName(Idx++, "%s", tr( "480p Pixel Fix Patch" )); + Options->SetName(Idx++, "%s", tr( "Sneek Video Patch" )); + Options->SetName(Idx++, "%s", tr( "VIDTV Patch" )); + Options->SetName(Idx++, "%s", tr( "Aspect Ratio" )); + Options->SetName(Idx++, "%s", tr( "Game Language" )); + Options->SetName(Idx++, "%s", tr( "Patch Country Strings" )); + Options->SetName(Idx++, "%s", tr( "Ocarina" )); + Options->SetName(Idx++, "%s", tr( "Private Server" )); + Options->SetName(Idx++, "%s", tr( "Loader's IOS" )); + Options->SetName(Idx++, "%s", tr( "Game's IOS" )); + Options->SetName(Idx++, "%s", tr( "Quick Boot" )); + Options->SetName(Idx++, "%s", tr( "Block IOS Reload" )); + Options->SetName(Idx++, "%s", tr( "Return To" )); + Options->SetName(Idx++, "%s", tr( "Nand Saves Emulation" )); + Options->SetName(Idx++, "%s", tr( "Nand Chan. Emulation" )); + Options->SetName(Idx++, "%s", tr( "Hooktype" )); + Options->SetName(Idx++, "%s", tr( "Wiird Debugger" )); + Options->SetName(Idx++, "%s", tr( "Debugger Paused Start" )); + Options->SetName(Idx++, "%s", tr( "Channel Launcher" )); + Options->SetName(Idx++, "%s", tr( "=== GameCube Settings" )); + Options->SetName(Idx++, "%s", tr( "GameCube Source" )); + Options->SetName(Idx++, "%s", tr( "GameCube Mode" )); + Options->SetName(Idx++, "%s", tr( "--== DM(L) + Nintendont" )); + Options->SetName(Idx++, "%s", tr( "Video Mode" )); + Options->SetName(Idx++, "%s", tr( "Progressive Patch" )); + Options->SetName(Idx++, "%s", tr( "Force Widescreen" )); + Options->SetName(Idx++, "%s", tr( "Debug" )); + Options->SetName(Idx++, "%s", tr( "Disc-Select Prompt" )); + Options->SetName(Idx++, "%s", tr( "--== DIOS MIOS (Lite) " )); + Options->SetName(Idx++, "%s", tr( "NMM Mode" )); + Options->SetName(Idx++, "%s", tr( "PAD Hook" )); + Options->SetName(Idx++, "%s", tr( "No Disc+" )); + Options->SetName(Idx++, "%s", tr( "Screenshot" )); + Options->SetName(Idx++, "%s", tr( "LED Activity" )); + Options->SetName(Idx++, "%s", tr( "Japanese Patch" )); + Options->SetName(Idx++, "%s", tr( "--== Nintendont" )); + Options->SetName(Idx++, "%s", tr( "Auto Boot" )); + Options->SetName(Idx++, "%s", tr( "Settings File" )); + Options->SetName(Idx++, "%s", tr( "Video Deflicker" )); + Options->SetName(Idx++, "%s", tr( "PAL50 Patch" )); + Options->SetName(Idx++, "%s", tr( "WiiU Widescreen" )); + Options->SetName(Idx++, "%s", tr( "Video scale" )); + if(Settings.NINVideoScale != 0) + { + Options->SetName(Idx++, "%s", tr( "Video Scale Value" )); + } + Options->SetName(Idx++, "%s", tr( "Video offset" )); + Options->SetName(Idx++, "%s", tr( "Remove Read Speed Limit" )); + Options->SetName(Idx++, "%s", tr( "Triforce Arcade Mode" )); + Options->SetName(Idx++, "%s", tr("CC Rumble")); + Options->SetName(Idx++, "%s", tr("Skip IPL")); + Options->SetName(Idx++, "%s", tr( "BBA Emulation")); // ASA + Options->SetName(Idx++, "%s", tr( "BBA Network Profile")); // ASA + Options->SetName(Idx++, "%s", tr( "Memory Card Emulation" )); + Options->SetName(Idx++, "%s", tr( "Memory Card Blocks Size" )); + Options->SetName(Idx++, "%s", tr( "USB-HID Controller" )); + Options->SetName(Idx++, "%s", tr( "GameCube Controller" )); + Options->SetName(Idx++, "%s", tr( "Native Controller" )); + Options->SetName(Idx++, "%s", tr( "LED Activity" )); + Options->SetName(Idx++, "%s", tr( "OSReport" )); + Options->SetName(Idx++, "%s", tr( "Log to file" )); + Options->SetName(Idx++, "%s", tr( "--== Devolution" )); + Options->SetName(Idx++, "%s", tr( "Memory Card Emulation" )); + Options->SetName(Idx++, "%s", tr( "Force Widescreen" )); + Options->SetName(Idx++, "%s", tr( "LED Activity" )); + Options->SetName(Idx++, "%s", tr( "F-Zero AX" )); + Options->SetName(Idx++, "%s", tr( "Timer Fix" )); + Options->SetName(Idx++, "%s", tr( "D Buttons" )); + Options->SetName(Idx++, "%s", tr( "Crop Overscan" )); + Options->SetName(Idx++, "%s", tr( "Disc Read Delay" )); + +} + +void LoaderSettings::SetOptionValues() +{ + int Idx = 0; + + //! Settings: Video Mode + Options->SetValue(Idx++, "%s", tr(VideoModeText[Settings.videomode])); + + //! Settings: Dol Video Patch + Options->SetValue(Idx++, "%s", tr( VideoPatchDolText[Settings.videoPatchDol] )); + + //! Settings: 480p Pixel Fix Patch + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.patchFix480p] )); + + //! Settings: Sneek Video Patch + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.sneekVideoPatch] )); + + //! Settings: VIDTV Patch + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.videopatch] )); + + //! Settings: Aspect Ratio + Options->SetValue(Idx++, "%s", tr( AspectText[Settings.GameAspectRatio] )); + + //! Settings: Game Language + Options->SetValue(Idx++, "%s", tr( LanguageText[Settings.language] )); + + //! Settings: Patch Country Strings + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.patchcountrystrings] )); + + //! Settings: Ocarina + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.ocarina] )); + + //! Settings: Private Server + Options->SetValue(Idx++, "%s", tr( PrivServText[Settings.PrivateServer] )); + + //! Settings: Loader's IOS + if (Settings.godmode) + Options->SetValue(Idx++, "IOS %i", Settings.LoaderIOS); + else + Options->SetValue(Idx++, "********"); + + //! Settings: Game's IOS + if (Settings.godmode) + Options->SetValue(Idx++, "IOS %i", Settings.cios); + else + Options->SetValue(Idx++, "********"); + + //! Settings: Quick Boot + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.quickboot] )); + + //! Settings: Block IOS Reload + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.BlockIOSReload] )); + + //! Settings: Return To + const char* TitleName = NULL; + u64 tid = NandTitles.FindU32(Settings.returnTo); + if (tid > 0) + TitleName = NandTitles.NameOf(tid); + TitleName = TitleName ? TitleName : strlen(Settings.returnTo) > 0 ? Settings.returnTo : tr(OnOffText[0]); + Options->SetValue(Idx++, "%s", TitleName); + + //! Settings: Nand Emulation + Options->SetValue(Idx++, "%s", tr( NandEmuText[Settings.NandEmuMode] )); + + //! Settings: Nand Chan. Emulation + Options->SetValue(Idx++, "%s", tr( NandEmuText[Settings.NandEmuChanMode] )); + + //! Settings: Hooktype + Options->SetValue(Idx++, "%s", tr( HooktypeText[Settings.Hooktype] )); + + //! Settings: Wiird Debugger + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.WiirdDebugger] )); + + //! Settings: Wiird Debugger Pause on Start + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.WiirdDebuggerPause] )); + + //! Settings: Channel Launcher + Options->SetValue(Idx++, "%s", tr( ChannelLaunchText[Settings.UseChanLauncher] )); + + //! Settings: TITLE - GameCube Settings + Options->SetValue(Idx++, "======="); + + //! Settings: GameCube Source + Options->SetValue(Idx++, "%s%s%s", tr(GCSourceText[Settings.GameCubeSource][0]), + GCSourceText[Settings.GameCubeSource][1], tr(GCSourceText[Settings.GameCubeSource][2])); + + //! Settings: GameCube Mode + Options->SetValue(Idx++, "%s", tr(GCMode[Settings.GameCubeMode])); + + //! Settings: TITLE - GameCube DIOS MIOS (Lite) + Nintendont + Options->SetValue(Idx++, "==-- "); + + //! Settings: DML + NIN Video Mode + Options->SetValue(Idx++, "%s", tr(DMLVideoText[Settings.DMLVideo])); + + //! Settings: DML + NIN Progressive Patch + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DMLProgPatch])); + + //! Settings: DML + NIN Force Widescreen + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DMLWidescreen])); + + //! Settings: DML + NIN Debug + Options->SetValue(Idx++, "%s", tr(DMLDebug[Settings.DMLDebug])); + + //! Settings: DML + NIN MultiDiscPrompt + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.MultiDiscPrompt])); + + //! Settings: TITLE - GameCube DIOS MIOS (Lite) + Options->SetValue(Idx++, "==-- "); + + //! Settings: DML NMM Mode + Options->SetValue(Idx++, "%s", tr(DMLNMMMode[Settings.DMLNMM])); + + //! Settings: DML PAD Hook + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DMLPADHOOK])); + + //! Settings: DML Extended No Disc + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DMLNoDisc2])); + + //! Settings: DML Screenshot + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DMLScreenshot])); + + //! Settings: DML LED Activity + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DMLActivityLED])); + + //! Settings: DML Japanese Patch + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DMLJPNPatch])); + + //! Settings: TITLE - Nintendont + Options->SetValue(Idx++, "==-- "); + + //! Settings: NIN Auto Boot + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINAutoboot])); + + //! Settings: NIN Nincfg.bin file + Options->SetValue(Idx++, "%s", tr(NINCfgText[Settings.NINSettings])); + + //! Settings: NIN Video Deflicker + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINDeflicker])); + + //! Settings: NIN PAL50 Patch + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINPal50Patch])); + + //! Settings: WiiU Widescreen + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINWiiUWide])); + + //! Settings: NIN VideoScale + if(Settings.NINVideoScale == 0) + Options->SetValue(Idx++, "%s", tr("Auto")); + else + { + Options->SetValue(Idx++, "%s", tr("Manual (40~120)")); + Options->SetValue(Idx++, "%d", Settings.NINVideoScale); + + } + + //! Settings: NIN VideoOffset + Options->SetValue(Idx++, "%d (-20~20)", Settings.NINVideoOffset); + + //! Settings: NIN Remove Read Speed Limiter + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINRemlimit])); + + //! Settings: NIN Arcade Mode + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINArcadeMode])); + + //! Settings: NIN CC Rumble + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINCCRumble])); + + //! Settings: NIN Skip IPL + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINSkipIPL])); + + //! Settings: NIN BBA // ASA + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINBBA])); + + //! Settings: NIN BAA Profile // ASA + if (Settings.NINBBAPROF == 0) + Options->SetValue(Idx++, "%s", tr("Auto")); + else + Options->SetValue(Idx++, "%hi", Settings.NINBBAPROF); + + //! Settings: NIN Memory Card Emulation + Options->SetValue(Idx++, "%s", tr(NINMCText[Settings.NINMCEmulation])); + + //! Settings: NIN Memory Card Blocks Size + Options->SetValue(Idx++, "%d", MEM_CARD_BLOCKS(Settings.NINMCSize)); + + //! Settings: NIN USB-HID controller + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINUSBHID])); + + //! Settings: NIN MaxPads - Number of GameCube controllers + Options->SetValue(Idx++, "%i", Settings.NINMaxPads); + + //! Settings: NIN Native Controller + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINNativeSI])); + + //! Settings: NIN LED Activity + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINLED])); + + //! Settings: NIN OS Report + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINOSReport])); + + //! Settings: NIN Log to file + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.NINLog])); + + //! Settings: TITLE - Devolution + Options->SetValue(Idx++, "==-- "); + + //! Settings: DEVO Memory Card Emulation + Options->SetValue(Idx++, "%s", tr(DEVOMCText[Settings.DEVOMCEmulation])); + + //! Settings: DEVO Widescreen Patch + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DEVOWidescreen])); + + //! Settings: DEVO Activity LED + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DEVOActivityLED])); + + //! Settings: DEVO F-Zero AX unlock patch + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DEVOFZeroAX])); + + //! Settings: DEVO Timer Fix + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DEVOTimerFix])); + + //! Settings: DEVO Direct Button Mapping + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DEVODButtons])); + + //! Settings: DEVO Crop Overscan + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DEVOCropOverscan])); + + //! Settings: DEVO Disc Read Delay + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DEVODiscDelay])); + +} + +int LoaderSettings::GetMenuInternal() +{ + int ret = optionBrowser->GetClickedOption(); + + if (ret < 0) + return MENU_NONE; + + int Idx = -1; + + //! Settings: Video Mode + if (ret == ++Idx) + { + if (++Settings.videomode >= VIDEO_MODE_MAX) Settings.videomode = 0; + } + + //! Settings: Dol Video Patch + if (ret == ++Idx) + { + if (++Settings.videoPatchDol >= VIDEO_PATCH_DOL_MAX) Settings.videoPatchDol = 0; + } + + //! Settings: 480p Pixel Fix Patch + if (ret == ++Idx) + { + if (++Settings.patchFix480p >= MAX_ON_OFF) Settings.patchFix480p = 0; + if(Settings.patchFix480p) + WindowPrompt(tr("Warning:"), tr("This patch might not work with all games. If a game doesn't boot, disable it in individual game settings menu."), tr("OK")); + } + + //! Settings: Sneek Video Patch + else if (ret == ++Idx ) + { + if (++Settings.sneekVideoPatch >= MAX_ON_OFF) Settings.sneekVideoPatch = 0; + } + + //! Settings: VIDTV Patch + else if (ret == ++Idx) + { + if (++Settings.videopatch >= MAX_ON_OFF) Settings.videopatch = 0; + } + + //! Settings: Aspect Ratio + else if (ret == ++Idx ) + { + if (++Settings.GameAspectRatio >= ASPECT_MAX) Settings.GameAspectRatio = 0; + } + + //! Settings: Game Language + else if (ret == ++Idx) + { + if (++Settings.language >= MAX_LANGUAGE) Settings.language = 0; + } + + //! Settings: Patch Country Strings + else if (ret == ++Idx) + { + if (++Settings.patchcountrystrings >= MAX_ON_OFF) Settings.patchcountrystrings = 0; + } + + //! Settings: Ocarina + else if (ret == ++Idx) + { + if (++Settings.ocarina >= MAX_ON_OFF) Settings.ocarina = 0; + } + + //! Settings: Private Server + else if (ret == ++Idx) + { + if (++Settings.PrivateServer >= PRIVSERV_MAX_CHOICE) Settings.PrivateServer = 0; + } + + //! Settings: Loader's IOS + else if (ret == ++Idx) + { + if(!Settings.godmode) + return MENU_NONE; + + char entered[4]; + snprintf(entered, sizeof(entered), "%i", Settings.LoaderIOS); + if(OnScreenNumpad(entered, sizeof(entered))) + { + if(atoi(entered) == 58) // allow only IOS58 for IOS <200 + Settings.LoaderIOS = 58; + else + Settings.LoaderIOS = LIMIT(atoi(entered), 200, 255); + + if(NandTitles.IndexOf(TITLE_ID(1, Settings.LoaderIOS)) < 0) + { + WindowPrompt(tr("Warning:"), tr("This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning."), tr("OK")); + } + else if(Settings.LoaderIOS == 254) + { + WindowPrompt(tr("Warning:"), tr("This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning."), tr("OK")); + } + } + } + + //! Settings: Game's IOS + else if (ret == ++Idx) + { + if(!Settings.godmode) + return MENU_NONE; + + char entered[4]; + snprintf(entered, sizeof(entered), "%i", Settings.cios); + if(OnScreenNumpad(entered, sizeof(entered))) + { + Settings.cios = LIMIT(atoi(entered), 200, 255); + + if(NandTitles.IndexOf(TITLE_ID(1, Settings.cios)) < 0) + { + WindowPrompt(tr("Warning:"), tr("This IOS was not found on the titles list. If you are sure you have it installed than ignore this warning."), tr("OK")); + } + else if(Settings.cios == 254) + { + WindowPrompt(tr("Warning:"), tr("This IOS is the BootMii ios. If you are sure it is not BootMii and you have something else installed there than ignore this warning."), tr("OK")); + } + } + } + + //! Settings: Quick Boot + else if (ret == ++Idx) + { + if (++Settings.quickboot >= MAX_ON_OFF) Settings.quickboot = 0; + } + + //! Settings: Block IOS Reload + else if (ret == ++Idx ) + { + if (++Settings.BlockIOSReload >= 3) Settings.BlockIOSReload = 0; + } + + //! Settings: Return To + else if (ret == ++Idx) + { + char tidChar[10]; + bool getChannel = TitleSelector(tidChar); + if (getChannel) + snprintf(Settings.returnTo, sizeof(Settings.returnTo), "%s", tidChar); + } + + //! Settings: Nand Emulation (Saves) + else if (ret == ++Idx ) + { + if(!IosLoader::IsD2X(Settings.cios)) + WindowPrompt(tr("Error:"), tr("Nand Emulation is only available on D2X cIOS!"), tr("OK")); + else if (++Settings.NandEmuMode >= EMUNAND_NEEK) Settings.NandEmuMode = EMUNAND_OFF; + } + + //! Settings: Nand Emulation (channel / neek) + else if (ret == ++Idx ) + { + if(++Settings.NandEmuChanMode >= EMUNAND_MAX) Settings.NandEmuChanMode = EMUNAND_PARTIAL; + } + + //! Settings: Hooktype + else if (ret == ++Idx ) + { + if (++Settings.Hooktype >= 8) Settings.Hooktype = 0; + } + + //! Settings: Wiird Debugger + else if (ret == ++Idx ) + { + if (++Settings.WiirdDebugger >= MAX_ON_OFF) Settings.WiirdDebugger = 0; + } + + //! Settings: Wiird Debugger Pause on Start + else if (ret == ++Idx ) + { + if (++Settings.WiirdDebuggerPause >= MAX_ON_OFF) Settings.WiirdDebuggerPause = 0; + } + + //! Settings: Channel Launcher + else if (ret == ++Idx ) + { + if (++Settings.UseChanLauncher >= MAX_ON_OFF) Settings.UseChanLauncher = 0; + } + + //! Settings: TITLE - GameCube Settings + else if (ret == ++Idx) + { + // This one is a category title + } + + //! Settings: GameCube Source + else if (ret == ++Idx) + { + if (++Settings.GameCubeSource >= CG_SOURCE_MAX_CHOICE) Settings.GameCubeSource = 0; + } + + //! Settings: GameCube Mode + else if (ret == ++Idx) + { + if (++Settings.GameCubeMode >= CG_MODE_MAX_CHOICE) Settings.GameCubeMode = 0; + } + + //! Settings: TITLE - GameCube DM(L) + Nintendont + else if (ret == ++Idx) + { + // This one is a category title + } + + //! Settings: DML + NIN Video Mode + else if (ret == ++Idx) + { + Settings.DMLVideo++; + if(Settings.DMLVideo == DML_VIDEO_FORCE_PATCH) // Skip Force Patch + Settings.DMLVideo++; + if(Settings.DMLVideo >= DML_VIDEO_MAX_CHOICE) Settings.DMLVideo = 0; + } + + //! Settings: DML + NIN Progressive Patch + else if (ret == ++Idx) + { + if (++Settings.DMLProgPatch >= MAX_ON_OFF) Settings.DMLProgPatch = 0; + } + + //! Settings: DML + NIN Force Widescreen + else if (ret == ++Idx) + { + if (++Settings.DMLWidescreen >= MAX_ON_OFF) Settings.DMLWidescreen = 0; + } + + //! Settings: DML + NIN Debug + else if (ret == ++Idx) + { + if (++Settings.DMLDebug >= 3) Settings.DMLDebug = 0; + } + + //! Settings: DML + NIN MultiDiscPrompt + else if (ret == ++Idx) + { + if (++Settings.MultiDiscPrompt >= MAX_ON_OFF) Settings.MultiDiscPrompt = 0; + } + + //! Settings: TITLE - GameCube DIOS MIOS (Lite) + else if (ret == ++Idx) + { + // This one is a category title + } + + //! Settings: DML + NIN NMM Mode + else if (ret == ++Idx) + { + if (++Settings.DMLNMM >= 3) Settings.DMLNMM = 0; + } + + //! Settings: DML PAD Hook + else if (ret == ++Idx) + { + if (++Settings.DMLPADHOOK >= MAX_ON_OFF) Settings.DMLPADHOOK = 0; + } + + //! Settings: DML Extended No Disc + else if (ret == ++Idx) + { + if (++Settings.DMLNoDisc2 >= MAX_ON_OFF) Settings.DMLNoDisc2 = 0; + } + + //! Settings: DML Screenshot + else if (ret == ++Idx) + { + if (++Settings.DMLScreenshot >= MAX_ON_OFF) Settings.DMLScreenshot = 0; + } + + //! Settings: DML LED Activity + else if (ret == ++Idx) + { + if (++Settings.DMLActivityLED >= MAX_ON_OFF) Settings.DMLActivityLED = 0; + } + + //! Settings: DML Japanese Patch + else if (ret == ++Idx) + { + if (++Settings.DMLJPNPatch >= MAX_ON_OFF) Settings.DMLJPNPatch = 0; + } + + //! Settings: TITLE - Nintendont + else if (ret == ++Idx) + { + // This one is a category title + } + + //! Settings: NIN Auto Boot + else if (ret == ++Idx) + { + if (++Settings.NINAutoboot >= MAX_ON_OFF) Settings.NINAutoboot = 0; + } + + //! Settings: NIN Nincfg.bin file + else if (ret == ++Idx) + { + if (++Settings.NINSettings > AUTO) Settings.NINSettings = 0; + } + + //! Settings: NIN Video Deflicker + else if (ret == ++Idx) + { + if (++Settings.NINDeflicker >= MAX_ON_OFF) Settings.NINDeflicker = 0; + } + + //! Settings: NIN PAL50 Patch + else if (ret == ++Idx) + { + if (++Settings.NINPal50Patch >= MAX_ON_OFF) Settings.NINPal50Patch = 0; + } + + //! Settings: WiiU Widescreen + else if (ret == ++Idx) + { + if (++Settings.NINWiiUWide >= MAX_ON_OFF) Settings.NINWiiUWide = 0; + } + + //! Settings: NIN VideoScale + else if (ret == ++Idx) + { + Settings.NINVideoScale == 0 ? Settings.NINVideoScale = 40 : Settings.NINVideoScale = 0; + Options->ClearList(); + SetOptionNames(); + SetOptionValues(); + } + + else if (Settings.NINVideoScale != 0 && ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%i", Settings.NINVideoScale); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.NINVideoScale = LIMIT(atoi(entrie), 40, 120); + } + + //! Settings: NIN VideoOffset + else if (ret == ++Idx) + { + char entrie[20]; + snprintf(entrie, sizeof(entrie), "%i", Settings.NINVideoOffset); + int ret = OnScreenNumpad(entrie, sizeof(entrie)); + if(ret) + Settings.NINVideoOffset = LIMIT(atoi(entrie), -20, 20); + } + + //! Settings: NIN Remove Read Speed Limiter + else if (ret == ++Idx) + { + if (++Settings.NINRemlimit >= MAX_ON_OFF) Settings.NINRemlimit = 0; + } + + //! Settings: NIN Arcade Mode + else if (ret == ++Idx) + { + if (++Settings.NINArcadeMode >= MAX_ON_OFF) Settings.NINArcadeMode = 0; + } + + //! Settings: NIN CC Rumble + else if (ret == ++Idx) + { + if (++Settings.NINCCRumble >= MAX_ON_OFF) Settings.NINCCRumble = 0; + } + + //! Settings: NIN Skip IPL + else if (ret == ++Idx) + { + if (++Settings.NINSkipIPL >= MAX_ON_OFF) Settings.NINSkipIPL = 0; + } + + //! Settings: NIN BBA // ASA + else if (ret == ++Idx) + { + if (++Settings.NINBBA >= MAX_ON_OFF) Settings.NINBBA = 0; + } + + //! Settings: NIN BBA Profile // ASA + else if (ret == ++Idx) + { + if (++Settings.NINBBAPROF >= 4) Settings.NINBBAPROF = 0; + } + + //! Settings: NIN Memory Card Emulation + else if (ret == ++Idx) + { + if (++Settings.NINMCEmulation >= NIN_MC_MAX_CHOICE) Settings.NINMCEmulation = 0; + } + + //! Settings: NIN Memory Card Blocks Size + else if (ret == ++Idx) + { + if (++Settings.NINMCSize >= 6) Settings.NINMCSize = 0; + if (Settings.NINMCSize == 5) + WindowPrompt(tr("Warning:"), tr("Memory Card with 2043 blocs has issues with Nintendont. Use at your own risk."), tr("Ok")); + } + + //! Settings: NIN USB-HID controller + else if (ret == ++Idx) + { + if (++Settings.NINUSBHID >= MAX_ON_OFF) Settings.NINUSBHID = 0; + } + + //! Settings: NIN MaxPads - Number of Gamecube controllers + else if (ret == ++Idx) + { + if (++Settings.NINMaxPads >= 5) Settings.NINMaxPads = 0; + } + + //! Settings: NIN Native Controller + else if (ret == ++Idx) + { + if (++Settings.NINNativeSI >= MAX_ON_OFF) Settings.NINNativeSI = 0; + } + + //! Settings: NIN LED Activity + else if (ret == ++Idx) + { + if (++Settings.NINLED >= MAX_ON_OFF) Settings.NINLED = 0; + } + + //! Settings: NIN OS Report + else if (ret == ++Idx) + { + if (++Settings.NINOSReport >= MAX_ON_OFF) Settings.NINOSReport = 0; + } + + //! Settings: NIN Log to file + else if (ret == ++Idx) + { + if (++Settings.NINLog >= MAX_ON_OFF) Settings.NINLog = 0; + } + + //! Settings: TITLE - Devolution + else if (ret == ++Idx) + { + // This one is a category title + } + + //! Settings: DEVO Memory Card Emulation + else if (ret == ++Idx) + { + if (++Settings.DEVOMCEmulation >= DEVO_MC_MAX_CHOICE) Settings.DEVOMCEmulation = 0; + } + + //! Settings: DEVO Widescreen Patch + else if (ret == ++Idx) + { + if (++Settings.DEVOWidescreen >= MAX_ON_OFF) Settings.DEVOWidescreen = 0; + } + + //! Settings: DEVO Activity LED + else if (ret == ++Idx) + { + if (++Settings.DEVOActivityLED >= MAX_ON_OFF) Settings.DEVOActivityLED = 0; + } + + //! Settings: DEVO F-Zero AX unlock patch + else if (ret == ++Idx) + { + if (++Settings.DEVOFZeroAX >= MAX_ON_OFF) Settings.DEVOFZeroAX = 0; + } + + //! Settings: DEVO Timer Fix + else if (ret == ++Idx) + { + if (++Settings.DEVOTimerFix >= MAX_ON_OFF) Settings.DEVOTimerFix = 0; + } + + //! Settings: DEVO Direct Button Mapping + else if (ret == ++Idx) + { + if (++Settings.DEVODButtons >= MAX_ON_OFF) Settings.DEVODButtons = 0; + } + + //! Settings: DEVO Crop Overscan + else if (ret == ++Idx) + { + if (++Settings.DEVOCropOverscan >= MAX_ON_OFF) Settings.DEVOCropOverscan = 0; + } + + //! Settings: DEVO Disc Read Delay + else if (ret == ++Idx) + { + if (++Settings.DEVODiscDelay >= MAX_ON_OFF) Settings.DEVODiscDelay = 0; + } + + SetOptionValues(); + + return MENU_NONE; +} + diff --git a/source/settings/menus/LoaderSettings.hpp b/source/settings/menus/LoaderSettings.hpp new file mode 100644 index 0000000..b087ad8 --- /dev/null +++ b/source/settings/menus/LoaderSettings.hpp @@ -0,0 +1,46 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef LOADERSETTINGS_HPP_ +#define LOADERSETTINGS_HPP_ + +#include "SettingsMenu.hpp" + +class LoaderSettings : public SettingsMenu +{ + public: + LoaderSettings(); + ~LoaderSettings(); + protected: + void SetOptionNames(); + void SetOptionValues(); + int GetMenuInternal(); + + short oldLoaderMode; + short oldGameCubeSource; + short oldLoaderIOS; + OptionList GuiOptions; +}; + + +#endif diff --git a/source/settings/menus/ParentalControlSM.cpp b/source/settings/menus/ParentalControlSM.cpp new file mode 100644 index 0000000..bee97ea --- /dev/null +++ b/source/settings/menus/ParentalControlSM.cpp @@ -0,0 +1,406 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "ParentalControlSM.hpp" +#include "settings/CSettings.h" +#include "prompts/PromptWindows.h" +#include "language/gettext.h" +#include "utils/PasswordCheck.h" + +static const char * OnOffText[MAX_ON_OFF] = +{ + trNOOP( "OFF" ), + trNOOP( "ON" ) +}; + +static const char * LockModeText[] = +{ + trNOOP( "Locked" ), + trNOOP( "Unlocked" ) +}; + +static const char * ParentalText[5] = +{ + trNOOP( "0 (Everyone)" ), + trNOOP( "1 (Child 7+)" ), + trNOOP( "2 (Teen 12+)" ), + trNOOP( "3 (Mature 16+)" ), + trNOOP( "4 (Adults Only 18+)" ) +}; + +ParentalControlSM::ParentalControlSM() + : SettingsMenu(tr("Parental Control"), &GuiOptions, MENU_NONE) +{ + int Idx = 0; + Options->SetName(Idx++, "%s", tr( "Console" )); + Options->SetName(Idx++, "%s", tr( "Password" )); + Options->SetName(Idx++, "%s", tr( "Controllevel" )); + Options->SetName(Idx++, "%s", tr( "Remember Unlock" )); + Options->SetName(Idx++, "%s", tr( "Block Global Settings" )); + Options->SetName(Idx++, "%s", tr( "Block Gui Settings" )); + Options->SetName(Idx++, "%s", tr( "Block Loader Settings" )); + Options->SetName(Idx++, "%s", tr( "Block Hard Drive Settings" )); + Options->SetName(Idx++, "%s", tr( "Block Feature Settings" )); + Options->SetName(Idx++, "%s", tr( "Block Parental Settings" )); + Options->SetName(Idx++, "%s", tr( "Block Sound Settings" )); + Options->SetName(Idx++, "%s", tr( "Block Theme Downloader" )); + Options->SetName(Idx++, "%s", tr( "Block Theme Menu" )); + Options->SetName(Idx++, "%s", tr( "Block Custom Paths" )); + Options->SetName(Idx++, "%s", tr( "Block Updates" )); + Options->SetName(Idx++, "%s", tr( "Block Reset Settings" )); + Options->SetName(Idx++, "%s", tr( "Block Game Settings" )); + Options->SetName(Idx++, "%s", tr( "Block HBC Menu" )); + Options->SetName(Idx++, "%s", tr( "Block Title Launcher" )); + Options->SetName(Idx++, "%s", tr( "Block Cover Downloads" )); + Options->SetName(Idx++, "%s", tr( "Block Game Install" )); + Options->SetName(Idx++, "%s", tr( "Block GameID Change" )); + Options->SetName(Idx++, "%s", tr( "Block Categories Menu" )); + Options->SetName(Idx++, "%s", tr( "Block Categories Modify" )); + Options->SetName(Idx++, "%s", tr( "Block SD Reload Button" )); + Options->SetName(Idx++, "%s", tr( "Block Priiloader Override" )); + Options->SetName(Idx++, "%s", tr( "Block Loader Mode Button" )); + Options->SetName(Idx++, "%s", tr( "Block Loader Layout Button" )); + + SetOptionValues(); +} + +void ParentalControlSM::SetOptionValues() +{ + int Idx = 0; + + //! Settings: Console + Options->SetValue(Idx++, "%s", tr( LockModeText[Settings.godmode] )); + + if(!Settings.godmode) + { + for(int i = Idx; i < Options->GetLength(); ++i) + Options->SetValue(i, "********"); + + return; + } + + //! Settings: Password + if (strcmp(Settings.unlockCode, "") == 0) + Options->SetValue(Idx++, "%s", tr( "not set" )); + else + Options->SetValue(Idx++, Settings.unlockCode); + + //! Settings: Controllevel + Options->SetValue(Idx++, "%s", tr(ParentalText[Settings.parentalcontrol])); + + //! Settings: Remember Unlock + Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.RememberUnlock])); + + //! Settings: Block Global Settings + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_GLOBAL_SETTINGS) != 0)])); + + //! Settings: Block Gui Settings + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_GUI_SETTINGS) != 0)])); + + //! Settings: Block Loader Settings + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_LOADER_SETTINGS) != 0)])); + + //! Settings: Block Hard Drive Settings + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_HARD_DRIVE_SETTINGS) != 0)])); + + //! Settings: Block Feature Settings + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_FEATURE_SETTINGS) != 0)])); + + //! Settings: Block Parental Settings + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_PARENTAL_SETTINGS) != 0)])); + + //! Settings: Block Sound Settings + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_SOUND_SETTINGS) != 0)])); + + //! Settings: Block Theme Downloader + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_THEME_DOWNLOADER) != 0)])); + + //! Settings: Block Theme Menu + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_THEME_MENU) != 0)])); + + //! Settings: Block Custom Paths + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_CUSTOMPATH_SETTINGS) != 0)])); + + //! Settings: Block Updates + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_UPDATES) != 0)])); + + //! Settings: Block Reset Settings + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_RESET_SETTINGS) != 0)])); + + //! Settings: Block Game Settings + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_GAME_SETTINGS) != 0)])); + + //! Settings: Block HBC Menu + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_HBC_MENU) != 0)])); + + //! Settings: Block Title Launcher + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_TITLE_LAUNCHER_MENU) != 0)])); + + //! Settings: Block Cover Downloads + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_COVER_DOWNLOADS) != 0)])); + + //! Settings: Block Game Install + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_GAME_INSTALL) != 0)])); + + //! Settings: Block GameID Change + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_GAMEID_CHANGE) != 0)])); + + //! Settings: Block Categories Menu + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_CATEGORIES_MENU) != 0)])); + + //! Settings: Block Categories Modify + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_CATEGORIES_MOD) != 0)])); + + //! Settings: Block SD Reload Button + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_SD_RELOAD_BUTTON) != 0)])); + + //! Settings: Block Priiloader Override + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_PRIILOADER_OVERRIDE) != 0)])); + + //! Settings: Block Loader Mode Button + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_LOADER_MODE_BUTTON) != 0)])); + + //! Settings: Block Loader Layout Button + Options->SetValue(Idx++, "%s", tr(OnOffText[((Settings.ParentalBlocks & BLOCK_LOADER_LAYOUT_BUTTON) != 0)])); +} + +int ParentalControlSM::GetMenuInternal() +{ + int ret = optionBrowser->GetClickedOption(); + + if (ret < 0) + return MENU_NONE; + + int Idx = -1; + + //! Settings: Console + if (ret == ++Idx) + { + if (!Settings.godmode) + { + //password check to unlock Install,Delete and Format + SetState(STATE_DISABLED); + int result = PasswordCheck(Settings.unlockCode); + SetState(STATE_DEFAULT); + if (result > 0) + { + if(result == 1) + WindowPrompt( tr( "Correct Password" ), tr( "All the features of USB Loader GX are unlocked." ), tr( "OK" )); + Settings.godmode = 1; + } + else if(result < 0) + WindowPrompt(tr( "Wrong Password" ), tr( "USB Loader GX is protected" ), tr( "OK" )); + } + else + { + int choice = WindowPrompt(tr( "Lock Console" ), tr( "Are you sure?" ), tr( "Yes" ), tr( "No" )); + if (choice == 1) + { + WindowPrompt(tr( "Console Locked" ), tr( "USB Loader GX is protected" ), tr( "OK" )); + Settings.godmode = 0; + } + } + } + + //! General permission check for all following + else if(!Settings.godmode) + { + WindowPrompt(tr( "Permission denied." ), tr( "Console must be unlocked for this option." ), tr( "OK" )); + } + + //! Settings: Password + else if (ret == ++Idx) + { + char entered[20]; + SetState(STATE_DISABLED); + snprintf(entered, sizeof(entered), Settings.unlockCode); + int result = OnScreenKeyboard(entered, 20, 0); + SetState(STATE_DEFAULT); + if (result == 1) + { + snprintf(Settings.unlockCode, sizeof(Settings.unlockCode), entered); + WindowPrompt(tr( "Password Changed" ), tr( "Password has been changed" ), tr( "OK" )); + } + } + + //! Settings: Controllevel + else if (ret == ++Idx) + { + if (++Settings.parentalcontrol >= 5) Settings.parentalcontrol = 0; + } + + //! Settings: Remember Unlock + else if (ret == ++Idx) + { + if (++Settings.RememberUnlock >= MAX_ON_OFF) Settings.RememberUnlock = 0; + } + + //! Settings: Block Global Settings + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_GLOBAL_SETTINGS; + } + + //! Settings: Block Gui Settings + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_GUI_SETTINGS; + } + + //! Settings: Block Loader Settings + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_LOADER_SETTINGS; + } + + //! Settings: Hard Drive Settings + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_HARD_DRIVE_SETTINGS; + } + + //! Settings: Block Feature Settings + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_FEATURE_SETTINGS; + } + + //! Settings: Block Parental Settings + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_PARENTAL_SETTINGS; + } + + //! Settings: Block Sound Settings + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_SOUND_SETTINGS; + } + + //! Settings: Block Theme Downloader + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_THEME_DOWNLOADER; + } + + //! Settings: Block Theme Menu + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_THEME_MENU; + } + + //! Settings: Block Custom Paths + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_CUSTOMPATH_SETTINGS; + } + + //! Settings: Block Updates + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_UPDATES; + } + + //! Settings: Block Reset Settings + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_RESET_SETTINGS; + } + + //! Settings: Block Game Settings + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_GAME_SETTINGS; + } + + //! Settings: Block HBC Menu + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_HBC_MENU; + } + + //! Settings: Block Title Launcher + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_TITLE_LAUNCHER_MENU; + } + + //! Settings: Block Cover Downloads + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_COVER_DOWNLOADS; + } + + //! Settings: Block Game Install + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_GAME_INSTALL; + } + + //! Settings: Block GameID Change + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_GAMEID_CHANGE; + } + + //! Settings: Block Categories Menu + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_CATEGORIES_MENU; + } + + //! Settings: Block Categories Modify + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_CATEGORIES_MOD; + } + + //! Settings: Block SD Reload Button + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_SD_RELOAD_BUTTON; + } + + //! Settings: Block Priiloader Override + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_PRIILOADER_OVERRIDE; + } + + //! Settings: Block Loader Mode Button + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_LOADER_MODE_BUTTON; + } + + //! Settings: Block Loader Layout Button + else if (ret == ++Idx) + { + Settings.ParentalBlocks ^= BLOCK_LOADER_LAYOUT_BUTTON; + } + + SetOptionValues(); + + return MENU_NONE; +} diff --git a/source/settings/menus/ParentalControlSM.hpp b/source/settings/menus/ParentalControlSM.hpp new file mode 100644 index 0000000..27541ed --- /dev/null +++ b/source/settings/menus/ParentalControlSM.hpp @@ -0,0 +1,41 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef PARENTALCONTROL_MENU_HPP_ +#define PARENTALCONTROL_MENU_HPP_ + +#include "SettingsMenu.hpp" + +class ParentalControlSM : public SettingsMenu +{ + public: + ParentalControlSM(); + protected: + void SetOptionValues(); + int GetMenuInternal(); + + OptionList GuiOptions; +}; + + +#endif diff --git a/source/settings/menus/SettingsMenu.cpp b/source/settings/menus/SettingsMenu.cpp new file mode 100644 index 0000000..1994557 --- /dev/null +++ b/source/settings/menus/SettingsMenu.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "SettingsMenu.hpp" +#include "themes/CTheme.h" +#include "language/gettext.h" + +SettingsMenu::SettingsMenu(const char * title, OptionList * opts, int returnTo) + : GuiWindow(screenwidth, screenheight) +{ + Options = opts; + returnToMenu = returnTo; + trigA = NULL; + trigB = NULL; + backBtnTxt = NULL; + backBtnImg = NULL; + backBtn = NULL; + btnOutline = NULL; + + //! Skipping back button if there is no menu defined to go back to + if(returnToMenu != MENU_NONE) + { + btnOutline = Resources::GetImageData("button_dialogue_box.png"); + + trigA = new GuiTrigger(); + trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + + trigB = new GuiTrigger(); + trigB->SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + backBtnTxt = new GuiText(tr("Back"), 22, (GXColor){0, 0, 0, 255}); + backBtnImg = new GuiImage(btnOutline); + backBtn = new GuiButton(backBtnImg, backBtnImg, 2, 3, -180, 400, trigA, btnSoundOver, btnSoundClick2, 1); + backBtn->SetLabel(backBtnTxt); + backBtn->SetTrigger(trigB); + Append(backBtn); + } + + optionBrowser = new GuiOptionBrowser(396, 280, Options, "bg_options_settings.png"); + optionBrowser->SetAlignment(thAlign("center - settings option browser align hor"), thAlign("top - settings option browser align ver")); + optionBrowser->SetPosition(thInt("0 - settings option browser pos x"), thInt("90 - settings option browser pos y")); + + titleTxt = new GuiText(title, 28, thColor("r=0 g=0 b=0 a=255 - settings title text color")); + titleTxt->SetAlignment(thAlign("center - settings title text align hor"), thAlign("top - settings title text align ver")); + titleTxt->SetPosition(thInt("0 - settings title text pos x"), thInt("40 - settings title text pos y")); + titleTxt->SetMaxWidth(thInt("310 - settings title text max width"), SCROLL_HORIZONTAL); + + Append(optionBrowser); + Append(titleTxt); + + SetEffect(EFFECT_FADE, 50); +} + +SettingsMenu::~SettingsMenu() +{ + ResumeGui(); + + SetEffect(EFFECT_FADE, -50); + while(this->GetEffect() > 0) + usleep(100); + + HaltGui(); + if(parentElement) + ((GuiWindow *) parentElement)->Remove(this); + + RemoveAll(); + + if(btnOutline) + delete btnOutline; + + if(backBtnTxt) + delete backBtnTxt; + if(backBtnImg) + delete backBtnImg; + if(backBtn) + delete backBtn; + + if(trigA) + delete trigA; + if(trigB) + delete trigB; + + delete titleTxt; + + delete optionBrowser; + + ResumeGui(); +} + +int SettingsMenu::GetClickedOption() +{ + if(!optionBrowser) + return -1; + + return optionBrowser->GetClickedOption(); +} + +int SettingsMenu::GetMenu() +{ + if(backBtn && backBtn->GetState() == STATE_CLICKED) + return returnToMenu; + + return GetMenuInternal(); +} diff --git a/source/settings/menus/SettingsMenu.hpp b/source/settings/menus/SettingsMenu.hpp new file mode 100644 index 0000000..c25ae37 --- /dev/null +++ b/source/settings/menus/SettingsMenu.hpp @@ -0,0 +1,59 @@ + /**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef SETTINGS_MENU_HPP_ +#define SETTINGS_MENU_HPP_ + +#include "GUI/gui.h" +#include "GUI/gui_optionbrowser.h" +#include "menu.h" + +class SettingsMenu : public GuiWindow +{ + public: + SettingsMenu(const char * title, OptionList * option, int returnTo); + virtual ~SettingsMenu(); + int GetClickedOption(); + int GetMenu(); + protected: + virtual int GetMenuInternal() { return MENU_NONE; }; + int returnToMenu; + + GuiImageData * btnOutline; + + GuiTrigger * trigA; + GuiTrigger * trigB; + + OptionList * Options; + + GuiText * titleTxt; + GuiText * backBtnTxt; + GuiImage * backBtnImg; + GuiButton * backBtn; + + GuiOptionBrowser * optionBrowser; + +}; + + +#endif diff --git a/source/settings/menus/SoundSettingsMenu.cpp b/source/settings/menus/SoundSettingsMenu.cpp new file mode 100644 index 0000000..f42f0b3 --- /dev/null +++ b/source/settings/menus/SoundSettingsMenu.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "SoundSettingsMenu.hpp" +#include "settings/CSettings.h" +#include "settings/SettingsPrompts.h" +#include "prompts/PromptWindows.h" +#include "language/gettext.h" + +static const char * GameSoundText[] = +{ + trNOOP( "Sound+Quiet" ), + trNOOP( "Sound+BGM" ), + trNOOP( "Loop Sound" ), +}; + +static const char * MusicLoopText[] = +{ + trNOOP( "Play Once" ), + trNOOP( "Loop Music" ), + trNOOP( "Random Directory Music" ), + trNOOP( "Loop Directory" ), +}; + +SoundSettingsMenu::SoundSettingsMenu() + : SettingsMenu(tr("Sound Settings"), &GuiOptions, MENU_NONE) +{ + int Idx = 0; + Options->SetName(Idx++, "%s", tr( "Backgroundmusic" )); + Options->SetName(Idx++, "%s", tr( "Music Volume" )); + Options->SetName(Idx++, "%s", tr( "SFX Volume" )); + Options->SetName(Idx++, "%s", tr( "Game Sound Mode" )); + Options->SetName(Idx++, "%s", tr( "Game Sound Volume" )); + Options->SetName(Idx++, "%s", tr( "Music Loop Mode" )); + Options->SetName(Idx++, "%s", tr( "Reset BG Music" )); + + SetOptionValues(); +} + +void SoundSettingsMenu::SetOptionValues() +{ + int Idx = 0; + + //! Settings: Backgroundmusic + const char * filename = strrchr(Settings.ogg_path, '/'); + if (filename) + Options->SetValue(Idx++, filename+1); + else + Options->SetValue(Idx++, tr( "Default" )); + + //! Settings: Music Volume + if (Settings.volume > 0) + Options->SetValue(Idx++, "%i", Settings.volume); + else + Options->SetValue(Idx++, tr( "OFF" )); + + //! Settings: SFX Volume + if (Settings.sfxvolume > 0) + Options->SetValue(Idx++, "%i", Settings.sfxvolume); + else + Options->SetValue(Idx++, tr( "OFF" )); + + //! Settings: Game Sound Mode + Options->SetValue(Idx++, "%s", tr( GameSoundText[Settings.gamesound] )); + + //! Settings: Game Sound Volume + if (Settings.gamesoundvolume > 0) + Options->SetValue(Idx++, "%i", Settings.gamesoundvolume); + else + Options->SetValue(Idx++, tr( "OFF" )); + + //! Settings: Music Loop Mode + Options->SetValue(Idx++, tr( MusicLoopText[Settings.musicloopmode] )); + + //! Settings: Reset BG Music + Options->SetValue(Idx++, " "); +} + +int SoundSettingsMenu::GetMenuInternal() +{ + int ret = optionBrowser->GetClickedOption(); + + if (ret < 0) + return MENU_NONE; + + int Idx = -1; + + //! Settings: Backgroundmusic + if (ret == ++Idx) + { + GuiWindow * parent = (GuiWindow *) parentElement; + if(parent) parent->SetState(STATE_DISABLED); + + MenuBackgroundMusic(); + + if(parent) parent->SetState(STATE_DEFAULT); + } + + //! Settings: Music Volume + else if (ret == ++Idx) + { + Settings.volume += 10; + if (Settings.volume > 100) Settings.volume = 0; + bgMusic->SetVolume(Settings.volume); + } + + //! Settings: SFX Volume + else if (ret == ++Idx) + { + Settings.sfxvolume += 10; + if (Settings.sfxvolume > 100) Settings.sfxvolume = 0; + btnSoundOver->SetVolume(Settings.sfxvolume); + btnSoundClick->SetVolume(Settings.sfxvolume); + btnSoundClick2->SetVolume(Settings.sfxvolume); + } + + //! Settings: Game Sound Mode + else if (ret == ++Idx) + { + if (++Settings.gamesound > 2) Settings.gamesound = 0; + } + + //! Settings: Game Sound Volume + else if (ret == ++Idx) + { + Settings.gamesoundvolume += 10; + if (Settings.gamesoundvolume > 100) Settings.gamesoundvolume = 0; + } + + //! Settings: Music Loop Mode + else if (ret == ++Idx) + { + if (++Settings.musicloopmode > 3) Settings.musicloopmode = 0; + bgMusic->SetLoop(Settings.musicloopmode); + } + + //! Settings: Reset BG Music + else if (ret == ++Idx) + { + int result = WindowPrompt(tr( "Reset to default BGM?" ), 0, tr( "Yes" ), tr( "No" )); + if (result) + { + bgMusic->LoadStandard(); + bgMusic->Play(); + } + } + + SetOptionValues(); + + return MENU_NONE; +} diff --git a/source/settings/menus/SoundSettingsMenu.hpp b/source/settings/menus/SoundSettingsMenu.hpp new file mode 100644 index 0000000..80d49c5 --- /dev/null +++ b/source/settings/menus/SoundSettingsMenu.hpp @@ -0,0 +1,41 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef SOUNDSETTINGS_MENU_HPP_ +#define SOUNDSETTINGS_MENU_HPP_ + +#include "SettingsMenu.hpp" + +class SoundSettingsMenu : public SettingsMenu +{ + public: + SoundSettingsMenu(); + protected: + void SetOptionValues(); + int GetMenuInternal(); + + OptionList GuiOptions; +}; + + +#endif diff --git a/source/settings/menus/UninstallSM.cpp b/source/settings/menus/UninstallSM.cpp new file mode 100644 index 0000000..bd0a325 --- /dev/null +++ b/source/settings/menus/UninstallSM.cpp @@ -0,0 +1,272 @@ + /**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include "UninstallSM.hpp" +#include "FileOperations/fileops.h" +#include "GameCube/GCGames.h" +#include "Channels/channels.h" +#include "settings/CSettings.h" +#include "settings/CGameSettings.h" +#include "settings/CGameStatistics.h" +#include "settings/GameTitles.h" +#include "prompts/PromptWindows.h" +#include "language/gettext.h" +#include "usbloader/wbfs.h" +#include "usbloader/GameList.h" +#include "wstring.hpp" + +UninstallSM::UninstallSM(struct discHdr * header) + : SettingsMenu(tr("Uninstall Menu"), &GuiOptions, MENU_NONE) +{ + DiscHeader = header; + + int Idx = 0; + + if( DiscHeader->type == TYPE_GAME_WII_IMG + || DiscHeader->type == TYPE_GAME_GC_IMG + || DiscHeader->type == TYPE_GAME_EMUNANDCHAN) + { + Options->SetName(Idx++, "%s", tr( "Uninstall Game" )); + } + Options->SetName(Idx++, "%s", tr( "Reset Playcounter" )); + Options->SetName(Idx++, "%s", tr( "Delete Cover Artwork" )); + Options->SetName(Idx++, "%s", tr( "Delete Disc Artwork" )); + Options->SetName(Idx++, "%s", tr( "Delete Cached Banner" )); + Options->SetName(Idx++, "%s", tr( "Delete Cheat TXT" )); + Options->SetName(Idx++, "%s", tr( "Delete Cheat GCT" )); + + SetOptionValues(); +} + +void UninstallSM::SetOptionValues() +{ + int Idx = 0; + + if( DiscHeader->type == TYPE_GAME_WII_IMG + || DiscHeader->type == TYPE_GAME_GC_IMG + || DiscHeader->type == TYPE_GAME_EMUNANDCHAN) + { + //! Settings: Uninstall Game + Options->SetValue(Idx++, " "); + } + + //! Settings: Reset Playcounter + Options->SetValue(Idx++, " "); + + //! Settings: Delete Cover Artwork + Options->SetValue(Idx++, " "); + + //! Settings: Delete Disc Artwork + Options->SetValue(Idx++, " "); + + //! Settings: Delete Cached Banner + Options->SetValue(Idx++, " "); + + //! Settings: Delete Cheat TXT + Options->SetValue(Idx++, " "); + + //! Settings: Delete Cheat GCT + Options->SetValue(Idx++, " "); +} + +int UninstallSM::GetMenuInternal() +{ + int ret = optionBrowser->GetClickedOption(); + + if (ret < 0) + return MENU_NONE; + + int Idx = -1; + + //! Settings: Uninstall Game + if( (DiscHeader->type == TYPE_GAME_WII_IMG + || DiscHeader->type == TYPE_GAME_GC_IMG + || DiscHeader->type == TYPE_GAME_EMUNANDCHAN) + && ret == ++Idx) + { + int choice = WindowPrompt(GameTitles.GetTitle(DiscHeader), tr( "What should be deleted for this game title:" ), tr( "Game Only" ), tr("Uninstall all"), tr( "Cancel" )); + if (choice == 0) + return MENU_NONE; + + char GameID[7]; + snprintf(GameID, sizeof(GameID), "%s", (char *) DiscHeader->id); + + std::string Title = GameTitles.GetTitle(DiscHeader); + GameSettings.Remove(DiscHeader->id); + GameSettings.Save(); + GameStatistics.Remove(DiscHeader->id); + GameStatistics.Save(); + + int ret = 0; + char filepath[512]; + + if(DiscHeader->type == TYPE_GAME_WII_IMG) + { + ret = WBFS_RemoveGame((u8 *) GameID); + if(ret >= 0) + { + wString oldFilter(gameList.GetCurrentFilter()); + gameList.ReadGameList(); + gameList.FilterList(oldFilter.c_str()); + } + } + else if(DiscHeader->type == TYPE_GAME_GC_IMG) + { + GCGames::Instance()->RemoveGame(GameID); + // Reload list + GCGames::Instance()->LoadAllGames(); + } + else if(DiscHeader->type == TYPE_GAME_EMUNANDCHAN && DiscHeader->tid != 0) + { + // Remove ticket + snprintf(filepath, sizeof(filepath), "%s/ticket/%08x/%08x.tik", Settings.NandEmuChanPath, (unsigned int) (DiscHeader->tid >> 32), (unsigned int) DiscHeader->tid); + RemoveFile(filepath); + + // Remove contents / data + snprintf(filepath, sizeof(filepath), "%s/title/%08x/%08x/", Settings.NandEmuChanPath, (unsigned int) (DiscHeader->tid >> 32), (unsigned int) DiscHeader->tid); + RemoveDirectory(filepath); + + Channels::Instance()->GetEmuChannelList(); + } + + if(choice == 2) + { + snprintf(filepath, sizeof(filepath), "%s%s.png", Settings.covers_path, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%s.png", Settings.covers2d_path, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%s.png", Settings.coversFull_path, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%s.png", Settings.disc_path, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%s.bnr", Settings.BNRCachePath, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%.4s.bnr", Settings.BNRCachePath, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%.3s.bnr", Settings.BNRCachePath, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%s.txt", Settings.TxtCheatcodespath, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%s.gct", Settings.Cheatcodespath, GameID); + if (CheckFile(filepath)) remove(filepath); + } + + if (ret < 0) + WindowPrompt(tr( "Can't delete:" ), Title.c_str(), tr( "OK" )); + else + WindowPrompt(tr( "Successfully deleted:" ), Title.c_str(), tr( "OK" )); + + return MENU_DISCLIST; + } + + //! Settings: Reset Playcounter + else if (ret == ++Idx) + { + int result = WindowPrompt(tr( "Are you sure?" ), 0, tr( "Yes" ), tr( "Cancel" )); + if (result == 1) + { + GameStatistics.SetPlayCount(DiscHeader->id, 0); + GameStatistics.Save(); + } + } + + //! Settings: Delete Cover Artwork + else if (ret == ++Idx) + { + int choice = WindowPrompt(tr( "Delete" ), tr("Are you sure?"), tr( "Yes" ), tr( "No" )); + if (choice != 1) + return MENU_NONE; + + char GameID[7]; + snprintf(GameID, sizeof(GameID), "%s", (char *) DiscHeader->id); + char filepath[200]; + snprintf(filepath, sizeof(filepath), "%s%s.png", Settings.covers_path, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%s.png", Settings.covers2d_path, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%s.png", Settings.coversFull_path, GameID); + if (CheckFile(filepath)) remove(filepath); + } + + //! Settings: Delete Disc Artwork + else if (ret == ++Idx) + { + char GameID[7]; + snprintf(GameID, sizeof(GameID), "%s", (char *) DiscHeader->id); + char filepath[200]; + snprintf(filepath, sizeof(filepath), "%s%s.png", Settings.disc_path, GameID); + + int choice = WindowPrompt(tr( "Delete" ), filepath, tr( "Yes" ), tr( "No" )); + if (choice == 1) + if (CheckFile(filepath)) remove(filepath); + } + + //! Settings: Delete Cached Banner + else if (ret == ++Idx) + { + int choice = WindowPrompt(tr( "Delete" ), tr("Are you sure?"), tr( "Yes" ), tr( "No" )); + if (choice != 1) + return MENU_NONE; + + char GameID[7]; + snprintf(GameID, sizeof(GameID), "%s", (char *) DiscHeader->id); + char filepath[200]; + snprintf(filepath, sizeof(filepath), "%s%s.bnr", Settings.BNRCachePath, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%.4s.bnr", Settings.BNRCachePath, GameID); + if (CheckFile(filepath)) remove(filepath); + snprintf(filepath, sizeof(filepath), "%s%.3s.bnr", Settings.BNRCachePath, GameID); + if (CheckFile(filepath)) remove(filepath); + } + + //! Settings: Delete Cheat TXT + else if (ret == ++Idx) + { + char GameID[7]; + snprintf(GameID, sizeof(GameID), "%s", (char *) DiscHeader->id); + char filepath[200]; + snprintf(filepath, sizeof(filepath), "%s%s.txt", Settings.TxtCheatcodespath, GameID); + + int choice = WindowPrompt(tr( "Delete" ), filepath, tr( "Yes" ), tr( "No" )); + if (choice == 1) + if (CheckFile(filepath)) remove(filepath); + } + + //! Settings: Delete Cheat GCT + else if (ret == ++Idx) + { + char GameID[7]; + snprintf(GameID, sizeof(GameID), "%s", (char *) DiscHeader->id); + char filepath[200]; + snprintf(filepath, sizeof(filepath), "%s%s.gct", Settings.Cheatcodespath, GameID); + + int choice = WindowPrompt(tr( "Delete" ), filepath, tr( "Yes" ), tr( "No" )); + if (choice == 1) + if (CheckFile(filepath)) remove(filepath); + } + + SetOptionValues(); + + return MENU_NONE; +} diff --git a/source/settings/menus/UninstallSM.hpp b/source/settings/menus/UninstallSM.hpp new file mode 100644 index 0000000..be436c0 --- /dev/null +++ b/source/settings/menus/UninstallSM.hpp @@ -0,0 +1,43 @@ + /**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef UNINSTALL_MENU_HPP_ +#define UNINSTALL_MENU_HPP_ + +#include "SettingsMenu.hpp" + +class UninstallSM : public SettingsMenu +{ + public: + UninstallSM(struct discHdr * header); + protected: + void SetOptionValues(); + int GetMenuInternal(); + + struct discHdr * DiscHeader; + + OptionList GuiOptions; +}; + + +#endif diff --git a/source/settings/meta.cpp b/source/settings/meta.cpp new file mode 100644 index 0000000..ca45a4f --- /dev/null +++ b/source/settings/meta.cpp @@ -0,0 +1,118 @@ +/* +Copyright (c) 2014 - Cyan + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include "homebrewboot/HomebrewXML.h" +#include "FileOperations/fileops.h" +#include "settings/CSettings.h" +#include "svnrev.h" + +int updateMetaXML (void) +{ + HomebrewXML MetaXML; + char filepath[255]; + snprintf(filepath, sizeof(filepath), "%s/meta.xml", Settings.update_path); + if(!MetaXML.LoadHomebrewXMLData(filepath)) + return 0; + + char line[50]; + snprintf(line, sizeof(line), "--ios=%d", Settings.LoaderIOS); + MetaXML.SetArgument(line); + snprintf(line, sizeof(line), "--usbport=%d", Settings.USBPort); + MetaXML.SetArgument(line); + snprintf(line, sizeof(line), "--mountusb=%d", Settings.USBAutoMount); + MetaXML.SetArgument(line); + snprintf(line, sizeof(line), "3.0 r%s", GetRev()); + MetaXML.SetVersion(line); + + int ret = MetaXML.SaveHomebrewXMLData(filepath); + return ret; +} + +int editMetaArguments (void) +{ + char metapath[255] = ""; + char metatmppath[255] = ""; + + snprintf(metapath, sizeof(metapath), "%s/meta.xml", Settings.update_path); + snprintf(metatmppath, sizeof(metatmppath), "%s/meta.tmp", Settings.update_path); + + FILE *source = fopen(metapath, "rb"); + if(!source) + { + return 0; + } + + FILE *destination = fopen(metatmppath, "wb"); + if(!destination) + { + fclose(source); + return 0; + } + + const int max_line_size = 255; + char *line = new char[max_line_size]; + while (fgets(line, max_line_size, source) != NULL) + { + // delete commented lines + if( strstr(line, "") != NULL) + { + strcpy(line, " \n"); + } + + // generate argurments + if(strstr(line, "") != NULL) + { + fputs(line, destination); + snprintf(line, max_line_size, " --ios=%d\n", Settings.LoaderIOS); + fputs(line, destination); + snprintf(line, max_line_size, " --usbport=%d\n", Settings.USBPort); + fputs(line, destination); + snprintf(line, max_line_size, " --mountusb=%d\n", Settings.USBAutoMount); + fputs(line, destination); + + while(strstr(line, "") == NULL) + { + fgets(line, max_line_size, source); // advance one line + if(feof(source)) + { + fclose(source); + fclose(destination); + delete [] line; + return 0; + } + } + } + fputs(line, destination); + } + + fclose(source); + fclose(destination); + delete [] line; + + if(CopyFile(metatmppath, metapath) <0) + return 0; + + RemoveFile(metatmppath); + + return 1; +} diff --git a/source/settings/meta.h b/source/settings/meta.h new file mode 100644 index 0000000..98bb6fa --- /dev/null +++ b/source/settings/meta.h @@ -0,0 +1,30 @@ +/**************************************************************************** + * Copyright (C) 2014 + * by cyan + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _META_H_ +#define _META_H_ + +int updateMetaXML(void); +int editMetaArguments(void); + +#endif diff --git a/source/settings/newtitles.cpp b/source/settings/newtitles.cpp new file mode 100644 index 0000000..9398a1b --- /dev/null +++ b/source/settings/newtitles.cpp @@ -0,0 +1,199 @@ +#include +#include + +#include "CSettings.h" +#include "settings/CGameStatistics.h" +#include "newtitles.h" + +#define NEW_SECONDS (24 * 60 * 60) +#define GAMETITLES "GameTimestamps.txt" + +NewTitles *NewTitles::instance = NULL; + +NewTitles::NewTitles() +{ + firstTitle = lastTitle = NULL; + isDirty = isNewFile = false; + Reload(); +} + +NewTitles::~NewTitles() +{ + Save(); + Clean(); +} + +void NewTitles::Clean(void) +{ + Title *t = firstTitle; + while (t != NULL) + { + Title *temp = t->next; + delete t; + t = temp; + } + firstTitle = lastTitle = NULL; + isDirty = isNewFile = false; +} + +void NewTitles::Reload(void) +{ + Save(); + Clean(); + + // Read the text file + char path[255]; + snprintf(path, sizeof(path), "%s/%s", Settings.titlestxt_path, GAMETITLES); + + char line[50]; + FILE *fp = fopen(path, "rb"); + if (!fp) + { + isNewFile = true; + return; + } + + time_t currenttime = time(0); + + while (fgets(line, sizeof(line), fp)) + { + // This is one line + if (line[0] == '#' || line[0] == ';') + continue; + + Title *title = new Title; + memset(title, 0, sizeof(Title)); + + char *delimeter = strchr(line, ':'); + if(!delimeter || ((delimeter-line) > 6)) // check for valid delimiter + continue; + + *delimeter = '\0'; + + snprintf(title->titleId, sizeof(title->titleId), "%s", line); + title->timestamp = strtoul(delimeter+1, 0, 10); + title->isNew = ((currenttime - title->timestamp) < NEW_SECONDS); + title->next = NULL; + + if (firstTitle == NULL) + { + firstTitle = title; + lastTitle = title; + } + else + { + lastTitle->next = title; + lastTitle = title; + } + } + + fclose(fp); +} + +void NewTitles::CheckGame(const u8 *titleid) +{ + if (titleid == NULL || strlen((char *) titleid) == 0) + return; + + Title *t = firstTitle; + while (t != NULL) + { + // Loop all titles, search for the correct titleid + if (strncmp((char*)titleid, t->titleId, 6) == 0) + return; // Game found, which is excellent + + t = t->next; + } + + // Not found, add it + t = new Title; + memset(t, 0, sizeof(Title)); + + snprintf(t->titleId, sizeof(t->titleId), "%s", (char *) titleid); + t->timestamp = time(0); + t->next = NULL; + + if (isNewFile) + { + t->isNew = false; + t->timestamp -= (NEW_SECONDS + 1); // Mark all games as not new if this is a new file + } + else + { + GameStatus *Status = GameStatistics.GetGameStatus(titleid); + t->isNew = (Status == NULL || Status->PlayCount == 0); + } + + if (firstTitle == NULL) + { + firstTitle = t; + lastTitle = t; + } + else + { + lastTitle->next = t; + lastTitle = t; + } + isDirty = true; +} + +bool NewTitles::IsNew(const u8 *titleid) const +{ + if (!titleid) return false; + + Title *t = firstTitle; + + while(t != NULL) + { + // Loop all titles, search for the correct titleid + if (strncmp((char*)titleid, t->titleId, 6) == 0) + return t->isNew; + + t = t->next; + } + + return false; +} + +void NewTitles::Remove(const u8 *titleid) +{ + if (titleid == NULL) return; + + Title *t = firstTitle, *prev = NULL; + while (t != NULL) + { + if (strncmp((char*)titleid, t->titleId, 6) == 0) + { + if (prev == NULL) + firstTitle = t->next; + else + prev->next = t->next; + + delete t; + isDirty = true; + return; + } + prev = t; + t = t->next; + } +} + +void NewTitles::Save(void) +{ + if (!isDirty) return; + + char path[255]; + snprintf(path, sizeof(path), "%s/%s", Settings.titlestxt_path, GAMETITLES); + + FILE *fp = fopen(path, "wb"); + if (fp == NULL) + return; + + Title *t = firstTitle; + while (t != NULL && strlen(t->titleId) > 0) + { + fprintf(fp, "%.6s:%lu\n", t->titleId, t->timestamp); + t = t->next; + } + fclose(fp); +} diff --git a/source/settings/newtitles.h b/source/settings/newtitles.h new file mode 100644 index 0000000..2ee10de --- /dev/null +++ b/source/settings/newtitles.h @@ -0,0 +1,38 @@ +#ifndef _NEWTITLES_H +#define _NEWTITLES_H + +#include + +class NewTitles +{ + public: + static NewTitles *Instance() { if(!instance) instance = new NewTitles(); return instance; } + static void DestroyInstance() { delete instance; instance = NULL; } + + void Save(void); + void Clean(void); + void Reload(void); + void CheckGame(const u8 *titleid); + bool IsNew(const u8 *titleid) const; + void Remove(const u8 *titleid); + private: + NewTitles(); + ~NewTitles(); + + static NewTitles *instance; + + struct Title + { + char titleId[7]; + time_t timestamp; + Title *next; + bool isNew; + }; + + Title *firstTitle; + Title *lastTitle; + bool isDirty; + bool isNewFile; +}; + +#endif //_NEWTITLES_H diff --git a/source/svnrev.c b/source/svnrev.c new file mode 100644 index 0000000..ef4f723 --- /dev/null +++ b/source/svnrev.c @@ -0,0 +1,6 @@ +#define SVN_REV "1273" + +const char *GetRev() +{ + return SVN_REV; +} diff --git a/source/svnrev.h b/source/svnrev.h new file mode 100644 index 0000000..5c51aa7 --- /dev/null +++ b/source/svnrev.h @@ -0,0 +1,15 @@ +#ifndef SVNREV_H +#define SVNREV_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + const char *GetRev(); + +#ifdef __cplusplus +} +#endif + +#endif /* SVNREV_H */ diff --git a/source/sys.cpp b/source/sys.cpp new file mode 100644 index 0000000..e29107f --- /dev/null +++ b/source/sys.cpp @@ -0,0 +1,313 @@ +#include +#include +#include + +#include "mload/mload.h" +#include "banner/BannerAsync.h" +#include "Controls/DeviceHandler.hpp" +#include "FileOperations/fileops.h" +#include "homebrewboot/BootHomebrew.h" +#include "homebrewboot/HomebrewXML.h" +#include "settings/CSettings.h" +#include "settings/GameTitles.h" +#include "settings/newtitles.h" +#include "settings/meta.h" +#include "language/gettext.h" +#include "network/networkops.h" +#include "utils/ResourceManager.h" +#include "usbloader/playlog.h" +#include "usbloader/wbfs.h" +#include "GameCube/GCGames.h" +#include "themes/CTheme.h" +#include "SoundOperations/SoundHandler.hpp" +#include "utils/ThreadedTask.hpp" +#include "audio.h" +#include "lstub.h" +#include "menu.h" +#include "video.h" +#include "gecko.h" +#include "wad/nandtitle.h" + +extern "C" +{ + extern s32 MagicPatches(s32); +} + +//Wiilight stuff +void wiilight(int enable) // Toggle wiilight (thanks Bool for wiilight source) +{ + static vu32 *_wiilight_reg = (u32*) 0xCD0000C0; + u32 val = (*_wiilight_reg & ~0x20); + if (enable && Settings.wiilight) val |= 0x20; + *_wiilight_reg = val; +} + +/* Variables */ +u8 shutdown = 0; +u8 reset = 0; + +/* + * True if running from a WiiU Wii Virtual console channel. + * Checked when initializing gamepad in input.c + * Thanks to Fix94 + */ +bool isWiiVC = false; + +void __Sys_ResetCallback(void) +{ + /* Reboot console */ + reset = 1; +} + +void __Sys_PowerCallback(void) +{ + /* Poweroff console */ + shutdown = 1; +} + +void Sys_Init(void) +{ + /* Initialize video subsytem */ + //VIDEO_Init(); + + /* Set RESET/POWER button callback */ + SYS_SetResetCallback(__Sys_ResetCallback); + SYS_SetPowerCallback(__Sys_PowerCallback); +} + +void AppCleanUp(void) +{ + static bool app_clean = false; + if(app_clean) + return; + + app_clean = true; + + BannerAsync::ThreadExit(); + + if(Settings.CacheTitles) + GameTitles.WriteCachedTitles(Settings.titlestxt_path); + Settings.Save(); + + ExitGUIThreads(); + StopGX(); + wiilight(0); + + delete btnSoundClick; + delete btnSoundOver; + delete btnSoundClick2; + delete bgMusic; + delete background; + delete bgImg; + delete mainWindow; + for (int i = 0; i < 4; i++) + delete pointer[i]; + + gettextCleanUp(); + Theme::CleanUp(); + NewTitles::DestroyInstance(); + ThreadedTask::DestroyInstance(); + SoundHandler::DestroyInstance(); + GCGames::DestroyInstance(); + DeinitNetwork(); + GameTitles.SetDefault(); + + ShutdownAudio(); + + ResourceManager::DestroyInstance(); + + WPAD_Shutdown(); + ISFS_Deinitialize(); +} + +void ExitApp(void) +{ + AppCleanUp(); + WBFS_CloseAll(); + DeviceHandler::DestroyInstance(); + USB_Deinitialize(); + if(Settings.PlaylogUpdate) + Playlog_Delete(); // Don't show USB Loader GX in the Wii message board + + MagicPatches(0); +} + +void Sys_Reboot(void) +{ + /* Restart console */ + ExitApp(); + STM_RebootSystem(); +} + +#define ShutdownToDefault 0 +#define ShutdownToIdle 1 +#define ShutdownToStandby 2 + +static void _Sys_Shutdown(int SHUTDOWN_MODE) +{ + ExitApp(); + + /* Poweroff console */ + if ((CONF_GetShutdownMode() == CONF_SHUTDOWN_IDLE && SHUTDOWN_MODE != ShutdownToStandby) || SHUTDOWN_MODE + == ShutdownToIdle) + { + s32 ret; + + /* Set LED mode */ + ret = CONF_GetIdleLedMode(); + if (ret >= 0 && ret <= 2) STM_SetLedMode(ret); + + /* Shutdown to idle */ + STM_ShutdownToIdle(); + } + else + { + /* Shutdown to standby */ + STM_ShutdownToStandby(); + } +} + +void Sys_Shutdown(void) +{ + _Sys_Shutdown(ShutdownToDefault); +} + +void Sys_ShutdownToIdle(void) +{ + _Sys_Shutdown(ShutdownToIdle); +} +void Sys_ShutdownToStandby(void) +{ + _Sys_Shutdown(ShutdownToStandby); +} + +void Sys_LoadMenu(void) +{ + ExitApp(); + + // Priiloader shutup + if (Settings.godmode || !(Settings.ParentalBlocks & BLOCK_PRIILOADER_OVERRIDE)) + { + *(u32 *)0x8132fffb = 0x50756e65; + *(u32 *)0x817feff0 = 0x50756e65; // priiloader 0.8 beta 4+ + DCFlushRange((u32 *)0x8132fffb, 4); + DCFlushRange((u32 *)0x817feff0, 4); + } + + /* Return to the Wii system menu */ + SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); +} + +void Sys_BackToLoader(void) +{ + ExitApp(); + + if (hbcStubAvailable()) + exit(0); + // Channel Version + SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); +} + +#define HBC_HAXX 0x0001000148415858LL +#define HBC_JODI 0x000100014A4F4449LL +#define HBC_1_0_7 0x00010001AF1BF516LL +#define HBC_LULZ 0x000100014c554c5aLL +#define HBC_OHBC 0x000100014F484243LL + +void Sys_LoadHBC(void) +{ + ExitApp(); + + WII_Initialize(); + + // Try launching all known HBC titles in reversed released order + // Can't use HBC Stub address here as it's overwritten with forwarder's TitleID for "return to" feature. + WII_LaunchTitle(HBC_OHBC); + WII_LaunchTitle(HBC_LULZ); + WII_LaunchTitle(HBC_1_0_7); + WII_LaunchTitle(HBC_JODI); + WII_LaunchTitle(HBC_HAXX); + + //Back to system menu if all fails + SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); +} + +bool RebootApp(void) +{ + // be sure to use current settings as arguments + editMetaArguments(); + +#ifdef FULLCHANNEL + ExitApp(); + WII_Initialize(); + return !(WII_LaunchTitle(TITLE_ID(0x00010001, 0x554c4e52)) < 0); +#else + + // Load meta.xml arguments + char filepath[255]; + HomebrewXML MetaXML; + snprintf(filepath, sizeof(filepath), "%s/meta.xml", Settings.update_path); + MetaXML.LoadHomebrewXMLData(filepath); + + u8 *buffer = NULL; + u32 filesize = 0; + snprintf(filepath, sizeof(filepath), "%s/boot.dol", Settings.update_path); + LoadFileToMem(filepath, &buffer, &filesize); + if(!buffer) + { + return false; + } + FreeHomebrewBuffer(); + CopyHomebrewMemory(buffer, 0, filesize); + + AddBootArgument(filepath); + + for(u32 i = 0; i < MetaXML.GetArguments().size(); ++i) + { + AddBootArgument(MetaXML.GetArguments().at(i).c_str()); + } + + return !(BootHomebrewFromMem() <0); +#endif +} + +void ScreenShot() +{ + time_t rawtime; + struct tm * timeinfo; + char filename[100]; // Filename, with current date/time. + char fullPath[300]; // Full pathname: ConfigPath + filename. + + time(&rawtime); + timeinfo = localtime(&rawtime); + + // Create the filename with the current date/time. + // Format: USBLoader_GX_ScreenShot-Month_Day_Hour_Minute_Second_Year.png + int ret = strftime(filename, sizeof(filename), "USBLoader_GX_ScreenShot-%b%d%H%M%S%y.png", timeinfo); + if (ret == 0) + { + // Error formatting the time. + // Use the raw time in seconds as a fallback. + snprintf(filename, sizeof(filename), "USBLoader_GX_ScreenShot-%ld.png", rawtime); + } + + // Create the full pathname. + snprintf(fullPath, sizeof(fullPath), "%s%s", Settings.ConfigPath, filename); + + if(!CreateSubfolder(Settings.ConfigPath)) + { + gprintf("Can't create screenshot folder\n"); + return; + } + + TakeScreenshot(fullPath); +} + +/* + * Check if the current console is a Wii or WiiU + * Thanks to Crediar + */ +bool isWiiU() +{ + return (((*(vu32*)(0xCD8005A0) >> 16 ) == 0xCAFE) || isWiiVC); +} diff --git a/source/sys.h b/source/sys.h new file mode 100644 index 0000000..894896e --- /dev/null +++ b/source/sys.h @@ -0,0 +1,21 @@ +#ifndef _SYS_H_ +#define _SYS_H_ + +void wiilight(int enable); + +/* Prototypes */ +void AppCleanUp(void); //! Deletes all allocated space for everything +void ExitApp(void); //! Like AppCleanUp() and additional device unmount +void Sys_Init(void); +void Sys_Reboot(void); +void Sys_Shutdown(void); +void Sys_ShutdownToIdle(void); +void Sys_ShutdownToStandby(void); +void Sys_LoadMenu(void); +void Sys_BackToLoader(void); +void Sys_LoadHBC(void); +bool RebootApp(void); +void ScreenShot(void); +bool isWiiU(void); + +#endif diff --git a/source/system/IosLoader.cpp b/source/system/IosLoader.cpp new file mode 100644 index 0000000..954d9e8 --- /dev/null +++ b/source/system/IosLoader.cpp @@ -0,0 +1,630 @@ +#include +#include + +#include "IosLoader.h" +#include "sys.h" +#include "Controls/DeviceHandler.hpp" +#include "usbloader/usbstorage2.h" +#include "usbloader/disc.h" +#include "usbloader/wbfs.h" +#include "usbloader/wdvd.h" +#include "wad/nandtitle.h" +#include "mload/mload_modules.h" +#include "settings/CSettings.h" +#include "wad/nandtitle.h" +#include "mload/mload.h" +#include "mload/modules/ehcmodule_5.h" +#include "mload/modules/dip_plugin_249.h" +#include "mload/modules/odip_frag.h" +#include "utils/tools.h" +#include "gecko.h" + +#define MEM2_PROT 0x0D8B420A +#define ES_MODULE_START ((u16 *)0x939F0000) +#define ES_MODULE_END (ES_MODULE_START + 0x4000) +#define ES_HACK_OFFSET 4 + +extern u32 hdd_sector_size[2]; + +/* + * Buffer variables for the IOS info to avoid loading it several times + */ +static int currentIOS = -1; +static iosinfo_t *currentIOSInfo = NULL; +static int currentMIOS = -1; +static int currentDMLVersion = -1; + +/****************************************************************************** + * Public Methods: + ******************************************************************************/ +/* + * Check if the ios passed is a Hermes ios. + */ +bool IosLoader::IsHermesIOS(s32 ios) +{ + return (ios == 222 || ios == 223 || ios == 224 || ios == 225 || ios == 202); +} + +/* + * Check if the ios passed is a Waninkoko ios. + */ +bool IosLoader::IsWaninkokoIOS(s32 ios) +{ + if(ios < 200 || ios > 255) + return false; + + return !IsHermesIOS(ios); +} + +/* + * Check if the ios passed is a d2x ios. + */ +bool IosLoader::IsD2X(s32 ios) +{ + iosinfo_t *info = GetIOSInfo(ios); + if(!info) + return false; + + bool res = (strncasecmp(info->name, "d2x", 3) == 0); + + return res; +} + +/* + * Loads CIOS (If possible the one from the settings file). + * @return 0 if a cios has been successfully loaded. Else a value below 0 is returned. + */ +s32 IosLoader::LoadAppCios() +{ + u32 activeCios = IOS_GetVersion(); + s32 ret = -1; + + // We have what we need + if((int) activeCios == Settings.LoaderIOS) + return 0; + + u8 ciosLoadPriority[] = { Settings.LoaderIOS, 249, 250, 222, 223, 245, 246, 247, 248 }; // Ascending. + + + for (u32 i = 0; i < (sizeof(ciosLoadPriority)/sizeof(ciosLoadPriority[0])); ++i) + { + u32 cios = ciosLoadPriority[i]; + + if (activeCios == cios) + { + ret = 0; + break; + } + + if ((ret = ReloadIosSafe(cios)) > -1) + { + // Remember working cios. + Settings.LoaderIOS = cios; + break; + } + } + + return ret; +} + + +/* + * Loads a CIOS before a game start. + * @return 0 if a cios has been successfully loaded. Else a value below 0 is returned. + */ +s32 IosLoader::LoadGameCios(s32 ios) +{ + if(ios == IOS_GetVersion()) + return 0; + + s32 ret = -1; + + // Unmount fat before reloading IOS. + WBFS_CloseAll(); + WDVD_Close(); + DeviceHandler::DestroyInstance(); + USBStorage2_Deinit(); + + ret = ReloadIosSafe(ios); + + // Remount devices after reloading IOS. + DeviceHandler::Instance()->MountSD(); + DeviceHandler::Instance()->MountAllUSB(true); + Disc_Init(); + + return ret; +} + +/* + * Reloads a certain IOS under the condition, that an appropriate version of the IOS is installed. + * @return a negative value if a safe reload of the ios was not possible. + */ +s32 IosLoader::ReloadIosSafe(s32 ios) +{ + if(IsHermesIOS(ios)) + { + s32 iosRev = NandTitles.VersionOf(TITLE_ID(1, ios)); + if((iosRev < 4 || iosRev > 6) && iosRev != 65535) + return -11; + } + else if(IsWaninkokoIOS(ios)) + { + s32 iosRev = NandTitles.VersionOf(TITLE_ID(1, ios)); + if((iosRev < 9 || iosRev > 30000) && iosRev != 65535) //let's see if Waninkoko actually gets to 30 + return -22; + } + else if(ios < 200) // use AHB Access + { + s32 iosRev = NandTitles.VersionOf(TITLE_ID(1, ios)); + if(!iosRev) + return -33; + } + else + { + return -44; + } + + s32 r = ReloadIosKeepingRights(ios); + if (r >= 0) WII_Initialize(); + + IosLoader::LoadIOSModules(IOS_GetVersion(), IOS_GetRevision()); + + return r; +} + +/* + * Reloads a certain IOS and keeps the AHBPROT flag enabled if available. + */ +s32 IosLoader::ReloadIosKeepingRights(s32 ios) +{ + if (CheckAHBPROT()) + { + static const u16 ticket_check[] = { + 0x685B, // ldr r3, [r3, #4] ; Get TMD pointer + 0x22EC, 0x0052, // movs r2, 0x1D8 ; Set offset of access rights field in TMD + 0x189B, // adds r3, r3, r2 ; Add offset to TMD pointer + 0x681B, // ldr r3, [r3] ; Load access rights. We'll hack it with full access rights!!! + 0x4698, // mov r8, r3 ; Store it for the DVD video bitcheck later + 0x07DB // lsls r3, r3, 0x1F ; check AHBPROT bit + }; + + /* Disable MEM 2 protection */ + write16(MEM2_PROT, 2); + + for (u16 *patchme = ES_MODULE_START; patchme < ES_MODULE_END; patchme++) + { + if (!memcmp(patchme, ticket_check, sizeof(ticket_check))) + { + gprintf("ReloadIos: Found TMD access rights check at %p\n", patchme); + + /* Apply patch */ + patchme[ES_HACK_OFFSET] = 0x23FF; // li r3, 0xFF ; Set full access rights + + /* Flush cache */ + DCFlushRange(patchme+ES_HACK_OFFSET, 2); + break; + } + } + } + + /* Reload IOS. MEM2 protection is implicitly re-enabled */ + return IOS_ReloadIOS(ios); +} + +/* + * Check if MIOS is DIOS MIOS, DIOS MIOS Lite or official MIOS. + */ +u8 IosLoader::GetMIOSInfo() +{ + if(currentMIOS > -1) + return currentMIOS; + + currentMIOS = DEFAULT_MIOS; + + if(isWiiU()) // vWii users + return currentMIOS; + + u8 *appfile = NULL; + u32 filesize = 0; + + // "title/00000001/00000101/content/0000000b.app" contains DM/DML version and built date, but is not always accurate. + // so we are looking inside 0000000c.app to find the correct version. + NandTitle::LoadFileFromNand("/title/00000001/00000101/content/0000000c.app", &appfile, &filesize); + + if(appfile) + { + for(u32 i = 0; i < filesize-4; ++i) + { + if((*(u32*)(appfile+i)) == 'DIOS' && (*(u32*)(appfile+i+5)) == 'MIOS') + { + if((*(u32*)(appfile+i+10)) == 'Lite') + { + currentMIOS = DIOS_MIOS_LITE; + gprintf("DIOS MIOS Lite "); + currentDMLVersion = GetDMLVersion((char*)(appfile+i+31)); + } + else + { + currentMIOS = DIOS_MIOS; + gprintf("DIOS MIOS "); + currentDMLVersion = GetDMLVersion((char*)(appfile+i+27)); + } + break; + } + else if((*(u32*)(appfile+i)) == 'Quad' && (*(u32*)(appfile+i+4)) == 'Forc') + { + currentMIOS = QUADFORCE; + char* QF_version = (char*)(appfile+i+10); + gprintf("QuadForce v%.1f \n", atof(QF_version)); + if(atof(QF_version) >= 4.0) currentDMLVersion = DML_VERSION_QUAD_4_0; + else if(atof(QF_version) == 3.0) currentDMLVersion = DML_VERSION_QUAD_3_0; + else if(atof(QF_version) == 2.0) currentDMLVersion = DML_VERSION_QUAD_2_0; + else currentDMLVersion = DML_VERSION_QUAD_0_1; + + break; + } + else if((*(u32*)(appfile+i)) == 'GCLo' && (*(u32*)(appfile+i+4)) == 'ader') + { + // QuadForce USB v4.1 binary doesn't have QF version, checking: GCLoader....Built : %s %s.....May 26 2013.00:15:28 + if((*(u32*)(appfile+i+32)) == 'May ' && (*(u32*)(appfile+i+44)) == '00:1' && (*(u32*)(appfile+i+48)) == '5:28') + { + currentMIOS = QUADFORCE_USB; + gprintf("QuadForce USB v4.1\n"); + currentDMLVersion = DML_VERSION_QUAD_4_1; + break; + } + } + } + free(appfile); + } + + if(currentMIOS == DEFAULT_MIOS) + gprintf("MIOS / cMIOS \n"); + + return currentMIOS; +} + + +u8 IosLoader::GetDMLVersion(char* releaseDate) +{ + if(currentDMLVersion > -1) + return currentDMLVersion; + + currentDMLVersion = DML_VERSION_MIOS; + + // Older versions - not working with USBloaderGX + if(strncmp(releaseDate, "t: ", 3) == 0) + { + currentMIOS = DEFAULT_MIOS; + return currentDMLVersion; + } + + // Current installed version + gprintf("built on %s\n", releaseDate); + + struct tm time; + strptime(releaseDate, "%b %d %Y %H:%M:%S", &time); + time_t unixTime = mktime(&time); + + if(currentMIOS == DIOS_MIOS) + { + // Timestamp of DM 2.0 + strptime("Jun 23 2012 19:43:21", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_0_time = mktime(&time); + + // Timestamp of DM 2.1 + strptime("Jul 17 2012 11:25:35", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_1_time = mktime(&time); + + // Timestamp of DM 2.2 initial release + strptime("Jul 18 2012 16:57:47", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_2_time = mktime(&time); + + // Timestamp of DM 2.2 update2 + strptime("Jul 20 2012 14:49:47", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_2_2_time = mktime(&time); + + // Timestamp of DM 2.3 + strptime("Sep 24 2012 15:51:54", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_3_time = mktime(&time); + + // Timestamp of DM 2.4 + strptime("Oct 21 2012 22:57:12", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_4_time = mktime(&time); + + // Timestamp of DM 2.5 + strptime("Nov 9 2012 21:18:52", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_5_time = mktime(&time); + + // Timestamp of DM 2.6.0 + strptime("Dec 1 2012 01:52:53", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_6_0_time = mktime(&time); + + // Timestamp of DM 2.6.1 + strptime("Dec 1 2012 16:42:34", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_6_1_time = mktime(&time); + + // Timestamp of DM 2.7 + strptime("Feb 20 2013 14:54:33", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_7_time = mktime(&time); + + // Timestamp of DM 2.8 + strptime("Feb 24 2013 14:17:03", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_8_time = mktime(&time); + + // Timestamp of DM 2.9 + strptime("Apr 5 2013 18:29:35", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_9_time = mktime(&time); + + // Timestamp of DM 2.10 + strptime("May 24 2013 21:22:22", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_10_time = mktime(&time); + + // Timestamp of DM 2.11 + strptime("Jul 2 2014 10:31:15", "%b %d %Y %H:%M:%S", &time); + const time_t dm_2_11_time = mktime(&time); + + if(difftime(unixTime, dm_2_11_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_11; + else if(difftime(unixTime, dm_2_10_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_10; + else if(difftime(unixTime, dm_2_9_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_9; + else if(difftime(unixTime, dm_2_8_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_8; + else if(difftime(unixTime, dm_2_7_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_7; + else if(difftime(unixTime, dm_2_6_1_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_6_1; + else if(difftime(unixTime, dm_2_6_0_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_6_0; + else if(difftime(unixTime, dm_2_5_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_5; + else if(difftime(unixTime, dm_2_4_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_4; + else if(difftime(unixTime, dm_2_3_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_3; + else if(difftime(unixTime, dm_2_2_2_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_2_2; + else if(difftime(unixTime, dm_2_2_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_2; + else if(difftime(unixTime, dm_2_1_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_1; + else if(difftime(unixTime, dm_2_0_time) >= 0) currentDMLVersion = DML_VERSION_DM_2_0; + } + else if(currentMIOS == DIOS_MIOS_LITE) + { + // Timestamp of DML r52 + strptime("Mar 7 2012 19:36:06", "%b %d %Y %H:%M:%S", &time); + const time_t dml_r52_time = mktime(&time); + + // Timestamp of DML 1.2 + strptime("Apr 24 2012 19:44:08", "%b %d %Y %H:%M:%S", &time); + const time_t dml_1_2_time = mktime(&time); + + // Timestamp of DML 1.4b + strptime("May 7 2012 21:12:47", "%b %d %Y %H:%M:%S", &time); + const time_t dml_1_4b_time = mktime(&time); + + // Timestamp of DML 1.5 + strptime("Jun 14 2012 00:05:09", "%b %d %Y %H:%M:%S", &time); + const time_t dml_1_5_time = mktime(&time); + + // Timestamp of DML 2.2 initial release + strptime("Aug 6 2012 15:19:17", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_2_time = mktime(&time); + + // Timestamp of DML 2.2 update1 + strptime("Aug 13 2012 00:12:46", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_2_1_time = mktime(&time); + + // Timestamp of DML 2.3 mirror link + strptime("Sep 24 2012 13:13:42", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_3m_time = mktime(&time); + + // Timestamp of DML 2.3 main link + strptime("Sep 25 2012 03:03:41", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_3_time = mktime(&time); + // Timestamp of DML 2.4 + strptime("Oct 21 2012 22:57:17", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_4_time = mktime(&time); + + // Timestamp of DML 2.5 + strptime("Nov 9 2012 21:18:56", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_5_time = mktime(&time); + + // Timestamp of DML 2.6 + strptime("Dec 1 2012 16:22:29", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_6_time = mktime(&time); + + // Timestamp of DML 2.7 + strptime("Feb 21 2013 03:13:49", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_7_time = mktime(&time); + + // Timestamp of DML 2.8 + strptime("Feb 24 2013 13:30:29", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_8_time = mktime(&time); + + // Timestamp of DML 2.9 + strptime("Apr 5 2013 18:20:33", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_9_time = mktime(&time); + + // Timestamp of DML 2.10 + strptime("May 24 2013 18:51:58", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_10_time = mktime(&time); + + // Timestamp of DML 2.11 + strptime("Jul 2 2014 10:31:06", "%b %d %Y %H:%M:%S", &time); + const time_t dml_2_11_time = mktime(&time); + + if(difftime(unixTime, dml_2_11_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_11; + else if(difftime(unixTime, dml_2_10_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_10; + else if(difftime(unixTime, dml_2_9_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_9; + else if(difftime(unixTime, dml_2_8_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_8; + else if(difftime(unixTime, dml_2_7_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_7; + else if(difftime(unixTime, dml_2_6_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_6; + else if(difftime(unixTime, dml_2_5_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_5; + else if(difftime(unixTime, dml_2_4_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_4; + else if(difftime(unixTime, dml_2_3_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_3; + else if(difftime(unixTime, dml_2_3m_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_3m; + else if(difftime(unixTime, dml_2_2_1_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_2_1; + else if(difftime(unixTime, dml_2_2_time) >= 0) currentDMLVersion = DML_VERSION_DML_2_2; + else if(difftime(unixTime, dml_1_5_time) >= 0) currentDMLVersion = DML_VERSION_DML_1_5; + else if(difftime(unixTime, dml_1_4b_time) >= 0) currentDMLVersion = DML_VERSION_DML_1_4b; + else if(difftime(unixTime, dml_1_2_time) > 0) currentDMLVersion = DML_VERSION_DML_1_4; + else if(difftime(unixTime, dml_1_2_time) == 0) currentDMLVersion = DML_VERSION_DML_1_2; + else if (difftime(unixTime, dml_r52_time) >= 0) currentDMLVersion = DML_VERSION_R52; + else currentDMLVersion = DML_VERSION_R51; + } + + return currentDMLVersion; + +} + +/* + * Check if selected IOS is compatible with Emulated NAND and user's settings + */ +bool IosLoader::is_NandEmu_compatible(const char *NandEmuPath, s32 ios) +{ + // TODO: Check features against cIOS revision + // rev17: 1st FAT32 partition of a 512 bytes/sector HDD, NandEmuPath must be on root, Full EmuNAND only + // rev18: adds Partial EmuNAND mode + // rev21: adds EmuNAND paths + // rev21 d2x beta: adds partition selection. officially supported in d2x v3 + // d2x v4: adds 4096 bytes/sector support + + // Check IOS + if(IsD2X(ios)) + return true; + + if(!IsWaninkokoIOS(ios) || NandTitles.VersionOf(TITLE_ID(1, ios)) < 17) + return false; + + // Check all path restrictions when using rev17+ + if(NandEmuPath) + { + // Check if EmuNAND Path location is on root + const char *NandEmuFolder = strchr(NandEmuPath, '/'); + if(!NandEmuFolder || strlen(NandEmuFolder) > 1) + return false; + + // Check if EmuNAND partition is on USB devices + if(strncmp(NandEmuPath, "usb", 3) == 0) + { + int part_num = atoi(NandEmuPath+3); + int usbport = DeviceHandler::PartitionToUSBPort(part_num-USB1); + + // Check if this is the first FAT32 partition on the drive + for(int dev = USB1; dev <= part_num; dev++) + { + if(strncmp(DeviceHandler::GetFSName(dev), "FAT", 3) == 0) + { + if(dev == part_num) + break; + else + return false; + } + } + + // Check if the partition is primary + // EmuNAND works with Primary and Extended partitions, no need to check the PartitionTableType + + // Check HDD sector size. Only 512 bytes/sector is supported by d2x < v4 + if(hdd_sector_size[usbport] != BYTES_PER_SECTOR) + return false; + } + } + return true; +} + +/****************************************************************************** + * Private/Protected Methods: + ******************************************************************************/ +void IosLoader::LoadIOSModules(s32 ios, s32 ios_rev) +{ + //! Hermes IOS + if(IsHermesIOS(ios)) + { + const u8 * ech_module = NULL; + int ehc_module_size = 0; + const u8 * dip_plugin = NULL; + int dip_plugin_size = 0; + + ech_module = ehcmodule_5; + ehc_module_size = size_ehcmodule_5; + dip_plugin = odip_frag; + dip_plugin_size = odip_frag_size; + gprintf("Loading ehc v5 and opendip module\n"); + + load_modules(ech_module, ehc_module_size, dip_plugin, dip_plugin_size); + } + //! Waninkoko IOS + else if(IsWaninkokoIOS(ios)) + { + // Init ISFS for d2x check + ISFS_Initialize(); + + iosinfo_t *info = GetIOSInfo(ios); + if(ios_rev >= 18 && (!info || info->version < 6)) + { + if(mload_init() >= 0) + { + gprintf("Loading dip module for Waninkoko's cios\n"); + mload_module((u8 *) dip_plugin_249, dip_plugin_249_size); + mload_close(); + } + } + ISFS_Deinitialize(); + } +} + +/* + * Reads the ios info struct from the .app file. + * @return pointer to iosinfo_t on success else NULL. The user is responsible for freeing the buffer. + */ +iosinfo_t *IosLoader::GetIOSInfo(s32 ios) +{ + if(currentIOS == ios && currentIOSInfo) + return currentIOSInfo; + + if(currentIOSInfo) + { + free(currentIOSInfo); + currentIOSInfo = NULL; + } + + currentIOS = ios; + char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(0x20); + u64 TicketID = ((((u64) 1) << 32) | ios); + u32 TMD_Length; + + s32 ret = ES_GetStoredTMDSize(TicketID, &TMD_Length); + if (ret < 0) + return NULL; + + signed_blob *TMD = (signed_blob*) memalign(32, ALIGN32(TMD_Length)); + if (!TMD) + return NULL; + + ret = ES_GetStoredTMD(TicketID, TMD, TMD_Length); + if (ret < 0) + { + free(TMD); + return NULL; + } + + snprintf(filepath, sizeof(filepath), "/title/%08x/%08x/content/%08x.app", 0x00000001, (unsigned int)ios, (unsigned int)(*(u8 *)((u32)TMD+0x1E7))); + + free(TMD); + + u8 *buffer = NULL; + u32 filesize = 0; + + NandTitle::LoadFileFromNand(filepath, &buffer, &filesize); + + if(!buffer) + return NULL; + + iosinfo_t *iosinfo = (iosinfo_t *) buffer; + + if(iosinfo->magicword != 0x1ee7c105 || iosinfo->magicversion != 1) + { + free(buffer); + return NULL; + } + + iosinfo = (iosinfo_t *) realloc(buffer, sizeof(iosinfo_t)); + if(!iosinfo) + iosinfo = (iosinfo_t *) buffer; + + currentIOSInfo = iosinfo; + + return iosinfo; +} diff --git a/source/system/IosLoader.h b/source/system/IosLoader.h new file mode 100644 index 0000000..85a3450 --- /dev/null +++ b/source/system/IosLoader.h @@ -0,0 +1,102 @@ +#ifndef _IOSLOADER_H_ +#define _IOSLOADER_H_ + +#include +#include + +#define CheckAHBPROT() (read32(0x0D800064) == 0xFFFFFFFF) + +enum MiosInfo +{ + DEFAULT_MIOS, + DIOS_MIOS, + DIOS_MIOS_LITE, + QUADFORCE, + QUADFORCE_USB, +}; + +enum DMLVersions +{ + DML_VERSION_MIOS = 0, + DML_VERSION_R51, + DML_VERSION_R52, +// DML_VERSION_DML_1_0, +// DML_VERSION_DML_1_1, + DML_VERSION_QUAD_0_1, // Feb 15 2012 13:19:36 wrong built date. + DML_VERSION_DML_1_2, // Apr 24 2012 19:44:08 +// DML_VERSION_DML_1_3, // Apr 26 2012 + DML_VERSION_DML_1_4, + DML_VERSION_DML_1_4b, // May 7 2012 21:12:47 +// DML_VERSION_QUAD_0_1 // Jun 9 2012 23:13:16 correct built date. + DML_VERSION_DML_1_5, // Jun 14 2012 00:05:09 + DML_VERSION_DM_2_0, // Jun 23 2012 19:43:21 +// DML_VERSION_DM_2_0_1, +// DML_VERSION_DM_2_0_2, +// DML_VERSION_DM_2_0_3, +// DML_VERSION_DM_2_0_3b, +// DML_VERSION_DM_2_0_3c, +// DML_VERSION_DM_2_0_3d, +// DML_VERSION_DM_2_0_4, +// DML_VERSION_DM_2_0_5, + DML_VERSION_DM_2_1, // Jul 17 2012 11:25:35 + DML_VERSION_DM_2_2, // Jul 18 2012 16:57:47 +// DML_VERSION_DM_2_2_1, + DML_VERSION_DM_2_2_2, // Jul 20 2012 14:49:47 + DML_VERSION_DML_2_2, // Aug 6 2012 15:19:17 + DML_VERSION_DML_2_2_1, // Aug 13 2012 00:12:46 + DML_VERSION_DML_2_3m, // Sep 24 2012 13:13:42 (mirror link) + DML_VERSION_DM_2_3, // Sep 24 2012 15:51:54 (Main link and Mirror link) + DML_VERSION_DML_2_3, // Sep 25 2012 03:03:41 (main link) + DML_VERSION_DM_2_4, // Oct 21 2012 22:57:12 + DML_VERSION_DML_2_4, // Oct 21 2012 22:57:17 + DML_VERSION_DM_2_5, // Nov 9 2012 21:18:52 + DML_VERSION_DML_2_5, // Nov 9 2012 21:18:56 + DML_VERSION_DM_2_6_0, // Dec 1 2012 01:52:53 + DML_VERSION_DML_2_6, // Dec 1 2012 16:22:29 + DML_VERSION_DM_2_6_1, // Dec 1 2012 16:42:34 + DML_VERSION_DM_2_7, // Feb 20 2013 14:54:33 + DML_VERSION_DML_2_7, // Feb 21 2013 03:13:49 + DML_VERSION_DML_2_8, // Feb 24 2013 13:30:29 + DML_VERSION_DM_2_8, // Feb 24 2013 14:17:03 + DML_VERSION_DML_2_9, // Apr 5 2013 18:20:33 + DML_VERSION_DM_2_9, // Apr 5 2013 18:29:35 + DML_VERSION_QUAD_2_0, // Apr 30 2013 17:31:32 + DML_VERSION_QUAD_3_0, // May 8 2013 22:21:44 + DML_VERSION_QUAD_4_0, // May 12 2013 20:22:57 + DML_VERSION_DML_2_10, // May 24 2013 18:51:58 + DML_VERSION_DM_2_10, // May 24 2013 21:22:22 + DML_VERSION_QUAD_4_1, // May 26 2013.00:15:28 (USB) + DML_VERSION_DML_2_11, // Jul 2 2014 10:31:06 + DML_VERSION_DM_2_11, // Jul 2 2014 10:31:15 + DML_VERSION_MAX_VERSION, +}; + +typedef struct _iosinfo_t +{ + u32 magicword; //0x1ee7c105 + u32 magicversion; // 1 + u32 version; // Example: 5 + u32 baseios; // Example: 56 + char name[0x10]; // Example: d2x + char versionstring[0x10]; // Example: beta2 +} __attribute__((packed)) iosinfo_t; + +class IosLoader +{ + public: + static s32 LoadAppCios(); + static s32 LoadGameCios(s32 ios); + static s32 ReloadIosSafe(s32 ios); + static s32 ReloadIosKeepingRights(s32 ios); + static bool IsHermesIOS(s32 ios = IOS_GetVersion()); + static bool IsWaninkokoIOS(s32 ios = IOS_GetVersion()); + static bool IsD2X(s32 ios = IOS_GetVersion()); + static iosinfo_t *GetIOSInfo(s32 ios); + static u8 GetMIOSInfo(); + static u8 GetDMLVersion(char* releaseDate = NULL); + static bool is_NandEmu_compatible(const char *NandEmuPath, s32 ios = IOS_GetVersion()); + private: + static void LoadIOSModules(s32 ios, s32 ios_rev); +}; + +#endif diff --git a/source/themes/CTheme.cpp b/source/themes/CTheme.cpp new file mode 100644 index 0000000..b698bb0 --- /dev/null +++ b/source/themes/CTheme.cpp @@ -0,0 +1,216 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include + +#include "CTheme.h" +#include "GUI/gui.h" +#include "settings/CSettings.h" +#include "banner/OpeningBNR.hpp" +#include "FileOperations/fileops.h" +#include "SystemMenu/SystemMenuResources.h" +#include "menu/menus.h" +#include "wad/nandtitle.h" +#include "FreeTypeGX.h" + +FreeTypeGX * fontSystem = NULL; +static FT_Byte * customFont = NULL; +static u32 customFontSize = 0; + +bool Theme::ShowTooltips = true; + +void Theme::Reload() +{ + HaltGui(); + mainWindow->Remove(bgImg); + for(int i = 0; i < 4; ++i) + { + char image[50]; + snprintf(image, sizeof(image), "player%i_point.png", i+1); + pointer[i]->SetImage(image); + } + delete btnSoundClick; + delete btnSoundClick2; + delete btnSoundOver; + btnSoundClick = new GuiSound(Resources::GetFile("button_click.wav"), Resources::GetFileSize("button_click.wav"), Settings.sfxvolume); + btnSoundClick2 = new GuiSound(Resources::GetFile("button_click2.wav"), Resources::GetFileSize("button_click2.wav"), Settings.sfxvolume); + btnSoundOver = new GuiSound(Resources::GetFile("button_over.wav"), Resources::GetFileSize("button_over.wav"), Settings.sfxvolume); + delete background; + background = Resources::GetImageData(Settings.widescreen ? "wbackground.png" : "background.png"); + delete bgImg; + bgImg = new GuiImage(background); + mainWindow->Append(bgImg); + ResumeGui(); +} + +void Theme::CleanUp() +{ + ThemeCleanUp(); + Resources::Clear(); + ClearFontData(); +} + +void Theme::SetDefault() +{ + ShowTooltips = true; + CleanUp(); + strcpy(Settings.theme, ""); + LoadFont(""); +} + +bool Theme::Load(const char * theme_file_path) +{ + bool result = LoadTheme(theme_file_path); + if(!result) + return result; + + Theme::ShowTooltips = (thInt("1 - Enable tooltips: 0 for off and 1 for on") != 0); + + FILE * file = fopen(theme_file_path, "rb"); + if(!file) + return false; + + char line[300]; + char * Foldername = NULL; + + while (fgets(line, sizeof(line), file)) + { + char * ptr = strcasestr(line, "Image-Folder:"); + if(!ptr) + continue; + + ptr += strlen("Image-Folder:"); + + while(*ptr != '\0' && *ptr == ' ') ptr++; + + Foldername = ptr; + + while(*ptr != '\\' && *ptr != '"' && *ptr != '\0') ptr++; + + *ptr = '\0'; + break; + } + + fclose(file); + + if(!Foldername) + return result; + + char theme_path[300]; + snprintf(theme_path, sizeof(theme_path), theme_file_path); + + char * ptr = strrchr(theme_path, '/'); + if(ptr) *ptr = '\0'; + + snprintf(theme_path, sizeof(theme_path), "%s/%s", theme_path, Foldername); + if(!Resources::LoadFiles(theme_path)) + { + const char * ThemeFilename = strrchr(theme_file_path, '/')+1; + char Filename[255]; + snprintf(Filename, sizeof(Filename), ThemeFilename); + + char * fileext = strrchr(Filename, '.'); + if(fileext) *fileext = 0; + + char * ptr = strrchr(theme_path, '/'); + *ptr = 0; + snprintf(theme_path, sizeof(theme_path), "%s/%s", theme_path, Filename); + Resources::LoadFiles(theme_path); + } + + //! Override font.ttf with the theme font.ttf if it exists in the image folder + char FontPath[300]; + snprintf(FontPath, sizeof(FontPath), "%s/font.ttf", theme_path); + + if(CheckFile(FontPath)) + Theme::LoadFont(theme_path); + + return result; +} + +bool Theme::LoadFont(const char *path) +{ + char FontPath[300]; + bool result = false; + FILE *pfile = NULL; + + delete [] customFont; + customFont = NULL; + + snprintf(FontPath, sizeof(FontPath), "%s/font.ttf", path); + + pfile = fopen(FontPath, "rb"); + + if (pfile) + { + fseek(pfile, 0, SEEK_END); + customFontSize = ftell(pfile); + rewind(pfile); + + customFont = new (std::nothrow) FT_Byte[customFontSize]; + if (customFont) + { + fread(customFont, 1, customFontSize, pfile); + result = true; + } + fclose(pfile); + } + + bool isSystemFont = false; + FT_Byte *loadedFont = customFont; + u32 loadedFontSize = customFontSize; + + if(!loadedFont && Settings.UseSystemFont) + { + //! Default to system font if no custom is loaded + loadedFont = (u8 *) SystemMenuResources::Instance()->GetSystemFont(); + loadedFontSize = SystemMenuResources::Instance()->GetSystemFontSize(); + if(loadedFont) + isSystemFont = true; + } + if(!loadedFont) + { + loadedFont = (FT_Byte *) Resources::GetFile("font.ttf"); + loadedFontSize = Resources::GetFileSize("font.ttf"); + } + + delete fontSystem; + + fontSystem = new FreeTypeGX(loadedFont, loadedFontSize, isSystemFont); + + return result; +} + +void Theme::ClearFontData() +{ + if (fontSystem) + delete fontSystem; + fontSystem = NULL; + + if(customFont) + delete [] customFont; + customFont = NULL; +} diff --git a/source/themes/CTheme.h b/source/themes/CTheme.h new file mode 100644 index 0000000..ad19e42 --- /dev/null +++ b/source/themes/CTheme.h @@ -0,0 +1,33 @@ +#ifndef _THEME_H_ +#define _THEME_H_ + +#include +#include +#include +#include "Resources.h" +#include "gettheme.h" + +class Theme +{ + public: + //!Set Default + static void SetDefault(); + //!Load + static bool Load(const char * path); + //!Load font data + static bool LoadFont(const char *path); + //!Load the original Wii System Menu font into memory only. It is not applied. + static bool loadSystemFont(bool korean); + //!Reload the main images/sounds for the new theme + static void Reload(); + //!Clear all image/font/theme data and free the memory + static void CleanUp(); + + //!Enable tooltips: special case treaded because it is called every frame + static bool ShowTooltips; + private: + //!Clear the font data and free the memory + static void ClearFontData(); +}; + +#endif diff --git a/source/themes/Resources.cpp b/source/themes/Resources.cpp new file mode 100644 index 0000000..057da53 --- /dev/null +++ b/source/themes/Resources.cpp @@ -0,0 +1,95 @@ +#include +#include +#include "FileOperations/fileops.h" +#include "Resources.h" +#include "filelist.h" + +void Resources::Clear() +{ + for(int i = 0; RecourceFiles[i].filename != NULL; ++i) + { + if(RecourceFiles[i].CustomFile) + { + free(RecourceFiles[i].CustomFile); + RecourceFiles[i].CustomFile = NULL; + } + + if(RecourceFiles[i].CustomFileSize != 0) + RecourceFiles[i].CustomFileSize = 0; + } +} + +bool Resources::LoadFiles(const char * path) +{ + if(!path) + return false; + + bool result = false; + Clear(); + + char fullpath[1024]; + + for(int i = 0; RecourceFiles[i].filename != NULL; ++i) + { + snprintf(fullpath, sizeof(fullpath), "%s/%s", path, RecourceFiles[i].filename); + + if(CheckFile(fullpath)) + { + u8 * buffer = NULL; + u32 filesize = 0; + + LoadFileToMem(fullpath, &buffer, &filesize); + + RecourceFiles[i].CustomFile = buffer; + RecourceFiles[i].CustomFileSize = (u32) filesize; + result = true; + } + } + + return result; +} + +const u8 * Resources::GetFile(const char * filename) +{ + for(int i = 0; RecourceFiles[i].filename != NULL; ++i) + { + if(strcasecmp(filename, RecourceFiles[i].filename) == 0) + { + return (RecourceFiles[i].CustomFile ? RecourceFiles[i].CustomFile : RecourceFiles[i].DefaultFile); + } + } + + return NULL; +} + +u32 Resources::GetFileSize(const char * filename) +{ + for(int i = 0; RecourceFiles[i].filename != NULL; ++i) + { + if(strcasecmp(filename, RecourceFiles[i].filename) == 0) + { + return (RecourceFiles[i].CustomFile ? RecourceFiles[i].CustomFileSize : RecourceFiles[i].DefaultFileSize); + } + } + + return 0; +} + +GuiImageData * Resources::GetImageData(const char * filename) +{ + for(int i = 0; RecourceFiles[i].filename != NULL; ++i) + { + if(strcasecmp(filename, RecourceFiles[i].filename) == 0) + { + const u8 * buff = RecourceFiles[i].CustomFile ? RecourceFiles[i].CustomFile : RecourceFiles[i].DefaultFile; + const u32 size = RecourceFiles[i].CustomFile ? RecourceFiles[i].CustomFileSize : RecourceFiles[i].DefaultFileSize; + + if(buff != NULL) + return (new GuiImageData(buff, size)); + else + return NULL; + } + } + + return NULL; +} diff --git a/source/themes/Resources.h b/source/themes/Resources.h new file mode 100644 index 0000000..5135199 --- /dev/null +++ b/source/themes/Resources.h @@ -0,0 +1,28 @@ +#ifndef RECOURCES_H_ +#define RECOURCES_H_ + +#include "GUI/gui_imagedata.h" + +typedef struct _RecourceFile +{ + const char *filename; + const u8 *DefaultFile; + const u32 DefaultFileSize; + u8 *CustomFile; + u32 CustomFileSize; +} RecourceFile; + +class Resources +{ + public: + static void Clear(); + static bool LoadFiles(const char * path); + static const u8 * GetFile(const char * filename); + static u32 GetFileSize(const char * filename); + static GuiImageData * GetImageData(const char * filename); + + private: + static RecourceFile RecourceFiles[]; +}; + +#endif diff --git a/source/themes/ThemeDownloader.cpp b/source/themes/ThemeDownloader.cpp new file mode 100644 index 0000000..0e37a63 --- /dev/null +++ b/source/themes/ThemeDownloader.cpp @@ -0,0 +1,491 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include + +#include "ThemeDownloader.h" +#include "language/gettext.h" +#include "prompts/PromptWindows.h" +#include "prompts/ProgressWindow.h" +#include "FileOperations/DirList.h" +#include "network/networkops.h" +#include "themes/CTheme.h" +#include "FileOperations/fileops.h" +#include "sys.h" +#include "network/FileDownloader.h" +#include "network/http.h" +#include "menu/menus.h" +#include "ZipFile.h" +#include "utils/ShowError.h" +#include "utils/tools.h" +#include "gecko.h" + + +ThemeDownloader::ThemeDownloader() + : FlyingButtonsMenu(tr("Theme Downloader")) +{ + ThemeList = NULL; + delete MainButtonImgData; + delete MainButtonImgOverData; + + ParentMenu = MENU_SETTINGS; + + ThemeListURL = "http://wii.spiffy360.com/themes.php?xml=1&category=1&adult="; + if(Settings.godmode) + ThemeListURL += "1"; + else + ThemeListURL += "0"; + + MainButtonImgData = Resources::GetImageData("theme_box.png"); + MainButtonImgOverData = NULL; + + urlTxt = new GuiText(tr( "Themes by www.spiffy360.com" ), 22, (GXColor) {255, 255, 255, 255}); + urlTxt->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + urlTxt->SetPosition(350, 12); + Append(urlTxt); + + for(int i = 0; i < 4; ++i) + ThemePreviews[i] = NULL; + + + defaultBtnTxt = new GuiText(tr( "Default" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + defaultBtnTxt->SetMaxWidth(btnOutline->GetWidth() - 30); + defaultBtnImg = new GuiImage(btnOutline); + if (Settings.wsprompt) + { + defaultBtnTxt->SetWidescreen(Settings.widescreen); + defaultBtnImg->SetWidescreen(Settings.widescreen); + } + defaultBtn = new GuiButton(btnOutline->GetWidth(), btnOutline->GetHeight()); + defaultBtn->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + defaultBtn->SetPosition(-20, 400); + defaultBtn->SetLabel(defaultBtnTxt); + defaultBtn->SetImage(defaultBtnImg); + defaultBtn->SetSoundOver(btnSoundOver); + defaultBtn->SetSoundClick(btnSoundClick2); + defaultBtn->SetTrigger(trigA); + defaultBtn->SetEffectGrow(); + Append(defaultBtn); + + backBtn->SetPosition(-205, 400); +} + +ThemeDownloader::~ThemeDownloader() +{ + HaltGui(); + for(u32 i = 0; i < MainButton.size(); ++i) + Remove(MainButton[i]); + Remove(urlTxt); + Remove(defaultBtn); + + delete urlTxt; + delete defaultBtn; + delete defaultBtnTxt; + delete defaultBtnImg; + delete ThemeList; + for(int i = 0; i < 4; ++i) + delete ThemePreviews[i]; +} + +int ThemeDownloader::Execute() +{ + ThemeDownloader * Menu = new ThemeDownloader(); + mainWindow->Append(Menu); + + Menu->ShowMenu(); + + int returnMenu = MENU_NONE; + + while((returnMenu = Menu->MainLoop()) == MENU_NONE); + + delete Menu; + + return returnMenu; +} + +int ThemeDownloader::MainLoop() +{ + if(defaultBtn->GetState() == STATE_CLICKED) + { + int choice = WindowPrompt(0, tr("Do you want to load the default theme?"), tr("Yes"), tr("Cancel")); + if(choice) + { + HaltGui(); + Theme::SetDefault(); + Theme::Reload(); + ResumeGui(); + return MENU_THEMEDOWNLOADER; + } + + defaultBtn->ResetState(); + } + + return FlyingButtonsMenu::MainLoop(); +} + +void ThemeDownloader::SetMainButton(int position, const char * ButtonText, GuiImageData * imageData, GuiImageData * themeImg) +{ + if(position >= (int) MainButton.size()) + { + MainButtonImg.resize(position+1); + MainButtonImgOver.resize(position+1); + MainButtonTxt.resize(position+1); + MainButton.resize(position+1); + } + + MainButtonImg[position] = new GuiImage(imageData); + MainButtonImgOver[position] = new GuiImage(themeImg); + MainButtonImgOver[position]->SetScale(0.4); + MainButtonImgOver[position]->SetPosition(50, -45); + + MainButtonTxt[position] = new GuiText(ButtonText, 18, ( GXColor ) {0, 0, 0, 255}); + MainButtonTxt[position]->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + MainButtonTxt[position]->SetPosition(0, 10); + MainButtonTxt[position]->SetMaxWidth(imageData->GetWidth() - 10, DOTTED); + + MainButton[position] = new GuiButton(imageData->GetWidth(), imageData->GetHeight()); + MainButton[position]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + MainButton[position]->SetSoundOver(btnSoundOver); + MainButton[position]->SetSoundClick(btnSoundClick); + MainButton[position]->SetImage(MainButtonImg[position]); + MainButton[position]->SetImageOver(MainButtonImg[position]); + MainButton[position]->SetIcon(MainButtonImgOver[position]); + MainButton[position]->SetLabel(MainButtonTxt[position]); + MainButton[position]->SetTrigger(trigA); + MainButton[position]->SetEffectGrow(); + + switch(position % 4) + { + case 0: + MainButton[position]->SetPosition(90, 75); + break; + case 1: + MainButton[position]->SetPosition(340, 75); + break; + case 2: + MainButton[position]->SetPosition(90, 230); + break; + case 3: + MainButton[position]->SetPosition(340, 230); + break; + default: + break; + } +} + +GuiImageData * ThemeDownloader::GetImageData(int theme) +{ + GuiImageData * ImageData = NULL; + char filepath[300]; + snprintf(filepath, sizeof(filepath), "%s/tmp/%s.jpg", Settings.theme_path, ThemeList->GetThemeTitle(theme)); + + if (!CheckFile(filepath)) + { + struct block file = downloadfile(ThemeList->GetImageLink(theme)); + char storepath[300]; + snprintf(storepath, sizeof(storepath), "%s/tmp/", Settings.theme_path); + CreateSubfolder(storepath); + if (file.data) + { + ImageData = new GuiImageData(file.data, file.size, false); + + FILE *storefile = fopen(filepath, "wb"); + if(storefile) + { + fwrite(file.data, 1, file.size, storefile); + fclose(storefile); + } + free(file.data); + } + } + else + ImageData = new GuiImageData(filepath); + + return ImageData; +} + +void ThemeDownloader::SetupMainButtons() +{ + ResumeGui(); + + if (!IsNetworkInit() && !NetworkInitPrompt()) + { + ShowError(tr("Could not initialize network!")); + return; + } + + ShowProgress(tr("Downloading pagelist:"), "www.spiffy360.com", tr("Please wait..."), 0, 1); + + if(!CheckConnection(ThemeListURL.c_str())) + { + ProgressStop(); + ShowError(tr("Connection to server timed out.")); + return; + } + + ThemeList = new Theme_List(ThemeListURL.c_str()); + + if (ThemeList->GetThemeCount() == 0) + { + ProgressStop(); + WindowPrompt(tr( "No themes found on the site." ), 0, "OK"); + returnMenu = MENU_SETTINGS; + } + + for(int i = 0; i < ThemeList->GetThemeCount(); ++i) + { + SetMainButton(i, ThemeList->GetThemeTitle(i), MainButtonImgData, NULL); + } +} + +void ThemeDownloader::AddMainButtons() +{ + HaltGui(); + for(u32 i = 0; i < MainButton.size(); ++i) + Remove(MainButton[i]); + ResumeGui(); + + int FirstItem = currentPage*4; + int n = 0; + + for(int i = FirstItem; i < (int) MainButton.size() && i < FirstItem+4; ++i) + { + delete ThemePreviews[n]; + ShowProgress(tr("Downloading image:"), 0, ThemeList->GetThemeTitle(i), n, 4); + ThemePreviews[n] = GetImageData(i); + MainButtonImgOver[i]->SetImage(ThemePreviews[n]); + n++; + } + ProgressStop(); + HaltGui(); + + FlyingButtonsMenu::AddMainButtons(); +} + +void ThemeDownloader::MainButtonClicked(int button) +{ + //! TODO: Clean me + const char * title = ThemeList->GetThemeTitle(button); + const char * author = ThemeList->GetThemeAuthor(button); + GuiImageData *thumbimageData = ThemePreviews[button % 4]; + const char *downloadlink = ThemeList->GetDownloadLink(button); + + gprintf("\nTheme_Prompt(%s ,%s, %s)", title, author, downloadlink); + bool leave = false; + int result = 0; + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData dialogBox(Resources::GetFile("theme_dialogue_box.png"), Resources::GetFileSize("theme_dialogue_box.png")); + + GuiImage dialogBoxImg(&dialogBox); + + GuiWindow promptWindow(dialogBox.GetWidth(), dialogBox.GetHeight()); + promptWindow.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + promptWindow.SetPosition(0, -10); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + GuiText titleTxt(tr( "Theme Title:" ), 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + titleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + titleTxt.SetPosition(230, 30); + + GuiText titleTxt2(title, 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + titleTxt2.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + titleTxt2.SetPosition(230, 50); + titleTxt2.SetMaxWidth(dialogBox.GetWidth() - 220, WRAP); + + GuiText authorTxt(tr( "Author(s):" ), 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + authorTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + authorTxt.SetPosition(230, 100); + + GuiText authorTxt2(author, 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + authorTxt2.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + authorTxt2.SetPosition(230, 120); + authorTxt2.SetMaxWidth(dialogBox.GetWidth() - 220, DOTTED); + + GuiText downloadBtnTxt(tr( "Download" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + downloadBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30); + GuiImage downloadBtnImg(&btnOutline); + if (Settings.wsprompt) + { + downloadBtnTxt.SetWidescreen(Settings.widescreen); + downloadBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton downloadBtn(&downloadBtnImg, &downloadBtnImg, ALIGN_RIGHT, ALIGN_TOP, -5, 170, &trigA, btnSoundOver, btnSoundClick2, 1); + downloadBtn.SetLabel(&downloadBtnTxt); + downloadBtn.SetScale(0.9); + + GuiText backBtnTxt(tr( "Back" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + backBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30); + GuiImage backBtnImg(&btnOutline); + if (Settings.wsprompt) + { + backBtnTxt.SetWidescreen(Settings.widescreen); + backBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton backBtn(&backBtnImg, &backBtnImg, ALIGN_RIGHT, ALIGN_TOP, -5, 220, &trigA, btnSoundOver, btnSoundClick2, 1); + backBtn.SetLabel(&backBtnTxt); + backBtn.SetTrigger(&trigB); + backBtn.SetScale(0.9); + + GuiImage ThemeImage(thumbimageData); + ThemeImage.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + ThemeImage.SetPosition(20, 10); + ThemeImage.SetScale(0.8); + + promptWindow.Append(&dialogBoxImg); + promptWindow.Append(&ThemeImage); + promptWindow.Append(&titleTxt); + promptWindow.Append(&titleTxt2); + promptWindow.Append(&authorTxt); + promptWindow.Append(&authorTxt2); + promptWindow.Append(&downloadBtn); + promptWindow.Append(&backBtn); + + HaltGui(); + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&promptWindow); + ResumeGui(); + + while (!leave) + { + VIDEO_WaitVSync(); + + if (shutdown) + Sys_Shutdown(); + else if (reset) + Sys_Reboot(); + + if (downloadBtn.GetState() == STATE_CLICKED) + { + int choice = WindowPrompt(tr( "Do you want to download this theme?" ), title, tr( "Yes" ), tr( "Cancel" )); + if (choice) + { + result = DownloadTheme(downloadlink, title); + if (result == 2) + { + returnMenu = MENU_THEMEDOWNLOADER; + leave = true; + } + } + mainWindow->SetState(STATE_DISABLED); + promptWindow.SetState(STATE_DEFAULT); + downloadBtn.ResetState(); + } + + else if (backBtn.GetState() == STATE_CLICKED) + { + leave = true; + backBtn.ResetState(); + } + } + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while (promptWindow.GetEffect() > 0) usleep(100); + HaltGui(); + mainWindow->Remove(&promptWindow); + mainWindow->SetState(STATE_DEFAULT); + ResumeGui(); +} + +int ThemeDownloader::DownloadTheme(const char *url, const char *title) +{ + if (!url) return -1; + + if(!CreateSubfolder(Settings.theme_path)) + { + ShowError(tr("Can't create path: %s"), Settings.theme_path); + return -1; + } + + DirList oldDir(Settings.theme_path); + + char filepath[300]; + snprintf(filepath, sizeof(filepath), "%s/TempTheme.zip", Settings.theme_path); + + int ret = DownloadFileToPath(url, filepath, false); + if(ret < 1024) + { + ShowError(tr("Error when downloading file: %i"), ret); + return -2; + } + + ZipFile *zipfile = new ZipFile(filepath); + + int result = zipfile->ExtractAll(Settings.theme_path); + if(result < 0) + { + WindowPrompt(tr( "Failed to extract." ), tr( "Unsupported format, try to extract manually TempTheme.zip." ), tr( "OK" )); + return -3; + } + + std::string themeDir; + std::string Filename; + zipfile->FindFilePart(".them", Filename); + zipfile->FindFilePart("/", themeDir); + + if(!zipfile->FindFile("theme_preview.png") && themeDir.size() != 0) + { + size_t pos = themeDir.find("/"); + if(pos != std::string::npos) + { + themeDir.erase(pos); + char filepath[255]; + char newfilepath[255]; + snprintf(filepath, sizeof(filepath), "%s/tmp/%s.jpg", Settings.theme_path, title); + snprintf(newfilepath, sizeof(newfilepath), "%s/%s/theme_preview.png", Settings.theme_path, themeDir.c_str()); + CopyFile(filepath, newfilepath); + } + + } + + delete zipfile; + remove(filepath); + + int choice = WindowPrompt(tr( "Successfully extracted theme." ), tr( "Do you want to apply it now?" ), tr( "Yes" ), tr( "No" )); + if (choice == 0) + return -1; + + if(Filename.size() == 0) + { + WindowPrompt(tr( "ERROR: Can't set up theme." ), tr( "The .them file was not found in the zip." ), tr( "OK" )); + return -1; + } + + char real_themepath[1024]; + snprintf(real_themepath, sizeof(real_themepath), "%s/%s", Settings.theme_path, Filename.c_str()); + + if (Theme::Load(real_themepath)) + { + snprintf(Settings.theme, sizeof(Settings.theme), real_themepath); + Theme::Reload(); + result = 2; + } + + return result; +} diff --git a/source/themes/ThemeDownloader.h b/source/themes/ThemeDownloader.h new file mode 100644 index 0000000..051a8e4 --- /dev/null +++ b/source/themes/ThemeDownloader.h @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _THEME_DOWNLOADER_H_ +#define _THEME_DOWNLOADER_H_ + +#include "settings/menus/FlyingButtonsMenu.hpp" +#include "themes/Theme_List.h" + +class ThemeDownloader : public FlyingButtonsMenu +{ + public: + ThemeDownloader(); + virtual ~ThemeDownloader(); + static int Execute(); + int MainLoop(); + protected: + void CreateSettingsMenu(int index) { MainButtonClicked(index); }; + void MainButtonClicked(int button); + void AddMainButtons(); + void SetupMainButtons(); + void SetMainButton(int position, const char * ButtonText, GuiImageData * imageData, GuiImageData * imageOver); + GuiImageData * GetImageData(int theme); + int DownloadTheme(const char *url, const char *title); + + Theme_List * ThemeList; + GuiText * urlTxt; + GuiText * defaultBtnTxt; + GuiImage * defaultBtnImg; + GuiButton * defaultBtn; + GuiImageData * ThemePreviews[4]; + std::string ThemeListURL; +}; + +#endif diff --git a/source/themes/ThemeMenu.cpp b/source/themes/ThemeMenu.cpp new file mode 100644 index 0000000..23a9e57 --- /dev/null +++ b/source/themes/ThemeMenu.cpp @@ -0,0 +1,438 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include + +#include "ThemeMenu.h" +#include "language/gettext.h" +#include "prompts/PromptWindows.h" +#include "prompts/ProgressWindow.h" +#include "FileOperations/DirList.h" +#include "network/networkops.h" +#include "themes/CTheme.h" +#include "FileOperations/fileops.h" +#include "sys.h" +#include "menu/menus.h" +#include "utils/ShowError.h" +#include "utils/tools.h" +#include "gecko.h" + + +ThemeMenu::ThemeMenu() + : FlyingButtonsMenu(tr("Theme Menu")) +{ + delete MainButtonImgData; + delete MainButtonImgOverData; + + MainButtonImgData = Resources::GetImageData("theme_box.png"); + MainButtonImgOverData = NULL; + + ParentMenu = MENU_SETTINGS; + + for(int i = 0; i < 4; ++i) + ThemePreviews[i] = NULL; + + defaultBtnTxt = new GuiText(tr( "Default" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + defaultBtnTxt->SetMaxWidth(btnOutline->GetWidth() - 30); + defaultBtnImg = new GuiImage(btnOutline); + if (Settings.wsprompt) + { + defaultBtnTxt->SetWidescreen(Settings.widescreen); + defaultBtnImg->SetWidescreen(Settings.widescreen); + } + defaultBtn = new GuiButton(btnOutline->GetWidth(), btnOutline->GetHeight()); + defaultBtn->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + defaultBtn->SetPosition(-20, 400); + defaultBtn->SetLabel(defaultBtnTxt); + defaultBtn->SetImage(defaultBtnImg); + defaultBtn->SetSoundOver(btnSoundOver); + defaultBtn->SetSoundClick(btnSoundClick2); + defaultBtn->SetTrigger(trigA); + defaultBtn->SetEffectGrow(); + Append(defaultBtn); + + backBtn->SetPosition(-205, 400); +} + +ThemeMenu::~ThemeMenu() +{ + HaltGui(); + for(u32 i = 0; i < MainButton.size(); ++i) + Remove(MainButton[i]); + Remove(defaultBtn); + + delete defaultBtn; + delete defaultBtnTxt; + delete defaultBtnImg; + for(int i = 0; i < 4; ++i) + delete ThemePreviews[i]; +} + +int ThemeMenu::Execute() +{ + ThemeMenu * Menu = new ThemeMenu(); + mainWindow->Append(Menu); + + Menu->ShowMenu(); + + int returnMenu = MENU_NONE; + + while((returnMenu = Menu->MainLoop()) == MENU_NONE); + + delete Menu; + + return returnMenu; +} + +int ThemeMenu::MainLoop() +{ + if(defaultBtn->GetState() == STATE_CLICKED) + { + int choice = WindowPrompt(0, tr("Do you want to load the default theme?"), tr("Yes"), tr("Cancel")); + if(choice) + { + HaltGui(); + Theme::SetDefault(); + Theme::Reload(); + ResumeGui(); + return MENU_THEMEMENU; + } + + defaultBtn->ResetState(); + } + + return FlyingButtonsMenu::MainLoop(); +} + +void ThemeMenu::SetMainButton(int position, const char * ButtonText, GuiImageData * imageData, GuiImageData * themeImg) +{ + if(position >= (int) MainButton.size()) + { + MainButtonImg.resize(position+1); + MainButtonImgOver.resize(position+1); + MainButtonTxt.resize(position+1); + MainButton.resize(position+1); + } + + MainButtonImg[position] = new GuiImage(imageData); + MainButtonImgOver[position] = new GuiImage(themeImg); + MainButtonImgOver[position]->SetScale(0.4); + MainButtonImgOver[position]->SetPosition(50, -45); + + MainButtonTxt[position] = new GuiText(ButtonText, 18, ( GXColor ) {0, 0, 0, 255}); + MainButtonTxt[position]->SetAlignment(ALIGN_CENTER, ALIGN_TOP); + MainButtonTxt[position]->SetPosition(0, 10); + MainButtonTxt[position]->SetMaxWidth(imageData->GetWidth() - 10, DOTTED); + + MainButton[position] = new GuiButton(imageData->GetWidth(), imageData->GetHeight()); + MainButton[position]->SetAlignment(ALIGN_LEFT, ALIGN_TOP); + MainButton[position]->SetSoundOver(btnSoundOver); + MainButton[position]->SetSoundClick(btnSoundClick); + MainButton[position]->SetImage(MainButtonImg[position]); + MainButton[position]->SetImageOver(MainButtonImg[position]); + MainButton[position]->SetIcon(MainButtonImgOver[position]); + MainButton[position]->SetLabel(MainButtonTxt[position]); + MainButton[position]->SetTrigger(trigA); + MainButton[position]->SetEffectGrow(); + + switch(position % 4) + { + case 0: + MainButton[position]->SetPosition(90, 75); + break; + case 1: + MainButton[position]->SetPosition(340, 75); + break; + case 2: + MainButton[position]->SetPosition(90, 230); + break; + case 3: + MainButton[position]->SetPosition(340, 230); + break; + default: + break; + } +} + +GuiImageData * ThemeMenu::GetImageData(int theme) +{ + char filepath[300]; + snprintf(filepath, sizeof(filepath), "%stheme_preview.png", ThemeList[theme].ImageFolder.c_str()); + + return (new GuiImageData(filepath)); +} + +void ThemeMenu::SetupMainButtons() +{ + ThemeList.clear(); + + DirList ThemeDir(Settings.theme_path, ".them", DirList::Files); + if (ThemeDir.GetFilecount() == 0) + { + WindowPrompt(tr( "No themes found." ), 0, "OK"); + } + + for(int i = 0; i < ThemeDir.GetFilecount(); ++i) + { + u8 *buffer = NULL; + u32 filesize; + gprintf("%i %s\n", i, ThemeDir.GetFilepath(i)); + LoadFileToMem(ThemeDir.GetFilepath(i), &buffer, &filesize); + + if(!buffer) continue; + + buffer[filesize-1] = '\0'; + + int size = ThemeList.size(); + ThemeList.resize(size+1); + + ThemeList[size].Filepath = ThemeDir.GetFilepath(i); + GetNodeText(buffer, "Theme-Title:", ThemeList[size].Title); + GetNodeText(buffer, "Theme-Team:", ThemeList[size].Team); + GetNodeText(buffer, "Theme-Version:", ThemeList[size].Version); + GetNodeText(buffer, "Image-Folder:", ThemeList[size].ImageFolder); + + if(ThemeList[size].Title.size() == 0 && ThemeDir.GetFilename(i)) + { + ThemeList[size].Title = ThemeDir.GetFilename(i); + size_t pos = ThemeList[size].Title.rfind('.'); + if(pos != std::string::npos) + ThemeList[size].Title.erase(pos); + } + + if(ThemeList[size].ImageFolder.size() == 0) + { + ThemeList[size].ImageFolder = ThemeDir.GetFilepath(i); + size_t pos = ThemeList[size].ImageFolder.rfind('.'); + if(pos != std::string::npos) + ThemeList[size].ImageFolder.erase(pos); + ThemeList[size].ImageFolder += '/'; + } + else + { + std::string tempString = ThemeList[size].ImageFolder; + ThemeList[size].ImageFolder = Settings.theme_path; + ThemeList[size].ImageFolder += tempString; + ThemeList[size].ImageFolder += '/'; + } + + SetMainButton(size, ThemeList[size].Title.c_str(), MainButtonImgData, NULL); + + free(buffer); + } +} + +bool ThemeMenu::GetNodeText(const u8 *buffer, const char *node, std::string &outtext) +{ + const char * nodeText = strcasestr((const char *) buffer, node); + if(!nodeText) + return false; + + nodeText += strlen(node); + + while(*nodeText == ' ') nodeText++; + + while(*nodeText != '\0' && *nodeText != '\\' && *nodeText != '\n' && *nodeText != '"') + { + outtext.push_back(*nodeText); + nodeText++; + } + + return true; +} + +void ThemeMenu::AddMainButtons() +{ + HaltGui(); + for(u32 i = 0; i < MainButton.size(); ++i) + Remove(MainButton[i]); + + int FirstItem = currentPage*4; + int n = 0; + + for(int i = FirstItem; i < (int) MainButton.size() && i < FirstItem+4; ++i) + { + delete ThemePreviews[n]; + ThemePreviews[n] = GetImageData(i); + MainButtonImgOver[i]->SetImage(ThemePreviews[n]); + n++; + } + + FlyingButtonsMenu::AddMainButtons(); +} + +void ThemeMenu::MainButtonClicked(int button) +{ + //! TODO: Clean me + const char * title = ThemeList[button].Title.c_str(); + const char * author = ThemeList[button].Team.c_str(); + const char * version = ThemeList[button].Version.c_str(); + GuiImageData *thumbimageData = ThemePreviews[button % 4]; + + gprintf("\nTheme_Prompt(%s ,%s)", title, author); + bool leave = false; + + GuiImageData btnOutline(Resources::GetFile("button_dialogue_box.png"), Resources::GetFileSize("button_dialogue_box.png")); + GuiImageData dialogBox(Resources::GetFile("theme_dialogue_box.png"), Resources::GetFileSize("theme_dialogue_box.png")); + + GuiImage dialogBoxImg(&dialogBox); + + GuiWindow promptWindow(dialogBox.GetWidth(), dialogBox.GetHeight()); + promptWindow.SetAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + promptWindow.SetPosition(0, -10); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + int PositionY = 30; + + GuiText titleTxt(tr( "Theme Title:" ), 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + titleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + titleTxt.SetPosition(230, PositionY); + PositionY += 20; + + GuiText titleTxt2(title, 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + titleTxt2.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + titleTxt2.SetPosition(230, PositionY); + titleTxt2.SetMaxWidth(dialogBox.GetWidth() - 220, WRAP); + + if(titleTxt2.GetTextWidth() >= dialogBox.GetWidth() - 220) + PositionY += 50; + else + PositionY += 30; + + GuiText authorTxt(tr( "Author(s):" ), 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + authorTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + authorTxt.SetPosition(230, PositionY); + PositionY += 20; + + GuiText authorTxt2(author, 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + authorTxt2.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + authorTxt2.SetPosition(230, PositionY); + authorTxt2.SetMaxWidth(dialogBox.GetWidth() - 220, DOTTED); + + if(authorTxt2.GetTextWidth() >= dialogBox.GetWidth() - 220) + PositionY += 50; + else + PositionY += 30; + + GuiText versionTxt(tr( "Version:" ), 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + versionTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + versionTxt.SetPosition(230, PositionY); + + GuiText versionTxt2(version, 18, thColor("r=0 g=0 b=0 a=255 - prompt windows text color")); + versionTxt2.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + versionTxt2.SetPosition(235+versionTxt.GetTextWidth(), PositionY); + versionTxt2.SetMaxWidth(dialogBox.GetWidth() - 220, DOTTED); + + GuiText applyBtnTxt(tr( "Apply" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + applyBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30); + GuiImage applyBtnImg(&btnOutline); + if (Settings.wsprompt) + { + applyBtnTxt.SetWidescreen(Settings.widescreen); + applyBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton applyBtn(&applyBtnImg, &applyBtnImg, ALIGN_RIGHT, ALIGN_TOP, -5, 170, &trigA, btnSoundOver, btnSoundClick2, 1); + applyBtn.SetLabel(&applyBtnTxt); + applyBtn.SetScale(0.9); + + GuiText backBtnTxt(tr( "Back" ), 22, thColor("r=0 g=0 b=0 a=255 - prompt windows button text color")); + backBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30); + GuiImage backBtnImg(&btnOutline); + if (Settings.wsprompt) + { + backBtnTxt.SetWidescreen(Settings.widescreen); + backBtnImg.SetWidescreen(Settings.widescreen); + } + GuiButton backBtn(&backBtnImg, &backBtnImg, ALIGN_RIGHT, ALIGN_TOP, -5, 220, &trigA, btnSoundOver, btnSoundClick2, 1); + backBtn.SetLabel(&backBtnTxt); + backBtn.SetTrigger(&trigB); + backBtn.SetScale(0.9); + + GuiImage ThemeImage(thumbimageData); + ThemeImage.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + ThemeImage.SetPosition(20, 10); + ThemeImage.SetScale(0.8); + + promptWindow.Append(&dialogBoxImg); + promptWindow.Append(&ThemeImage); + promptWindow.Append(&titleTxt); + promptWindow.Append(&titleTxt2); + promptWindow.Append(&authorTxt); + promptWindow.Append(&authorTxt2); + promptWindow.Append(&versionTxt); + promptWindow.Append(&versionTxt2); + promptWindow.Append(&applyBtn); + promptWindow.Append(&backBtn); + + HaltGui(); + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); + mainWindow->SetState(STATE_DISABLED); + mainWindow->Append(&promptWindow); + ResumeGui(); + + while (!leave) + { + usleep(100); + + if (shutdown) + Sys_Shutdown(); + else if (reset) + Sys_Reboot(); + + if (applyBtn.GetState() == STATE_CLICKED) + { + int choice = WindowPrompt(tr( "Do you want to apply this theme?" ), title, tr( "Yes" ), tr( "Cancel" )); + if (choice) + { + if (Theme::Load(ThemeList[button].Filepath.c_str())) + { + snprintf(Settings.theme, sizeof(Settings.theme), ThemeList[button].Filepath.c_str()); + Theme::Reload(); + returnMenu = MENU_THEMEMENU; + leave = true; + } + } + mainWindow->SetState(STATE_DISABLED); + promptWindow.SetState(STATE_DEFAULT); + applyBtn.ResetState(); + } + + else if (backBtn.GetState() == STATE_CLICKED) + { + leave = true; + backBtn.ResetState(); + } + } + + promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50); + while (promptWindow.GetEffect() > 0) usleep(100); + HaltGui(); + mainWindow->Remove(&promptWindow); + mainWindow->SetState(STATE_DEFAULT); + ResumeGui(); +} diff --git a/source/themes/ThemeMenu.h b/source/themes/ThemeMenu.h new file mode 100644 index 0000000..9c94d0d --- /dev/null +++ b/source/themes/ThemeMenu.h @@ -0,0 +1,64 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _THEME_MENU_H_ +#define _THEME_MENU_H_ + +#include +#include +#include "settings/menus/FlyingButtonsMenu.hpp" +#include "FileOperations/DirList.h" +#include "themes/Theme_List.h" + +class ThemeMenu : public FlyingButtonsMenu +{ + public: + ThemeMenu(); + virtual ~ThemeMenu(); + static int Execute(); + int MainLoop(); + protected: + void CreateSettingsMenu(int index) { MainButtonClicked(index); }; + void MainButtonClicked(int button); + void AddMainButtons(); + void SetupMainButtons(); + void SetMainButton(int position, const char * ButtonText, GuiImageData * imageData, GuiImageData * imageOver); + GuiImageData * GetImageData(int theme); + bool GetNodeText(const u8 *buffer, const char *node, std::string &outtext); + + struct ThemeInfoStruct + { + std::string Filepath; + std::string Title; + std::string Team; + std::string Version; + std::string ImageFolder; + }; + std::vector ThemeList; + GuiText * defaultBtnTxt; + GuiImage * defaultBtnImg; + GuiButton * defaultBtn; + GuiImageData * ThemePreviews[4]; +}; + +#endif diff --git a/source/themes/Theme_List.cpp b/source/themes/Theme_List.cpp new file mode 100644 index 0000000..dff17a0 --- /dev/null +++ b/source/themes/Theme_List.cpp @@ -0,0 +1,143 @@ +/*************************************************************************** + * Copyright (C) 2009 + * by USB Loader GX Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * Theme_List Class + * for the USB Loader GX + ***************************************************************************/ +#include +#include +#include +#include + +#include "network/networkops.h" +#include "Theme_List.h" +#include "xml/tinyxml2.h" + +using namespace tinyxml2; + +Theme_List::Theme_List(const char * url) +{ + if (!IsNetworkInit()) + return; + + u8 *buffer = NULL; + u32 size = 0; + + DownloadWithResponse(url, &buffer, &size); + + if(!buffer) + return; + + const char *xml = strstr((char *) buffer, "FirstChildElement("theme"); + + while(theme) + { + int i = ThemesList.size(); + ThemesList.resize(i+1); + + XMLElement *node = NULL; + + node = theme->FirstChildElement("name"); + if(node && node->FirstChild() && node->FirstChild()->Value()) + ThemesList[i].themetitle = node->FirstChild()->Value(); + + node = theme->FirstChildElement("creator"); + if(node && node->FirstChild() && node->FirstChild()->Value()) + ThemesList[i].author = node->FirstChild()->Value(); + + node = theme->FirstChildElement("thumbpath"); + if(node && node->FirstChild() && node->FirstChild()->Value()) + ThemesList[i].imagelink = node->FirstChild()->Value(); + + node = theme->FirstChildElement("downloadpath"); + if(node && node->FirstChild() && node->FirstChild()->Value()) + ThemesList[i].downloadlink = node->FirstChild()->Value(); + + node = theme->FirstChildElement("averagerating"); + if(node && node->FirstChild() && node->FirstChild()->Value()) + ThemesList[i].rating = atoi(node->FirstChild()->Value()); + + theme = theme->NextSiblingElement(); + } + + return true; +} + +const char * Theme_List::GetThemeTitle(int ind) const +{ + if (ind < 0 || ind >= (int) ThemesList.size()) + return NULL; + + else return ThemesList[ind].themetitle.c_str(); +} + +const char * Theme_List::GetThemeAuthor(int ind) const +{ + if (ind < 0 || ind >= (int) ThemesList.size()) + return NULL; + + return ThemesList[ind].author.c_str(); +} + +const char * Theme_List::GetImageLink(int ind) const +{ + if (ind < 0 || ind >= (int) ThemesList.size()) + return NULL; + + return ThemesList[ind].imagelink.c_str(); +} + +const char * Theme_List::GetDownloadLink(int ind) const +{ + if (ind < 0 || ind >= (int) ThemesList.size()) + return NULL; + + return ThemesList[ind].downloadlink.c_str(); +} diff --git a/source/themes/Theme_List.h b/source/themes/Theme_List.h new file mode 100644 index 0000000..ffb337a --- /dev/null +++ b/source/themes/Theme_List.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * Theme_List Class + * for USB Loader GX + * by dimok + ***************************************************************************/ +#ifndef ___THEMELIST_H_ +#define ___THEMELIST_H_ + +#include +#include +#include "network/networkops.h" +#include "network/http.h" + +typedef struct _theme_info +{ + std::string themetitle; + std::string author; + std::string imagelink; + std::string downloadlink; + u8 rating; +} Theme_Info; + +class Theme_List +{ + public: + //!Constructor + //!\param url from where to get the list of links + Theme_List(const char *url); + //!Destructor + ~Theme_List(); + //! Get the a theme title + //!\param list index + const char * GetThemeTitle(int index) const; + //! Get the author of the theme + //!\param list index + const char * GetThemeAuthor(int index) const; + //! Get the author of the theme + //!\param list index + const char * GetImageLink(int index) const; + //! Get the download link of the theme + //!\param list index + const char * GetDownloadLink(int index) const; + //! Get the number of links counted + int GetThemeCount() const { return ThemesList.size(); }; + protected: + //!Get Themes into a struct from the XML file amount + bool ParseXML(const char * xmlfile); + std::vector ThemesList; +}; + +#endif diff --git a/source/themes/filelist.h b/source/themes/filelist.h new file mode 100644 index 0000000..1002c3f --- /dev/null +++ b/source/themes/filelist.h @@ -0,0 +1,822 @@ +/**************************************************************************** + * USB Loader GX resource files. + * This file is generated automatically. + * Includes 200 files. + * + * NOTE: + * Any manual modification of this file will be overwriten by the generation. + ****************************************************************************/ +#ifndef _FILELIST_H_ +#define _FILELIST_H_ + +#include + +extern const u8 abcIcon_png[]; +extern const u32 abcIcon_png_size; + +extern const u8 add_png[]; +extern const u32 add_png_size; + +extern const u8 addressbar_textbox_png[]; +extern const u32 addressbar_textbox_png_size; + +extern const u8 arrangeBannerGrid_png[]; +extern const u32 arrangeBannerGrid_png_size; + +extern const u8 arrangeBannerGrid_gray_png[]; +extern const u32 arrangeBannerGrid_gray_png_size; + +extern const u8 arrangeCarousel_png[]; +extern const u32 arrangeCarousel_png_size; + +extern const u8 arrangeCarousel_gray_png[]; +extern const u32 arrangeCarousel_gray_png_size; + +extern const u8 arrangeGrid_png[]; +extern const u32 arrangeGrid_png_size; + +extern const u8 arrangeGrid_gray_png[]; +extern const u32 arrangeGrid_gray_png_size; + +extern const u8 arrangeList_png[]; +extern const u32 arrangeList_png_size; + +extern const u8 arrangeList_gray_png[]; +extern const u32 arrangeList_gray_png_size; + +extern const u8 background_png[]; +extern const u32 background_png_size; + +extern const u8 balanceboard_png[]; +extern const u32 balanceboard_png_size; + +extern const u8 balanceboardR_png[]; +extern const u32 balanceboardR_png_size; + +extern const u8 battery_png[]; +extern const u32 battery_png_size; + +extern const u8 battery_bar_png[]; +extern const u32 battery_bar_png_size; + +extern const u8 battery_bar_red_png[]; +extern const u32 battery_bar_red_png_size; + +extern const u8 battery_bar_white_png[]; +extern const u32 battery_bar_white_png_size; + +extern const u8 battery_red_png[]; +extern const u32 battery_red_png_size; + +extern const u8 battery_white_png[]; +extern const u32 battery_white_png_size; + +extern const u8 bg_browser_png[]; +extern const u32 bg_browser_png_size; + +extern const u8 bg_browser_selection_png[]; +extern const u32 bg_browser_selection_png_size; + +extern const u8 bg_options_png[]; +extern const u32 bg_options_png_size; + +extern const u8 bg_options_entry_png[]; +extern const u32 bg_options_entry_png_size; + +extern const u8 bg_options_settings_png[]; +extern const u32 bg_options_settings_png_size; + +extern const u8 boxBorder_png[]; +extern const u32 boxBorder_png_size; + +extern const u8 browser_png[]; +extern const u32 browser_png_size; + +extern const u8 browser_over_png[]; +extern const u32 browser_over_png_size; + +extern const u8 button_dialogue_box_png[]; +extern const u32 button_dialogue_box_png_size; + +extern const u8 button_install_png[]; +extern const u32 button_install_png_size; + +extern const u8 button_install_over_png[]; +extern const u32 button_install_over_png_size; + +extern const u8 category_png[]; +extern const u32 category_png_size; + +extern const u8 categoryPrompt_png[]; +extern const u32 categoryPrompt_png_size; + +extern const u8 category_gray_png[]; +extern const u32 category_gray_png_size; + +extern const u8 cero_a_png[]; +extern const u32 cero_a_png_size; + +extern const u8 cero_b_png[]; +extern const u32 cero_b_png_size; + +extern const u8 cero_c_png[]; +extern const u32 cero_c_png_size; + +extern const u8 cero_d_png[]; +extern const u32 cero_d_png_size; + +extern const u8 cero_z_png[]; +extern const u32 cero_z_png_size; + +extern const u8 channel_btn_png[]; +extern const u32 channel_btn_png_size; + +extern const u8 checkBoxSelection_png[]; +extern const u32 checkBoxSelection_png_size; + +extern const u8 classiccontroller_png[]; +extern const u32 classiccontroller_png_size; + +extern const u8 classiccontrollerR_png[]; +extern const u32 classiccontrollerR_png_size; + +extern const u8 closebutton_png[]; +extern const u32 closebutton_png_size; + +extern const u8 credits_bg_png[]; +extern const u32 credits_bg_png_size; + +extern const u8 credits_button_png[]; +extern const u32 credits_button_png_size; + +extern const u8 credits_button_over_png[]; +extern const u32 credits_button_over_png_size; + +extern const u8 dancepad_png[]; +extern const u32 dancepad_png_size; + +extern const u8 dancepadR_png[]; +extern const u32 dancepadR_png_size; + +extern const u8 dialogue_box_png[]; +extern const u32 dialogue_box_png_size; + +extern const u8 dialogue_box_startgame_png[]; +extern const u32 dialogue_box_startgame_png_size; + +extern const u8 drums_png[]; +extern const u32 drums_png_size; + +extern const u8 drumsR_png[]; +extern const u32 drumsR_png_size; + +extern const u8 dvd_png[]; +extern const u32 dvd_png_size; + +extern const u8 dvd_gray_png[]; +extern const u32 dvd_gray_png_size; + +extern const u8 esrb_ao_png[]; +extern const u32 esrb_ao_png_size; + +extern const u8 esrb_e_png[]; +extern const u32 esrb_e_png_size; + +extern const u8 esrb_ec_png[]; +extern const u32 esrb_ec_png_size; + +extern const u8 esrb_eten_png[]; +extern const u32 esrb_eten_png_size; + +extern const u8 esrb_m_png[]; +extern const u32 esrb_m_png_size; + +extern const u8 esrb_t_png[]; +extern const u32 esrb_t_png_size; + +extern const u8 exit_bottom_png[]; +extern const u32 exit_bottom_png_size; + +extern const u8 exit_bottom_over_png[]; +extern const u32 exit_bottom_over_png_size; + +extern const u8 exit_button_png[]; +extern const u32 exit_button_png_size; + +extern const u8 exit_top_png[]; +extern const u32 exit_top_png_size; + +extern const u8 exit_top_over_png[]; +extern const u32 exit_top_over_png_size; + +extern const u8 favIcon_png[]; +extern const u32 favIcon_png_size; + +extern const u8 favIcon_gray_png[]; +extern const u32 favIcon_gray_png_size; + +extern const u8 favorite_png[]; +extern const u32 favorite_png_size; + +extern const u8 gameinfo1_png[]; +extern const u32 gameinfo1_png_size; + +extern const u8 gameinfo1a_png[]; +extern const u32 gameinfo1a_png_size; + +extern const u8 gameinfo2_png[]; +extern const u32 gameinfo2_png_size; + +extern const u8 gameinfo2a_png[]; +extern const u32 gameinfo2a_png_size; + +extern const u8 gcncontroller_png[]; +extern const u32 gcncontroller_png_size; + +extern const u8 gcncontrollerR_png[]; +extern const u32 gcncontrollerR_png_size; + +extern const u8 gc_banner_bg_png[]; +extern const u32 gc_banner_bg_png_size; + +extern const u8 gc_icon_bg_png[]; +extern const u32 gc_icon_bg_png_size; + +extern const u8 guitar_png[]; +extern const u32 guitar_png_size; + +extern const u8 guitarR_png[]; +extern const u32 guitarR_png_size; + +extern const u8 gxlogo_png[]; +extern const u32 gxlogo_png_size; + +extern const u8 icon_folder_png[]; +extern const u32 icon_folder_png_size; + +extern const u8 keyboard_backspace_over_png[]; +extern const u32 keyboard_backspace_over_png_size; + +extern const u8 keyboard_clear_over_png[]; +extern const u32 keyboard_clear_over_png_size; + +extern const u8 keyboard_key_png[]; +extern const u32 keyboard_key_png_size; + +extern const u8 keyboard_key_over_png[]; +extern const u32 keyboard_key_over_png_size; + +extern const u8 keyboard_largekey_over_png[]; +extern const u32 keyboard_largekey_over_png_size; + +extern const u8 keyboard_mediumkey_over_png[]; +extern const u32 keyboard_mediumkey_over_png_size; + +extern const u8 keyboard_textbox_png[]; +extern const u32 keyboard_textbox_png_size; + +extern const u8 little_star_png[]; +extern const u32 little_star_png_size; + +extern const u8 loader_mode_png[]; +extern const u32 loader_mode_png_size; + +extern const u8 lock_png[]; +extern const u32 lock_png_size; + +extern const u8 lock_gray_png[]; +extern const u32 lock_gray_png_size; + +extern const u8 menu_button_png[]; +extern const u32 menu_button_png_size; + +extern const u8 menu_button_over_png[]; +extern const u32 menu_button_over_png_size; + +extern const u8 microphone_png[]; +extern const u32 microphone_png_size; + +extern const u8 microphoneR_png[]; +extern const u32 microphoneR_png_size; + +extern const u8 motionplus_png[]; +extern const u32 motionplus_png_size; + +extern const u8 motionplusR_png[]; +extern const u32 motionplusR_png_size; + +extern const u8 new_png[]; +extern const u32 new_png_size; + +extern const u8 nintendods_png[]; +extern const u32 nintendods_png_size; + +extern const u8 nintendodsR_png[]; +extern const u32 nintendodsR_png_size; + +extern const u8 nocover_png[]; +extern const u32 nocover_png_size; + +extern const u8 nocoverFlat_png[]; +extern const u32 nocoverFlat_png_size; + +extern const u8 nocoverFull_png[]; +extern const u32 nocoverFull_png_size; + +extern const u8 nodisc_png[]; +extern const u32 nodisc_png_size; + +extern const u8 norating_png[]; +extern const u32 norating_png_size; + +extern const u8 not_favorite_png[]; +extern const u32 not_favorite_png_size; + +extern const u8 nunchuk_png[]; +extern const u32 nunchuk_png_size; + +extern const u8 nunchukR_png[]; +extern const u32 nunchukR_png_size; + +extern const u8 one_png[]; +extern const u32 one_png_size; + +extern const u8 oneButtonScroll_png[]; +extern const u32 oneButtonScroll_png_size; + +extern const u8 pageindicator_png[]; +extern const u32 pageindicator_png_size; + +extern const u8 pegi_12_png[]; +extern const u32 pegi_12_png_size; + +extern const u8 pegi_16_png[]; +extern const u32 pegi_16_png_size; + +extern const u8 pegi_18_png[]; +extern const u32 pegi_18_png_size; + +extern const u8 pegi_3_png[]; +extern const u32 pegi_3_png_size; + +extern const u8 pegi_7_png[]; +extern const u32 pegi_7_png_size; + +extern const u8 playCountIcon_png[]; +extern const u32 playCountIcon_png_size; + +extern const u8 player1_grab_png[]; +extern const u32 player1_grab_png_size; + +extern const u8 player1_point_png[]; +extern const u32 player1_point_png_size; + +extern const u8 player2_grab_png[]; +extern const u32 player2_grab_png_size; + +extern const u8 player2_point_png[]; +extern const u32 player2_point_png_size; + +extern const u8 player3_grab_png[]; +extern const u32 player3_grab_png_size; + +extern const u8 player3_point_png[]; +extern const u32 player3_point_png_size; + +extern const u8 player4_grab_png[]; +extern const u32 player4_grab_png_size; + +extern const u8 player4_point_png[]; +extern const u32 player4_point_png_size; + +extern const u8 playersSort_png[]; +extern const u32 playersSort_png_size; + +extern const u8 progressbar_png[]; +extern const u32 progressbar_png_size; + +extern const u8 progressbar_empty_png[]; +extern const u32 progressbar_empty_png_size; + +extern const u8 progressbar_outline_png[]; +extern const u32 progressbar_outline_png_size; + +extern const u8 rankIcon_png[]; +extern const u32 rankIcon_png_size; + +extern const u8 remove_png[]; +extern const u32 remove_png_size; + +extern const u8 rplayer1_point_png[]; +extern const u32 rplayer1_point_png_size; + +extern const u8 rplayer2_point_png[]; +extern const u32 rplayer2_point_png_size; + +extern const u8 rplayer3_point_png[]; +extern const u32 rplayer3_point_png_size; + +extern const u8 rplayer4_point_png[]; +extern const u32 rplayer4_point_png_size; + +extern const u8 scrollBarBottom_png[]; +extern const u32 scrollBarBottom_png_size; + +extern const u8 scrollBarTile_png[]; +extern const u32 scrollBarTile_png_size; + +extern const u8 scrollBarTop_png[]; +extern const u32 scrollBarTop_png_size; + +extern const u8 scrollbar_arrowdown_png[]; +extern const u32 scrollbar_arrowdown_png_size; + +extern const u8 scrollbar_arrowup_png[]; +extern const u32 scrollbar_arrowup_png_size; + +extern const u8 scrollbar_box_png[]; +extern const u32 scrollbar_box_png_size; + +extern const u8 sdcard_png[]; +extern const u32 sdcard_png_size; + +extern const u8 sdcard_over_png[]; +extern const u32 sdcard_over_png_size; + +extern const u8 searchIcon_png[]; +extern const u32 searchIcon_png_size; + +extern const u8 searchIcon_gray_png[]; +extern const u32 searchIcon_gray_png_size; + +extern const u8 settings_background_png[]; +extern const u32 settings_background_png_size; + +extern const u8 settings_button_png[]; +extern const u32 settings_button_png_size; + +extern const u8 settings_button_over_png[]; +extern const u32 settings_button_over_png_size; + +extern const u8 settings_title_png[]; +extern const u32 settings_title_png_size; + +extern const u8 settings_title_over_png[]; +extern const u32 settings_title_over_png_size; + +extern const u8 startgame_arrow_left_png[]; +extern const u32 startgame_arrow_left_png_size; + +extern const u8 startgame_arrow_right_png[]; +extern const u32 startgame_arrow_right_png_size; + +extern const u8 theme_box_png[]; +extern const u32 theme_box_png_size; + +extern const u8 theme_dialogue_box_png[]; +extern const u32 theme_dialogue_box_png_size; + +extern const u8 tooltip_left_png[]; +extern const u32 tooltip_left_png_size; + +extern const u8 tooltip_right_png[]; +extern const u32 tooltip_right_png_size; + +extern const u8 tooltip_tile_png[]; +extern const u32 tooltip_tile_png_size; + +extern const u8 unlock_png[]; +extern const u32 unlock_png_size; + +extern const u8 unlock_gray_png[]; +extern const u32 unlock_gray_png_size; + +extern const u8 wbackground_png[]; +extern const u32 wbackground_png_size; + +extern const u8 wdialogue_box_startgame_png[]; +extern const u32 wdialogue_box_startgame_png_size; + +extern const u8 wheel_png[]; +extern const u32 wheel_png_size; + +extern const u8 wheelR_png[]; +extern const u32 wheelR_png_size; + +extern const u8 wifi1_png[]; +extern const u32 wifi1_png_size; + +extern const u8 wifi10_png[]; +extern const u32 wifi10_png_size; + +extern const u8 wifi12_png[]; +extern const u32 wifi12_png_size; + +extern const u8 wifi16_png[]; +extern const u32 wifi16_png_size; + +extern const u8 wifi2_png[]; +extern const u32 wifi2_png_size; + +extern const u8 wifi3_png[]; +extern const u32 wifi3_png_size; + +extern const u8 wifi32_png[]; +extern const u32 wifi32_png_size; + +extern const u8 wifi4_png[]; +extern const u32 wifi4_png_size; + +extern const u8 wifi6_png[]; +extern const u32 wifi6_png_size; + +extern const u8 wifi8_png[]; +extern const u32 wifi8_png_size; + +extern const u8 wifi_btn_png[]; +extern const u32 wifi_btn_png_size; + +extern const u8 wiimote_png[]; +extern const u32 wiimote_png_size; + +extern const u8 wiimote1_png[]; +extern const u32 wiimote1_png_size; + +extern const u8 wiimote2_png[]; +extern const u32 wiimote2_png_size; + +extern const u8 wiimote3_png[]; +extern const u32 wiimote3_png_size; + +extern const u8 wiimote4_png[]; +extern const u32 wiimote4_png_size; + +extern const u8 wiimote_poweroff_png[]; +extern const u32 wiimote_poweroff_png_size; + +extern const u8 wiimote_poweroff_over_png[]; +extern const u32 wiimote_poweroff_over_png_size; + +extern const u8 wiispeak_png[]; +extern const u32 wiispeak_png_size; + +extern const u8 wiispeakR_png[]; +extern const u32 wiispeakR_png_size; + +extern const u8 zapper_png[]; +extern const u32 zapper_png_size; + +extern const u8 zapperR_png[]; +extern const u32 zapperR_png_size; + +extern const u8 bg_music_ogg[]; +extern const u32 bg_music_ogg_size; + +extern const u8 button_click_wav[]; +extern const u32 button_click_wav_size; + +extern const u8 button_click2_wav[]; +extern const u32 button_click2_wav_size; + +extern const u8 button_over_wav[]; +extern const u32 button_over_wav_size; + +extern const u8 credits_music_ogg[]; +extern const u32 credits_music_ogg_size; + +extern const u8 gc_banner_ogg[]; +extern const u32 gc_banner_ogg_size; + +extern const u8 menuin_ogg[]; +extern const u32 menuin_ogg_size; + +extern const u8 menuout_ogg[]; +extern const u32 menuout_ogg_size; + +extern const u8 success_ogg[]; +extern const u32 success_ogg_size; + +extern const u8 clock_ttf[]; +extern const u32 clock_ttf_size; + +extern const u8 font_ttf[]; +extern const u32 font_ttf_size; + +extern const u8 app_booter_bin[]; +extern const u32 app_booter_bin_size; + +extern const u8 custom_banner_bnr[]; +extern const u32 custom_banner_bnr_size; + +extern const u8 stub_bin[]; +extern const u32 stub_bin_size; + +RecourceFile Resources::RecourceFiles[] = +{ + {"abcIcon.png", abcIcon_png, abcIcon_png_size, NULL, 0}, + {"add.png", add_png, add_png_size, NULL, 0}, + {"addressbar_textbox.png", addressbar_textbox_png, addressbar_textbox_png_size, NULL, 0}, + {"arrangeBannerGrid.png", arrangeBannerGrid_png, arrangeBannerGrid_png_size, NULL, 0}, + {"arrangeBannerGrid_gray.png", arrangeBannerGrid_gray_png, arrangeBannerGrid_gray_png_size, NULL, 0}, + {"arrangeCarousel.png", arrangeCarousel_png, arrangeCarousel_png_size, NULL, 0}, + {"arrangeCarousel_gray.png", arrangeCarousel_gray_png, arrangeCarousel_gray_png_size, NULL, 0}, + {"arrangeGrid.png", arrangeGrid_png, arrangeGrid_png_size, NULL, 0}, + {"arrangeGrid_gray.png", arrangeGrid_gray_png, arrangeGrid_gray_png_size, NULL, 0}, + {"arrangeList.png", arrangeList_png, arrangeList_png_size, NULL, 0}, + {"arrangeList_gray.png", arrangeList_gray_png, arrangeList_gray_png_size, NULL, 0}, + {"background.png", background_png, background_png_size, NULL, 0}, + {"balanceboard.png", balanceboard_png, balanceboard_png_size, NULL, 0}, + {"balanceboardR.png", balanceboardR_png, balanceboardR_png_size, NULL, 0}, + {"battery.png", battery_png, battery_png_size, NULL, 0}, + {"battery_bar.png", battery_bar_png, battery_bar_png_size, NULL, 0}, + {"battery_bar_red.png", battery_bar_red_png, battery_bar_red_png_size, NULL, 0}, + {"battery_bar_white.png", battery_bar_white_png, battery_bar_white_png_size, NULL, 0}, + {"battery_red.png", battery_red_png, battery_red_png_size, NULL, 0}, + {"battery_white.png", battery_white_png, battery_white_png_size, NULL, 0}, + {"bg_browser.png", bg_browser_png, bg_browser_png_size, NULL, 0}, + {"bg_browser_selection.png", bg_browser_selection_png, bg_browser_selection_png_size, NULL, 0}, + {"bg_options.png", bg_options_png, bg_options_png_size, NULL, 0}, + {"bg_options_entry.png", bg_options_entry_png, bg_options_entry_png_size, NULL, 0}, + {"bg_options_settings.png", bg_options_settings_png, bg_options_settings_png_size, NULL, 0}, + {"boxBorder.png", boxBorder_png, boxBorder_png_size, NULL, 0}, + {"browser.png", browser_png, browser_png_size, NULL, 0}, + {"browser_over.png", browser_over_png, browser_over_png_size, NULL, 0}, + {"button_dialogue_box.png", button_dialogue_box_png, button_dialogue_box_png_size, NULL, 0}, + {"button_install.png", button_install_png, button_install_png_size, NULL, 0}, + {"button_install_over.png", button_install_over_png, button_install_over_png_size, NULL, 0}, + {"category.png", category_png, category_png_size, NULL, 0}, + {"categoryPrompt.png", categoryPrompt_png, categoryPrompt_png_size, NULL, 0}, + {"category_gray.png", category_gray_png, category_gray_png_size, NULL, 0}, + {"cero_a.png", cero_a_png, cero_a_png_size, NULL, 0}, + {"cero_b.png", cero_b_png, cero_b_png_size, NULL, 0}, + {"cero_c.png", cero_c_png, cero_c_png_size, NULL, 0}, + {"cero_d.png", cero_d_png, cero_d_png_size, NULL, 0}, + {"cero_z.png", cero_z_png, cero_z_png_size, NULL, 0}, + {"channel_btn.png", channel_btn_png, channel_btn_png_size, NULL, 0}, + {"checkBoxSelection.png", checkBoxSelection_png, checkBoxSelection_png_size, NULL, 0}, + {"classiccontroller.png", classiccontroller_png, classiccontroller_png_size, NULL, 0}, + {"classiccontrollerR.png", classiccontrollerR_png, classiccontrollerR_png_size, NULL, 0}, + {"closebutton.png", closebutton_png, closebutton_png_size, NULL, 0}, + {"credits_bg.png", credits_bg_png, credits_bg_png_size, NULL, 0}, + {"credits_button.png", credits_button_png, credits_button_png_size, NULL, 0}, + {"credits_button_over.png", credits_button_over_png, credits_button_over_png_size, NULL, 0}, + {"dancepad.png", dancepad_png, dancepad_png_size, NULL, 0}, + {"dancepadR.png", dancepadR_png, dancepadR_png_size, NULL, 0}, + {"dialogue_box.png", dialogue_box_png, dialogue_box_png_size, NULL, 0}, + {"dialogue_box_startgame.png", dialogue_box_startgame_png, dialogue_box_startgame_png_size, NULL, 0}, + {"drums.png", drums_png, drums_png_size, NULL, 0}, + {"drumsR.png", drumsR_png, drumsR_png_size, NULL, 0}, + {"dvd.png", dvd_png, dvd_png_size, NULL, 0}, + {"dvd_gray.png", dvd_gray_png, dvd_gray_png_size, NULL, 0}, + {"esrb_ao.png", esrb_ao_png, esrb_ao_png_size, NULL, 0}, + {"esrb_e.png", esrb_e_png, esrb_e_png_size, NULL, 0}, + {"esrb_ec.png", esrb_ec_png, esrb_ec_png_size, NULL, 0}, + {"esrb_eten.png", esrb_eten_png, esrb_eten_png_size, NULL, 0}, + {"esrb_m.png", esrb_m_png, esrb_m_png_size, NULL, 0}, + {"esrb_t.png", esrb_t_png, esrb_t_png_size, NULL, 0}, + {"exit_bottom.png", exit_bottom_png, exit_bottom_png_size, NULL, 0}, + {"exit_bottom_over.png", exit_bottom_over_png, exit_bottom_over_png_size, NULL, 0}, + {"exit_button.png", exit_button_png, exit_button_png_size, NULL, 0}, + {"exit_top.png", exit_top_png, exit_top_png_size, NULL, 0}, + {"exit_top_over.png", exit_top_over_png, exit_top_over_png_size, NULL, 0}, + {"favIcon.png", favIcon_png, favIcon_png_size, NULL, 0}, + {"favIcon_gray.png", favIcon_gray_png, favIcon_gray_png_size, NULL, 0}, + {"favorite.png", favorite_png, favorite_png_size, NULL, 0}, + {"gameinfo1.png", gameinfo1_png, gameinfo1_png_size, NULL, 0}, + {"gameinfo1a.png", gameinfo1a_png, gameinfo1a_png_size, NULL, 0}, + {"gameinfo2.png", gameinfo2_png, gameinfo2_png_size, NULL, 0}, + {"gameinfo2a.png", gameinfo2a_png, gameinfo2a_png_size, NULL, 0}, + {"gcncontroller.png", gcncontroller_png, gcncontroller_png_size, NULL, 0}, + {"gcncontrollerR.png", gcncontrollerR_png, gcncontrollerR_png_size, NULL, 0}, + {"gc_banner_bg.png", gc_banner_bg_png, gc_banner_bg_png_size, NULL, 0}, + {"gc_icon_bg.png", gc_icon_bg_png, gc_icon_bg_png_size, NULL, 0}, + {"guitar.png", guitar_png, guitar_png_size, NULL, 0}, + {"guitarR.png", guitarR_png, guitarR_png_size, NULL, 0}, + {"gxlogo.png", gxlogo_png, gxlogo_png_size, NULL, 0}, + {"icon_folder.png", icon_folder_png, icon_folder_png_size, NULL, 0}, + {"keyboard_backspace_over.png", keyboard_backspace_over_png, keyboard_backspace_over_png_size, NULL, 0}, + {"keyboard_clear_over.png", keyboard_clear_over_png, keyboard_clear_over_png_size, NULL, 0}, + {"keyboard_key.png", keyboard_key_png, keyboard_key_png_size, NULL, 0}, + {"keyboard_key_over.png", keyboard_key_over_png, keyboard_key_over_png_size, NULL, 0}, + {"keyboard_largekey_over.png", keyboard_largekey_over_png, keyboard_largekey_over_png_size, NULL, 0}, + {"keyboard_mediumkey_over.png", keyboard_mediumkey_over_png, keyboard_mediumkey_over_png_size, NULL, 0}, + {"keyboard_textbox.png", keyboard_textbox_png, keyboard_textbox_png_size, NULL, 0}, + {"little_star.png", little_star_png, little_star_png_size, NULL, 0}, + {"loader_mode.png", loader_mode_png, loader_mode_png_size, NULL, 0}, + {"lock.png", lock_png, lock_png_size, NULL, 0}, + {"lock_gray.png", lock_gray_png, lock_gray_png_size, NULL, 0}, + {"menu_button.png", menu_button_png, menu_button_png_size, NULL, 0}, + {"menu_button_over.png", menu_button_over_png, menu_button_over_png_size, NULL, 0}, + {"microphone.png", microphone_png, microphone_png_size, NULL, 0}, + {"microphoneR.png", microphoneR_png, microphoneR_png_size, NULL, 0}, + {"motionplus.png", motionplus_png, motionplus_png_size, NULL, 0}, + {"motionplusR.png", motionplusR_png, motionplusR_png_size, NULL, 0}, + {"new.png", new_png, new_png_size, NULL, 0}, + {"nintendods.png", nintendods_png, nintendods_png_size, NULL, 0}, + {"nintendodsR.png", nintendodsR_png, nintendodsR_png_size, NULL, 0}, + {"nocover.png", nocover_png, nocover_png_size, NULL, 0}, + {"nocoverFlat.png", nocoverFlat_png, nocoverFlat_png_size, NULL, 0}, + {"nocoverFull.png", nocoverFull_png, nocoverFull_png_size, NULL, 0}, + {"nodisc.png", nodisc_png, nodisc_png_size, NULL, 0}, + {"norating.png", norating_png, norating_png_size, NULL, 0}, + {"not_favorite.png", not_favorite_png, not_favorite_png_size, NULL, 0}, + {"nunchuk.png", nunchuk_png, nunchuk_png_size, NULL, 0}, + {"nunchukR.png", nunchukR_png, nunchukR_png_size, NULL, 0}, + {"one.png", one_png, one_png_size, NULL, 0}, + {"oneButtonScroll.png", oneButtonScroll_png, oneButtonScroll_png_size, NULL, 0}, + {"pageindicator.png", pageindicator_png, pageindicator_png_size, NULL, 0}, + {"pegi_12.png", pegi_12_png, pegi_12_png_size, NULL, 0}, + {"pegi_16.png", pegi_16_png, pegi_16_png_size, NULL, 0}, + {"pegi_18.png", pegi_18_png, pegi_18_png_size, NULL, 0}, + {"pegi_3.png", pegi_3_png, pegi_3_png_size, NULL, 0}, + {"pegi_7.png", pegi_7_png, pegi_7_png_size, NULL, 0}, + {"playCountIcon.png", playCountIcon_png, playCountIcon_png_size, NULL, 0}, + {"player1_grab.png", player1_grab_png, player1_grab_png_size, NULL, 0}, + {"player1_point.png", player1_point_png, player1_point_png_size, NULL, 0}, + {"player2_grab.png", player2_grab_png, player2_grab_png_size, NULL, 0}, + {"player2_point.png", player2_point_png, player2_point_png_size, NULL, 0}, + {"player3_grab.png", player3_grab_png, player3_grab_png_size, NULL, 0}, + {"player3_point.png", player3_point_png, player3_point_png_size, NULL, 0}, + {"player4_grab.png", player4_grab_png, player4_grab_png_size, NULL, 0}, + {"player4_point.png", player4_point_png, player4_point_png_size, NULL, 0}, + {"playersSort.png", playersSort_png, playersSort_png_size, NULL, 0}, + {"progressbar.png", progressbar_png, progressbar_png_size, NULL, 0}, + {"progressbar_empty.png", progressbar_empty_png, progressbar_empty_png_size, NULL, 0}, + {"progressbar_outline.png", progressbar_outline_png, progressbar_outline_png_size, NULL, 0}, + {"rankIcon.png", rankIcon_png, rankIcon_png_size, NULL, 0}, + {"remove.png", remove_png, remove_png_size, NULL, 0}, + {"rplayer1_point.png", rplayer1_point_png, rplayer1_point_png_size, NULL, 0}, + {"rplayer2_point.png", rplayer2_point_png, rplayer2_point_png_size, NULL, 0}, + {"rplayer3_point.png", rplayer3_point_png, rplayer3_point_png_size, NULL, 0}, + {"rplayer4_point.png", rplayer4_point_png, rplayer4_point_png_size, NULL, 0}, + {"scrollBarBottom.png", scrollBarBottom_png, scrollBarBottom_png_size, NULL, 0}, + {"scrollBarTile.png", scrollBarTile_png, scrollBarTile_png_size, NULL, 0}, + {"scrollBarTop.png", scrollBarTop_png, scrollBarTop_png_size, NULL, 0}, + {"scrollbar_arrowdown.png", scrollbar_arrowdown_png, scrollbar_arrowdown_png_size, NULL, 0}, + {"scrollbar_arrowup.png", scrollbar_arrowup_png, scrollbar_arrowup_png_size, NULL, 0}, + {"scrollbar_box.png", scrollbar_box_png, scrollbar_box_png_size, NULL, 0}, + {"sdcard.png", sdcard_png, sdcard_png_size, NULL, 0}, + {"sdcard_over.png", sdcard_over_png, sdcard_over_png_size, NULL, 0}, + {"searchIcon.png", searchIcon_png, searchIcon_png_size, NULL, 0}, + {"searchIcon_gray.png", searchIcon_gray_png, searchIcon_gray_png_size, NULL, 0}, + {"settings_background.png", settings_background_png, settings_background_png_size, NULL, 0}, + {"settings_button.png", settings_button_png, settings_button_png_size, NULL, 0}, + {"settings_button_over.png", settings_button_over_png, settings_button_over_png_size, NULL, 0}, + {"settings_title.png", settings_title_png, settings_title_png_size, NULL, 0}, + {"settings_title_over.png", settings_title_over_png, settings_title_over_png_size, NULL, 0}, + {"startgame_arrow_left.png", startgame_arrow_left_png, startgame_arrow_left_png_size, NULL, 0}, + {"startgame_arrow_right.png", startgame_arrow_right_png, startgame_arrow_right_png_size, NULL, 0}, + {"theme_box.png", theme_box_png, theme_box_png_size, NULL, 0}, + {"theme_dialogue_box.png", theme_dialogue_box_png, theme_dialogue_box_png_size, NULL, 0}, + {"tooltip_left.png", tooltip_left_png, tooltip_left_png_size, NULL, 0}, + {"tooltip_right.png", tooltip_right_png, tooltip_right_png_size, NULL, 0}, + {"tooltip_tile.png", tooltip_tile_png, tooltip_tile_png_size, NULL, 0}, + {"unlock.png", unlock_png, unlock_png_size, NULL, 0}, + {"unlock_gray.png", unlock_gray_png, unlock_gray_png_size, NULL, 0}, + {"wbackground.png", wbackground_png, wbackground_png_size, NULL, 0}, + {"wdialogue_box_startgame.png", wdialogue_box_startgame_png, wdialogue_box_startgame_png_size, NULL, 0}, + {"wheel.png", wheel_png, wheel_png_size, NULL, 0}, + {"wheelR.png", wheelR_png, wheelR_png_size, NULL, 0}, + {"wifi1.png", wifi1_png, wifi1_png_size, NULL, 0}, + {"wifi10.png", wifi10_png, wifi10_png_size, NULL, 0}, + {"wifi12.png", wifi12_png, wifi12_png_size, NULL, 0}, + {"wifi16.png", wifi16_png, wifi16_png_size, NULL, 0}, + {"wifi2.png", wifi2_png, wifi2_png_size, NULL, 0}, + {"wifi3.png", wifi3_png, wifi3_png_size, NULL, 0}, + {"wifi32.png", wifi32_png, wifi32_png_size, NULL, 0}, + {"wifi4.png", wifi4_png, wifi4_png_size, NULL, 0}, + {"wifi6.png", wifi6_png, wifi6_png_size, NULL, 0}, + {"wifi8.png", wifi8_png, wifi8_png_size, NULL, 0}, + {"wifi_btn.png", wifi_btn_png, wifi_btn_png_size, NULL, 0}, + {"wiimote.png", wiimote_png, wiimote_png_size, NULL, 0}, + {"wiimote1.png", wiimote1_png, wiimote1_png_size, NULL, 0}, + {"wiimote2.png", wiimote2_png, wiimote2_png_size, NULL, 0}, + {"wiimote3.png", wiimote3_png, wiimote3_png_size, NULL, 0}, + {"wiimote4.png", wiimote4_png, wiimote4_png_size, NULL, 0}, + {"wiimote_poweroff.png", wiimote_poweroff_png, wiimote_poweroff_png_size, NULL, 0}, + {"wiimote_poweroff_over.png", wiimote_poweroff_over_png, wiimote_poweroff_over_png_size, NULL, 0}, + {"wiispeak.png", wiispeak_png, wiispeak_png_size, NULL, 0}, + {"wiispeakR.png", wiispeakR_png, wiispeakR_png_size, NULL, 0}, + {"zapper.png", zapper_png, zapper_png_size, NULL, 0}, + {"zapperR.png", zapperR_png, zapperR_png_size, NULL, 0}, + {"bg_music.ogg", bg_music_ogg, bg_music_ogg_size, NULL, 0}, + {"button_click.wav", button_click_wav, button_click_wav_size, NULL, 0}, + {"button_click2.wav", button_click2_wav, button_click2_wav_size, NULL, 0}, + {"button_over.wav", button_over_wav, button_over_wav_size, NULL, 0}, + {"credits_music.ogg", credits_music_ogg, credits_music_ogg_size, NULL, 0}, + {"gc_banner.ogg", gc_banner_ogg, gc_banner_ogg_size, NULL, 0}, + {"menuin.ogg", menuin_ogg, menuin_ogg_size, NULL, 0}, + {"menuout.ogg", menuout_ogg, menuout_ogg_size, NULL, 0}, + {"success.ogg", success_ogg, success_ogg_size, NULL, 0}, + {"clock.ttf", clock_ttf, clock_ttf_size, NULL, 0}, + {"font.ttf", font_ttf, font_ttf_size, NULL, 0}, + {"app_booter.bin", app_booter_bin, app_booter_bin_size, NULL, 0}, + {"custom_banner.bnr", custom_banner_bnr, custom_banner_bnr_size, NULL, 0}, + {"stub.bin", stub_bin, stub_bin_size, NULL, 0}, + {"listBackground.png", NULL, 0, NULL, 0}, // Optional + {"carouselBackground.png", NULL, 0, NULL, 0}, // Optional + {"gridBackground.png", NULL, 0, NULL, 0}, // Optional + {NULL, NULL, 0, NULL, 0} +}; + +#endif diff --git a/source/themes/gettheme.c b/source/themes/gettheme.c new file mode 100644 index 0000000..e89ce71 --- /dev/null +++ b/source/themes/gettheme.c @@ -0,0 +1,280 @@ +#include +#include +#include +#include +#include + +enum +{ + ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE +}; + +typedef struct _MSG +{ + u32 id; + char* msgstr; + struct _MSG *next; +} MSG; +static MSG *baseMSG=0; + + +#define HASHWORDBITS 32 + +/* Defines the so called `hashpjw' function by P.J. Weinberger + [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, + 1986, 1987 Bell Telephone Laboratories, Inc.] */ +static inline u32 hash_string (const char *str_param) +{ + u32 hval, g; + const char *str = str_param; + + /* Compute the hash value for the given string. */ + hval = 0; + while (*str != '\0') + { + hval <<= 4; + hval += (u8) *str++; + g = hval & ((u32) 0xf << (HASHWORDBITS - 4)); + if (g != 0) + { + hval ^= g >> (HASHWORDBITS - 8); + hval ^= g; + } + } + return hval; +} + + +static MSG *findMSG(u32 id) +{ + MSG *msg; + for(msg=baseMSG; msg; msg=msg->next) + { + if(msg->id == id) + return msg; + } + return NULL; +} + +static MSG *setMSG(const char *msgid, const char *msgstr) +{ + u32 id = hash_string(msgid); + MSG *msg = findMSG(id); + if(!msg) + { + msg = (MSG *)malloc(sizeof(MSG)); + msg->id = id; + msg->msgstr = NULL; + msg->next = baseMSG; + baseMSG = msg; + } + if(msg) + { + if(msgstr) + { + if(msg->msgstr) free(msg->msgstr); + msg->msgstr = strdup(msgstr); + } + return msg; + } + return NULL; +} + +static inline void ClearPrefixes(char * msg) +{ + if(!msg) + return; + + const char * ptr = msg; + + int i = 0; + + while(ptr[0] != '\0') + { + if(ptr[0] == '\\' && (ptr[1] == '\\' || ptr[1] == '"')) + { + ++ptr; + } + + msg[i] = ptr[0]; + + ++i; + ++ptr; + } + + msg[i] = '\0'; +} + +void ThemeCleanUp(void) +{ + while(baseMSG) + { + MSG *nextMsg =baseMSG->next; + free(baseMSG->msgstr); + free(baseMSG); + baseMSG = nextMsg; + } +} + +bool LoadTheme(const char* themeFile) +{ + FILE *f; + char line[200]; + char *lastID=NULL; + + ThemeCleanUp(); + f = fopen(themeFile, "r"); + if(!f) + return false; + + while (fgets(line, sizeof(line), f)) + { + // lines starting with # are comments + if (line[0] == '#') + continue; + else if (strncmp(line, "msgid \"", 7) == 0) + { + char *msgid, *end; + if(lastID) { free(lastID); lastID=NULL;} + msgid = &line[7]; + end = strrchr(msgid, '"'); + if(end && end-msgid>1) + { + *end = 0; + ClearPrefixes(msgid); + lastID = strdup(msgid); + } + } + else if (strncmp(line, "msgstr \"", 8) == 0) + { + char *msgstr, *end; + + if(lastID == NULL) + continue; + + msgstr = &line[8]; + end = strrchr(msgstr, '"'); + if(end && end-msgstr>1) + { + *end = 0; + ClearPrefixes(msgstr); + setMSG(lastID, msgstr); + } + free(lastID); + lastID=NULL; + } + } + + fclose(f); + return true; +} + +int getThemeInt(const char *msgid) +{ + MSG *msg = findMSG(hash_string(msgid)); + if(msg) return atoi(msg->msgstr); + return atoi(msgid); +} + +float getThemeFloat(const char *msgid) +{ + MSG *msg = findMSG(hash_string(msgid)); + if(msg) return atof(msg->msgstr); + return atof(msgid); +} + +int getThemeAlignment(const char *msgid) +{ + MSG *msg = findMSG(hash_string(msgid)); + + const char * string = msgid; + if(msg) + string = msg->msgstr; + + while(*string == ' ') string++; + + if(strncasecmp(string, "left", strlen("left")) == 0) + return ALIGN_LEFT; + + else if(strncasecmp(string, "right", strlen("right")) == 0) + return ALIGN_RIGHT; + + else if(strncasecmp(string, "center", strlen("center")) == 0) + return ALIGN_CENTER; + + else if(strncasecmp(string, "top", strlen("top")) == 0) + return ALIGN_TOP; + + else if(strncasecmp(string, "bottom", strlen("bottom")) == 0) + return ALIGN_BOTTOM; + + else if(strncasecmp(string, "middle", strlen("middle")) == 0) + return ALIGN_MIDDLE; + + return -1; +} + +GXColor getThemeColor(const char *msgid) +{ + MSG *msg = findMSG(hash_string(msgid)); + + const char * string = msgid; + if(msg) + string = msg->msgstr; + + GXColor color = (GXColor) {0, 0, 0, 0}; + + while(*string == ' ') string++; + + while(*string != '\0') + { + if(*string == 'r') + { + string++; + while(*string == ' ' || *string == '=' || *string == ',') string++; + + if(*string == '\0') + break; + + color.r = atoi(string) & 0xFF; + } + else if(*string == 'g') + { + string++; + while(*string == ' ' || *string == '=' || *string == ',') string++; + + if(*string == '\0') + break; + + color.g = atoi(string) & 0xFF; + } + else if(*string == 'b') + { + string++; + while(*string == ' ' || *string == '=' || *string == ',') string++; + + if(*string == '\0') + break; + + color.b = atoi(string) & 0xFF; + } + else if(*string == 'a') + { + string++; + while(*string == ' ' || *string == '=' || *string == ',') string++; + + if(*string == '\0') + break; + + color.a = atoi(string) & 0xFF; + } + else if(*string == '-') + { + break; + } + + ++string; + } + + return color; +} diff --git a/source/themes/gettheme.h b/source/themes/gettheme.h new file mode 100644 index 0000000..0f27f8d --- /dev/null +++ b/source/themes/gettheme.h @@ -0,0 +1,27 @@ +#ifndef GETTHEME_H_ +#define GETTHEME_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +int getThemeInt(const char *msgid); +float getThemeFloat(const char *msgid); +int getThemeAlignment(const char *msgid); +GXColor getThemeColor(const char *msgid); +bool LoadTheme(const char* themeFile); +void ThemeCleanUp(void); + +#define thInt(s) getThemeInt(s) +#define thFloat(s) getThemeFloat(s) +#define thAlign(s) getThemeAlignment(s) +#define thColor(s) getThemeColor(s) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/usbloader/AlternateDOLOffsets.cpp b/source/usbloader/AlternateDOLOffsets.cpp new file mode 100644 index 0000000..fed6bc5 --- /dev/null +++ b/source/usbloader/AlternateDOLOffsets.cpp @@ -0,0 +1,254 @@ +#include "prompts/PromptWindows.h" +#include "language/gettext.h" +#include "gecko.h" + +static int defaultDolSelected = 0; + +void defaultDolPrompt(const char *gameid) +{ + char id[7]; + snprintf(id, sizeof(id), gameid); + defaultDolSelected = 0; + + //Metroid Prime Trilogy + if (strcmp(id, "R3ME01") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, "Metroid Prime", "Metroid Prime 2", "Metroid Prime 3", tr("Pick from a list")); + if(choice == 1) + defaultDolSelected = 780; + + else if(choice == 2) + defaultDolSelected = 781; + + else if(choice == 3) + defaultDolSelected = 782; + } + //Metroid Prime Trilogy + else if (strcmp(id, "R3MP01") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, "Metroid Prime", "Metroid Prime 2", "Metroid Prime 3", tr("Pick from a list")); + if(choice == 1) + defaultDolSelected = 782; + + else if(choice == 2) + defaultDolSelected = 783; + + else if(choice == 3) + defaultDolSelected = 784; + } +} + +int defaultAltDol(const char *gameid) +{ + //! If one dol was selected in the defaultDolPrompt on game start + //! return that dol offset + if(defaultDolSelected) + return defaultDolSelected; + + char id[7]; + snprintf(id, sizeof(id), gameid); + + //Boogie + if (strcmp(id, "RBOP69") == 0) return 675;//previous value was 657 + if (strcmp(id, "RBOE69") == 0) return 675;//starstremr + + //Fifa 08 + if (strcmp(id, "RF8E69") == 0) return 439;//from isostar + if (strcmp(id, "RF8P69") == 0) return 463;//from isostar + if (strcmp(id, "RF8X69") == 0) return 464;//from isostar + + //Madden NFL07 + if (strcmp(id, "RMDP69") == 0) return 39;//from isostar + + //Madden NFL08 + if (strcmp(id, "RNFP69") == 0) return 1079;//from isostar + + //Medal of Honor: Heroes 2 + if (strcmp(id, "RM2X69") == 0) return 601;//dj_skual + if (strcmp(id, "RM2P69") == 0) return 517;//MZottel + if (strcmp(id, "RM2E69") == 0) return 492;//Old8oy + + //Mortal Kombat + if (strcmp(id, "RKMP5D") == 0) return 290;//from isostar + if (strcmp(id, "RKME5D") == 0) return 290;//starstremr + + //NBA 08 + if (strcmp(id, "RNBX69") == 0) return 964;//from isostar + + //Pangya! Golf with Style + if (strcmp(id, "RPYP9B") == 0) return 12490;//from isostar + + //Redsteel + if (strncmp(id, "RED", 3) == 0) return 1957;//from isostar + + //SSX + if (strcmp(id, "RSXP69") == 0) return 377;//previous value was 337 + if (strcmp(id, "RSXE69") == 0) return 377;//previous value was 337 + + //Madden NFL 07 + if (strcmp(id, "RMDE69") == 0) return 39; //from TwEbErIs + + //Madden NFL 08 + if (strcmp(id, "RNFE69") == 0) return 1079; //from TwEbErIs + + //Super Swing Golf + if (strcmp(id, "RPYE9B") == 0) return 10617; //from TwEbErIs + + //NBA Live 08 + if (strcmp(id, "RNBE69") == 0) return 936; //from TwEbErIs + + return 0; //none found +} + +int autoSelectDolPrompt(const char *gameid) +{ + char id[7]; + snprintf(id, sizeof(id), gameid); + + //Indiana Jones and the Staff of Kings (Fate of Atlantis) + if (strcmp(id, "RJ8E64") == 0 || strcmp(id, "RJ8P64") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, "Fate of Atlantis", tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 8; //from starstremr + else if(choice == 0) + return 0; + } + //Metal Slug Anthology (Metal Slug 6) + else if (strcmp(id, "RMLEH4") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, "Metal Slug 6", tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 54; + else if(choice == 0) + return 0; + } + //Metal Slug Anthology (Metal Slug 6) + else if (strcmp(id, "RMLP7U") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, "Metal Slug 6", tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 56; + else if(choice == 0) + return 0; + } + //Rampage: Total Destruction (M1.dol=Rampage, jarvos.dol=Rampage World Tour) + else if (strcmp(id, "RPGP5D") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, "Rampage", "World Tour", tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 369; + + else if(choice == 2) + return 368; + + else if(choice == 0) + return 0; + } + //The House Of The Dead 2 & 3 Return (only to play 2) + else if (strcmp(id, "RHDE8P") == 0 || strcmp(id, "RHDP8P") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, "HotD 2", tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 149; + else if(choice == 2) + return 0; + else if(choice == 0) + return 0; + } + //Grand Slam Tennis + else if (strcmp(id, "R5TP69") == 0 || strcmp(id, "R5TE69") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, tr("Motion+ Video"), tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 1493;//from isostar + else if(choice == 0) + return 0; + } + //Medal of Honor Heroes + else if (strcmp(id, "RMZX69") == 0 || strcmp(id, "RMZP69") == 0 || strcmp(id, "RMZE69") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, tr("Motion+ Video"), tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 492;//from isostar + else if(choice == 0) + return 0; + } + //Tiger Woods 10 + else if(strcmp(id, "R9OP69") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, tr("Motion+ Video"), tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 1991;//from isostar + else if(choice == 0) + return 0; + } + //Tiger Woods 10 + else if(strcmp(id, "R9OE69") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, tr("Motion+ Video"), tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 1973;//starstremr + else if(choice == 0) + return 0; + } + //The Legend of Zelda - Skyward Sword + else if (strcmp(id, "SOUE01") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, tr("Motion+ Video"), tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 836;//from cheatfreak47 + } + //The Legend of Zelda - Skyward Sword + else if (strcmp(id, "SOUP01") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, tr("Motion+ Video"), tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 974;//from Cyan + } + //Virtual Tennis 2009 + else if (strcmp(id, "RVUP8P") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, tr("Motion+ Video"), tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 16426;//from isostar + } + //Virtual Tennis 2009 + else if (strcmp(id, "RVUE8P") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, tr("Motion+ Video"), tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 16405;//from isostar + else if(choice == 0) + return 0; + } + //Wii Sports Resort + else if (strcmp(id, "RZTP01") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, tr("Motion+ Video"), tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 952;//from isostar + else if(choice == 0) + return 0; + } + //Wii Sports Resort + else if (strcmp(id, "RZTE01") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, tr("Motion+ Video"), tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 674;//from starstremr + else if(choice == 0) + return 0; + } + //Red Steel 2 + else if (strcmp(id, "RD2X41") == 0) + { + int choice = WindowPrompt(tr( "Select a DOL" ), 0, tr("Motion+ Video"), tr("Pick from a list"), tr( "Cancel" )); + if(choice == 1) + return 301;//from Cyan + else if(choice == 0) + return 0; + } + + return -1; +} diff --git a/source/usbloader/AlternateDOLOffsets.h b/source/usbloader/AlternateDOLOffsets.h new file mode 100644 index 0000000..a56f514 --- /dev/null +++ b/source/usbloader/AlternateDOLOffsets.h @@ -0,0 +1,8 @@ +#ifndef ALTERNATEDOLOFFSETS_H_ +#define ALTERNATEDOLOFFSETS_H_ + +int defaultAltDol(const char *id); +int defaultDolPrompt(const char *id); +int autoSelectDolPrompt(const char *id); + +#endif diff --git a/source/usbloader/GameBooter.cpp b/source/usbloader/GameBooter.cpp new file mode 100644 index 0000000..a1203e4 --- /dev/null +++ b/source/usbloader/GameBooter.cpp @@ -0,0 +1,1917 @@ +/**************************************************************************** + * Copyright (C) 2012-2015 Cyan + * Copyright (C) 2011 Dimok + * + * 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 "menu/menus.h" +#include "menu/WDMMenu.hpp" +#include "mload/mload.h" +#include "mload/mload_modules.h" +#include "system/IosLoader.h" +#include "libs/libruntimeiospatch/runtimeiospatch.h" +#include "Controls/DeviceHandler.hpp" +#include "Channels/channels.h" +#include "usbloader/disc.h" +#include "usbloader/apploader.h" +#include "usbloader/usbstorage2.h" +#include "usbloader/wdvd.h" +#include "usbloader/GameList.h" +#include "settings/CGameSettings.h" +#include "settings/SettingsEnums.h" +#include "usbloader/frag.h" +#include "usbloader/wbfs.h" +#include "usbloader/playlog.h" +#include "usbloader/MountGamePartition.h" +#include "usbloader/AlternateDOLOffsets.h" +#include "GameCube/GCGames.h" +#include "settings/newtitles.h" +#include "network/Wiinnertag.h" +#include "patches/patchcode.h" +#include "patches/gamepatches.h" +#include "patches/wip.h" +#include "patches/bca.h" +#include "banner/OpeningBNR.hpp" +#include "wad/nandtitle.h" +#include "menu/menus.h" +#include "memory/memory.h" +#include "utils/StringTools.h" +#include "homebrewboot/BootHomebrew.h" +#include "GameBooter.hpp" +#include "NandEmu.h" +#include "SavePath.h" +#include "sys.h" +#include "FileOperations/fileops.h" +#include "prompts/ProgressWindow.h" +#include "neek.hpp" + +//appentrypoint has to be global because of asm +u32 AppEntrypoint = 0; + +extern bool isWiiVC; // in sys.cpp +extern u32 hdd_sector_size[2]; +extern "C" +{ + syssram* __SYS_LockSram(); + u32 __SYS_UnlockSram(u32 write); + u32 __SYS_SyncSram(void); + extern void __exception_closeall(); +} + +int GameBooter::BootGCMode(struct discHdr *gameHdr) +{ + // check the settings + GameCFG * game_cfg = GameSettings.GetGameCFG(gameHdr->id); + u8 GCMode = game_cfg->GameCubeMode == INHERIT ? Settings.GameCubeMode : game_cfg->GameCubeMode; + + // Devolution + if(GCMode == GC_MODE_DEVOLUTION) + return BootDevolution(gameHdr); + + // Nintendont + if(GCMode == GC_MODE_NINTENDONT) + return BootNintendont(gameHdr); + + // DIOS MIOS (Lite) and QuadForce + int currentMIOS = IosLoader::GetMIOSInfo(); + if(currentMIOS == DIOS_MIOS || currentMIOS == DIOS_MIOS_LITE || currentMIOS == QUADFORCE || currentMIOS == QUADFORCE_USB) + return BootDIOSMIOS(gameHdr); + + // MIOS or Wiigator cMIOS + if(gameHdr->type == TYPE_GAME_GC_DISC) + { + ExitApp(); + gprintf("\nLoading BC for GameCube"); + WII_Initialize(); + return WII_LaunchTitle(0x0000000100000100ULL); + } + + WindowPrompt(tr("Error:"), tr("You need to install an additional GameCube loader or select a different GameCube Mode to launch GameCube games from USB or SD card."), tr("OK")); + + return 0; +} + +u32 GameBooter::BootPartition(char * dolpath, u8 videoselected, u8 alternatedol, u32 alternatedoloffset) +{ + gprintf("booting partition IOS %u r%u\n", IOS_GetVersion(), IOS_GetRevision()); + entry_point p_entry; + s32 ret; + u64 offset; + + /* Find game partition offset */ + ret = Disc_FindPartition(&offset); + if (ret < 0) + return 0; + + /* Open specified partition */ + ret = WDVD_OpenPartition(offset); + if (ret < 0) + return 0; + + /* Setup low memory */ + Disc_SetLowMem(); + + /* Setup video mode */ + Disc_SelectVMode(videoselected, false, NULL, NULL); + + /* Run apploader */ + ret = Apploader_Run(&p_entry, dolpath, alternatedol, alternatedoloffset); + + if (ret < 0) + return 0; + + return (u32) p_entry; +} + +void GameBooter::SetupAltDOL(u8 * gameID, u8 &alternatedol, u32 &alternatedoloffset) +{ + if(alternatedol == ALT_DOL_ON_LAUNCH) + { + alternatedol = ALT_DOL_FROM_GAME; + alternatedoloffset = WDMMenu::GetAlternateDolOffset(); + } + else if(alternatedol == ALT_DOL_DEFAULT) + { + alternatedol = ALT_DOL_FROM_GAME; + alternatedoloffset = defaultAltDol((char *) gameID); + } + + if(alternatedol == ALT_DOL_FROM_GAME && alternatedoloffset == 0) + alternatedol = OFF; +} + +void GameBooter::SetupNandEmu(u8 NandEmuMode, const char *NandEmuPath, struct discHdr &gameHeader) +{ + if(NandEmuMode && strchr(NandEmuPath, '/')) + { + int partition = -1; + + //! Create save game path and title.tmd for not existing saves + CreateSavePath(&gameHeader, NandEmuPath); + + gprintf("Enabling %s Nand Emulation on: %s\n", NandEmuMode == 2 ? "Full" : "Partial" , NandEmuPath); + Set_FullMode(NandEmuMode == 2); + Set_Path(strchr(NandEmuPath, '/')); + + //! Unmount devices to flush data before activating NAND Emu + if(strncmp(NandEmuPath, "usb", 3) == 0) + { + //! Set which partition to use (USB only) + partition = atoi(NandEmuPath+3)-1; + Set_Partition(DeviceHandler::PartitionToPortPartition(partition)); + DeviceHandler::Instance()->UnMount(USB1 + partition); + } + else + DeviceHandler::Instance()->UnMountSD(); + + Enable_Emu(strncmp(NandEmuPath, "usb", 3) == 0 ? EMU_USB : EMU_SD); + + //! Mount USB to start game, SD is not required + if(strncmp(NandEmuPath, "usb", 3) == 0) + DeviceHandler::Instance()->Mount(USB1 + partition); + + } +} + +int GameBooter::SetupDisc(struct discHdr &gameHeader) +{ + if (gameHeader.type == TYPE_GAME_WII_DISC) + { + gprintf("\tloading DVD\n"); + return Disc_Open(); + } + + int ret = -1; + + if(IosLoader::IsWaninkokoIOS() && IOS_GetRevision() < 18) + { + gprintf("Disc_SetUSB..."); + ret = Disc_SetUSB(gameHeader.id); + gprintf("%d\n", ret); + if(ret < 0) return ret; + } + else + { + gprintf("Loading fragment list..."); + ret = get_frag_list(gameHeader.id); + gprintf("%d\n", ret); + if(ret < 0) return ret; + ret = set_frag_list(gameHeader.id); + if(ret < 0) return ret; + gprintf("\tUSB set to game\n"); + } + + gprintf("Disc_Open()..."); + ret = Disc_Open(); + gprintf("%d\n", ret); + + return ret; +} + +void GameBooter::ShutDownDevices(int gameUSBPort) +{ + gprintf("Shutting down devices...\n"); + //! Flush all caches and close up all devices + WBFS_CloseAll(); + DeviceHandler::DestroyInstance(); + + //! Shadow mload - Only needed on some games with Hermes v5.1 (Check is inside the function) + shadow_mload(); + + if(Settings.USBPort == 2) + //! Reset USB port because device handler changes it for cache flushing + USBStorage2_SetPort(gameUSBPort); + USBStorage2_Deinit(); + USB_Deinitialize(); +} + +int GameBooter::BootGame(struct discHdr *gameHdr) +{ + if(!gameHdr) + return -1; + + struct discHdr gameHeader; + memcpy(&gameHeader, gameHdr, sizeof(struct discHdr)); + + gprintf("\tBootGame: %.6s\n", gameHeader.id); + + if(Settings.Wiinnertag) + Wiinnertag::TagGame((const char *) gameHeader.id); + + if(gameHeader.type == TYPE_GAME_GC_IMG || gameHeader.type == TYPE_GAME_GC_DISC || gameHdr->type == TYPE_GAME_GC_EXTRACTED) + return BootGCMode(&gameHeader); + + //! Setup game configuration from game settings. If no game settings exist use global/default. + GameCFG * game_cfg = GameSettings.GetGameCFG(gameHeader.id); + u8 videoChoice = game_cfg->video == INHERIT ? Settings.videomode : game_cfg->video; + u8 videoPatchDolChoice = game_cfg->videoPatchDol == INHERIT ? Settings.videoPatchDol : game_cfg->videoPatchDol; + u8 patchFix480pChoice = game_cfg->patchFix480p == INHERIT ? Settings.patchFix480p : game_cfg->patchFix480p; + u8 aspectChoice = game_cfg->aspectratio == INHERIT ? Settings.GameAspectRatio : game_cfg->aspectratio; + u8 languageChoice = game_cfg->language == INHERIT ? Settings.language : game_cfg->language; + u8 ocarinaChoice = game_cfg->ocarina == INHERIT ? Settings.ocarina : game_cfg->ocarina; + u8 PrivServChoice = game_cfg->PrivateServer == INHERIT ? Settings.PrivateServer : game_cfg->PrivateServer; + u8 viChoice = game_cfg->vipatch == INHERIT ? Settings.videopatch : game_cfg->vipatch; + u8 sneekChoice = game_cfg->sneekVideoPatch == INHERIT ? Settings.sneekVideoPatch : game_cfg->sneekVideoPatch; + u8 iosChoice = game_cfg->ios == INHERIT ? Settings.cios : game_cfg->ios; + u8 countrystrings = game_cfg->patchcountrystrings == INHERIT ? Settings.patchcountrystrings : game_cfg->patchcountrystrings; + u8 alternatedol = game_cfg->loadalternatedol; + u32 alternatedoloffset = game_cfg->alternatedolstart; + u8 reloadblock = game_cfg->iosreloadblock == INHERIT ? Settings.BlockIOSReload : game_cfg->iosreloadblock; + u8 Hooktype = game_cfg->Hooktype == INHERIT ? Settings.Hooktype : game_cfg->Hooktype; + u8 WiirdDebugger = game_cfg->WiirdDebugger == INHERIT ? Settings.WiirdDebugger : game_cfg->WiirdDebugger; + u64 returnToChoice = strlen(Settings.returnTo) > 0 ? (game_cfg->returnTo ? NandTitles.FindU32(Settings.returnTo) : 0) : 0; + u8 NandEmuMode = OFF; + const char *NandEmuPath = game_cfg->NandEmuPath.size() == 0 ? Settings.NandEmuPath : game_cfg->NandEmuPath.c_str(); + if(gameHeader.type == TYPE_GAME_WII_IMG) + NandEmuMode = game_cfg->NandEmuMode == INHERIT ? Settings.NandEmuMode : game_cfg->NandEmuMode; + if(gameHeader.type == TYPE_GAME_EMUNANDCHAN) + { + NandEmuMode = game_cfg->NandEmuMode == INHERIT ? Settings.NandEmuChanMode : game_cfg->NandEmuMode; + NandEmuPath = game_cfg->NandEmuPath.size() == 0 ? Settings.NandEmuChanPath : game_cfg->NandEmuPath.c_str(); + } + + // boot neek for Wii games and EmuNAND channels only + if(NandEmuMode == EMUNAND_NEEK && (gameHeader.type == TYPE_GAME_WII_IMG || gameHeader.type == TYPE_GAME_EMUNANDCHAN)) + return BootNeek(&gameHeader); + + AppCleanUp(); + + gprintf("\tSettings.partition: %d\n", Settings.partition); + + s32 ret = -1; + + //! Remember game's USB port + int partition = gameList.GetPartitionNumber(gameHeader.id); + int usbport = DeviceHandler::PartitionToUSBPort(partition); + + //! Prepare alternate dol settings + SetupAltDOL(gameHeader.id, alternatedol, alternatedoloffset); + + //! Reload game settings cIOS for this game + if(iosChoice != IOS_GetVersion()) + { + gprintf("Reloading into game cIOS: %i...\n", iosChoice); + IosLoader::LoadGameCios(iosChoice); + if(MountGamePartition(false) < 0) + return -1; + } + + //! Modify Wii Message Board to display the game starting here (before Nand Emu) + if(Settings.PlaylogUpdate) + { + // enable isfs permission if using IOS+AHB or Hermes v4 + if(IOS_GetVersion() < 200 || (IosLoader::IsHermesIOS() && IOS_GetRevision() == 4)) + { + gprintf("Patching IOS%d...\n", IOS_GetVersion()); + if (IosPatch_RUNTIME(true, false, false, false, false) == ERROR_PATCH) + gprintf("Patching %sIOS%d failed!\n", IOS_GetVersion() >= 200 ? "c" : "", IOS_GetVersion()); + } + + BNRInstance::Instance()->Load(&gameHeader); + Playlog_Update((char *) gameHeader.id, BNRInstance::Instance()->GetIMETTitle(CONF_GetLanguage())); + } + + //! Load wip codes + load_wip_code(gameHeader.id); + + // force hooktype if not selected but Ocarina is enabled + if(ocarinaChoice && Hooktype == OFF) + Hooktype = 1; + + //! Load Ocarina codes + if (ocarinaChoice) + ocarina_load_code(Settings.Cheatcodespath, gameHeader.id); + + //! Load gameconfig.txt even if ocarina disabled + if(Hooktype) + LoadGameConfig(Settings.Cheatcodespath); + + //! Setup NAND emulation + SetupNandEmu(NandEmuMode, NandEmuPath, gameHeader); + + //! Setup disc stuff if we load a game + if(gameHeader.tid == 0) + { + //! Setup disc in cIOS and open it + ret = SetupDisc(gameHeader); + if (ret < 0) + Sys_BackToLoader(); + + //! Load BCA data for the game + gprintf("Loading BCA data..."); + ret = do_bca_code(Settings.BcaCodepath, gameHeader.id); + gprintf("%d\n", ret); + } + + if(IosLoader::IsHermesIOS(iosChoice)) + { + if(reloadblock == ON) + { + //! Setup IOS reload block + enable_ES_ioctlv_vector(); + if (gameList.GetGameFS(gameHeader.id) == PART_FS_WBFS) + mload_close(); + } + } + else if(IosLoader::IsD2X(iosChoice)) + { + // Open ES file descriptor for the d2x patches + static char es_fs[] ATTRIBUTE_ALIGN(32) = "/dev/es"; + int es_fd = IOS_Open(es_fs, 0); + if(es_fd >= 0) + { + // IOS Reload Block + if(reloadblock != OFF) { + BlockIOSReload(es_fd, iosChoice); + } + // Check if new patch method for return to works otherwise old method will be used + if(PatchNewReturnTo(es_fd, returnToChoice) >= 0) + returnToChoice = 0; // Patch successful, no need for old method + + // Close ES file descriptor + IOS_Close(es_fd); + } + } + + //! Now we can free up the memory used by the game/channel lists + gameList.clear(); + Channels::DestroyInstance(); + + //! Load main.dol or alternative dol into memory, start the game apploader and get game entrypoint + if(gameHeader.tid == 0) + { + gprintf("\tGame Boot\n"); + AppEntrypoint = BootPartition(Settings.dolpath, videoChoice, alternatedol, alternatedoloffset); + // Reading of game is done we can close devices now + ShutDownDevices(usbport); + } + else + { + //! shutdown now and avoid later crashs with free if memory gets overwritten by channel + ShutDownDevices(DeviceHandler::PartitionToUSBPort(std::max(atoi(NandEmuPath+3)-1, 0))); + gprintf("\tChannel Boot\n"); + /* Setup video mode */ + Disc_SelectVMode(videoChoice, false, NULL, NULL); + // Load dol + AppEntrypoint = Channels::LoadChannel(gameHeader.tid); + } + + //! No entrypoint found...back to HBC/SystemMenu + if(AppEntrypoint == 0) + { + gprintf("AppEntryPoint is 0, something went wrong\n"); + WDVD_ClosePartition(); + Sys_BackToLoader(); + } + + //! Do all the game patches + gprintf("Applying game patches...\n"); + + + //! Now this code block is responsible for the private server patch + //! and the gecko code handler loading + + //! If a server other than Wiimmfi is selected, do the normal patching + //! If Wiimmfi is selected for other games than MKWii, do normal patching as well + //! If Wiimmfi is selected for MKWii, skip normal patching (PRIVSERV_OFF) + //! and let the new code in do_new_wiimmfi() handle the complete server patch + + //! Also, the new Wiimmfi server patch should be loaded into memory after + //! the code handler and the cheat codes. + + if (PrivServChoice != PRIVSERV_WIIMMFI || memcmp(((void *)(0x80000000)), (char*)"RMC", 3) != 0) { + //! Either the server is not Wiimmfi, or, if it is Wiimmfi, the game isn't MKWii - patch the old way + gamepatches(videoChoice, videoPatchDolChoice, aspectChoice, languageChoice, countrystrings, viChoice, sneekChoice, Hooktype, returnToChoice, PrivServChoice); + } + else { + //! Wiimmfi patch for Mario Kart Wii - patch with PRIVSERV_OFF and handle all the patching within do_new_wiimmfi() + gamepatches(videoChoice, videoPatchDolChoice, aspectChoice, languageChoice, countrystrings, viChoice, sneekChoice, Hooktype, returnToChoice, PRIVSERV_OFF); + } + + + //! Load Code handler if needed + load_handler(Hooktype, WiirdDebugger, Settings.WiirdDebuggerPause); + + + //! Perform 480p fix if needed. + //! Needs to be done after the call to gamepatches(), after loading any code handler. + //! Can (and should) be done before Wiimmfi patching, can't be done in gamepatches() itself. + if(patchFix480pChoice) + PatchFix480p(); + + //! New Wiimmfi patch should be loaded last, after the codehandler, just before the call to the entry point + if (PrivServChoice == PRIVSERV_WIIMMFI && memcmp(((void *)(0x80000000)), (char*)"RMC", 3) == 0 ) { + // all the cool new Wiimmfi stuff: + switch(do_new_wiimmfi()) { + case 0: + gprintf("Wiimmfi patch for Mario Kart Wii successful.\n"); + break; + case -1: + gprintf("Could not determine game region for Wiimmfi patch - make sure the fourth char of the ID is one of [PEJK].\n"); + break; + case -2: + gprintf("This image is already patched for Wiimmfi, no need to do so again.\n"); + break; + } + } + + //! Jump to the entrypoint of the game - the last function of the USB Loader + gprintf("Jumping to game entrypoint: 0x%08X.\n", AppEntrypoint); + return Disc_JumpToEntrypoint(Hooktype, WDMMenu::GetDolParameter()); +} + +int GameBooter::BootDIOSMIOS(struct discHdr *gameHdr) +{ + const char *RealPath = GCGames::Instance()->GetPath((const char *) gameHdr->id); + + GameCFG * game_cfg = GameSettings.GetGameCFG(gameHdr->id); + s8 languageChoice = game_cfg->language == INHERIT ? Settings.language - 1 : game_cfg->language; + u8 ocarinaChoice = game_cfg->ocarina == INHERIT ? Settings.ocarina : game_cfg->ocarina; + u8 multiDiscChoice = Settings.MultiDiscPrompt; + u8 dmlVideoChoice = game_cfg->DMLVideo == INHERIT ? Settings.DMLVideo : game_cfg->DMLVideo; + u8 dmlProgressivePatch = game_cfg->DMLProgPatch == INHERIT ? Settings.DMLProgPatch : game_cfg->DMLProgPatch; + u8 dmlNMMChoice = game_cfg->DMLNMM == INHERIT ? Settings.DMLNMM : game_cfg->DMLNMM; + u8 dmlActivityLEDChoice = game_cfg->DMLActivityLED == INHERIT ? Settings.DMLActivityLED : game_cfg->DMLActivityLED; + u8 dmlPADHookChoice = game_cfg->DMLPADHOOK == INHERIT ? Settings.DMLPADHOOK : game_cfg->DMLPADHOOK; + u8 dmlNoDisc2Choice = game_cfg->DMLNoDisc2 == INHERIT ? Settings.DMLNoDisc2 : game_cfg->DMLNoDisc2; + u8 dmlWidescreenChoice = game_cfg->DMLWidescreen == INHERIT ? Settings.DMLWidescreen : game_cfg->DMLWidescreen; + u8 dmlScreenshotChoice = game_cfg->DMLScreenshot == INHERIT ? Settings.DMLScreenshot : game_cfg->DMLScreenshot; + u8 dmlJPNPatchChoice = game_cfg->DMLJPNPatch == INHERIT ? Settings.DMLJPNPatch : game_cfg->DMLJPNPatch; + u8 dmlDebugChoice = game_cfg->DMLDebug == INHERIT ? Settings.DMLDebug : game_cfg->DMLDebug; + + int currentMIOS = IosLoader::GetMIOSInfo(); + char LoaderName[15]; + if(currentMIOS == DIOS_MIOS) + snprintf(LoaderName, sizeof(LoaderName), "DIOS MIOS"); + else if(currentMIOS == DIOS_MIOS_LITE) + snprintf(LoaderName, sizeof(LoaderName), "DIOS MIOS Lite"); + else if(currentMIOS == QUADFORCE) + snprintf(LoaderName, sizeof(LoaderName), "QuadForce"); + else if(currentMIOS == QUADFORCE_USB) + snprintf(LoaderName, sizeof(LoaderName), "QuadForce_USB"); + + // DIOS MIOS + if(currentMIOS == DIOS_MIOS || currentMIOS == QUADFORCE_USB) + { + // Check Main GameCube Path location + if(strncmp(Settings.GameCubePath, "sd", 2) == 0 || strncmp(DeviceHandler::PathToFSName(Settings.GameCubePath), "FAT", 3) != 0) + { + WindowPrompt(tr("Error:"), fmt(tr("To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition."),LoaderName), tr("OK")); + return -1; + } + + // Check current game location + if(strncmp(RealPath, "sd", 2) == 0) + { + WindowPrompt(tr("The game is on SD Card."), fmt(tr("To run GameCube games with %s you need to place them on an USB FAT32 partition."),LoaderName), tr("OK")); + // Todo: Add here copySD2USB. + return -1; + } + + // Check if the partition is the first primary partition on the drive + bool found = false; + int USB_partNum = DeviceHandler::PathToDriveType(Settings.GameCubePath)-USB1; + int USBport_partNum = DeviceHandler::PartitionToPortPartition(USB_partNum); + int usbport = DeviceHandler::PartitionToUSBPort(USB_partNum); + PartitionHandle * usbHandle = DeviceHandler::Instance()->GetUSBHandleFromPartition(USB_partNum); + for(int partition = 0 ; partition <= USBport_partNum; partition++) + { + if(usbHandle->GetPartitionTableType(partition) != MBR) + continue; + + if(partition == USBport_partNum) + { + found = true; + break; + } + } + if(!found) + { + WindowPrompt(tr("Error:"), fmt(tr("To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary partition of the Hard Drive."),LoaderName), tr("OK")); + return -1; + } + + // Check HDD sector size. Only 512 bytes/sector is supported by DIOS MIOS + if(hdd_sector_size[usbport] != BYTES_PER_SECTOR) + { + WindowPrompt(tr("Error:"), fmt(tr("To run GameCube games with %s you need to use a 512 bytes/sector Hard Drive."),LoaderName), tr("OK")); + return -1; + } + + if(usbHandle->GetPartitionClusterSize(usbHandle->GetLBAStart(USBport_partNum)) > 32768) + { + WindowPrompt(tr("Error:"), fmt(tr("To run GameCube games with %s you need to use a partition with 32k bytes/cluster or less."),LoaderName), tr("OK")); + return -1; + } + } + + // DIOS MIOS Lite + else if(currentMIOS == DIOS_MIOS_LITE || currentMIOS == QUADFORCE) + { + if(((gameHdr->type == TYPE_GAME_GC_IMG) || (gameHdr->type == TYPE_GAME_GC_EXTRACTED)) && strncmp(RealPath, "usb", 3) == 0) + { + if(!GCGames::Instance()->CopyUSB2SD(gameHdr)) + return -1; + + RealPath = GCGames::Instance()->GetPath((const char *) gameHdr->id); + } + } + + + // Check DIOS MIOS config for specific versions + if(currentMIOS != QUADFORCE && currentMIOS != QUADFORCE_USB) + { + if(IosLoader::GetDMLVersion() < DML_VERSION_DML_1_2) + { + WindowPrompt(tr("Error:"), tr("You need to install DIOS MIOS Lite v1.2 or a newer version."), tr("OK")); + return -1; + } + if(dmlWidescreenChoice && IosLoader::GetDMLVersion() < DML_VERSION_DM_2_1) // DML Force Widescreen setting : added in DM v2.1+, config v1. + { + if(Settings.DMLWidescreen) // Display the warning only if set as Global setting. Individual game setting is not displayed. + WindowPrompt(tr("Warning:"), tr("The Force Widescreen setting requires DIOS MIOS v2.1 or more. This setting will be ignored."), tr("OK")); + dmlWidescreenChoice = OFF; + } + if(dmlNoDisc2Choice && (IosLoader::GetDMLVersion() < DML_VERSION_DM_2_2_2 || IosLoader::GetDMLVersion() > DML_VERSION_DML_2_2_1)) // DML NoDisc+ setting : Added in DM 2.2 upate 2, config v2, removed in DM(L) v2.3 + { + if(Settings.DMLNoDisc2) // Display the warning only if set as Global setting. Individual game setting is not displayed. + WindowPrompt(tr("Warning:"), tr("The No Disc+ setting requires DIOS MIOS 2.2 update2. This setting will be ignored."), tr("OK")); + dmlNoDisc2Choice = false; + } + } + + // Check Ocarina and cheat file location. the .gct file need to be located on the same partition than the game. + if(gameHdr->type != TYPE_GAME_GC_DISC && ocarinaChoice && strcmp(DeviceHandler::GetDevicePrefix(RealPath), DeviceHandler::GetDevicePrefix(Settings.Cheatcodespath)) != 0) + { + char path[255], destPath[255]; + int res = -1; + snprintf(path, sizeof(path), "%s%.6s.gct", Settings.Cheatcodespath, (char *)gameHdr->id); + snprintf(destPath, sizeof(destPath), "%s:/DMLTemp.gct", DeviceHandler::GetDevicePrefix(RealPath)); + + gprintf("DML: Copying %s to %s \n", path, destPath); + res = CopyFile(path, destPath); + if(res < 0) + { + gprintf("DML: Couldn't copy the file. ret %d. Ocarina Disabled\n", res); + RemoveFile(destPath); + ocarinaChoice = false; + } + } + + // Check if game has multi Discs + bool bootDisc2 = false; + if(multiDiscChoice && gameHdr->type != TYPE_GAME_GC_DISC && gameHdr->disc_no == 0 && currentMIOS != QUADFORCE) + { + char disc2Path[255]; + snprintf(disc2Path, sizeof(disc2Path), "%s", RealPath); + char *pathPtr = strrchr(disc2Path, '/'); + if(pathPtr) *pathPtr = 0; + snprintf(disc2Path, sizeof(disc2Path), "%s/disc2.iso", disc2Path); + if(CheckFile(disc2Path)) + { + int choice = WindowPrompt(gameHdr->title, tr("This game has multiple discs. Please select the disc to launch."), tr("Disc 1"), tr("Disc 2"), tr("Cancel")); + if(choice == 0) + return -1; + else if(choice == 2) + bootDisc2 = true; + } + } + + const char *gcPath = strchr(RealPath, '/'); + if(!gcPath) gcPath = ""; + + char gamePath[255]; + snprintf(gamePath, sizeof(gamePath), "%s", gcPath); + + if(bootDisc2) + { + char *pathPtr = strrchr(gamePath, '/'); + if(pathPtr) *pathPtr = 0; + snprintf(gamePath, sizeof(gamePath), "%s/disc2.iso", gamePath); + } + + ExitApp(); + + // Game ID + memcpy((u8 *)Disc_ID, gameHdr->id, 6); + DCFlushRange((u8 *)Disc_ID, 6); + + // *(vu32*)0xCC003024 |= 7; // DML 1.1- only? + + DML_CFG *dml_config = (DML_CFG *) DML_CONFIG_ADDRESS; + memset(dml_config, 0, sizeof(DML_CFG)); + + // Magic and version for DML + dml_config->Magicbytes = DML_MAGIC; + dml_config->Version = IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_2 ? 0x00000002 : 0x00000001; + + // Select disc source + if((gameHdr->type == TYPE_GAME_GC_IMG) || (gameHdr->type == TYPE_GAME_GC_EXTRACTED)) + { + dml_config->Config |= DML_CFG_GAME_PATH; + strncpy(dml_config->GamePath, gamePath, sizeof(dml_config->GamePath)); + // Extended NoDisc patch + if(dmlNoDisc2Choice && IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_2_2 && IosLoader::GetDMLVersion() < DML_VERSION_DML_2_3m) + dml_config->Config |= DML_CFG_NODISC2; // used by v2.2 update2 as an Extended NoDisc patching + + gprintf("DML: Loading game %s\n", dml_config->GamePath); + } + else + { + dml_config->Config |= DML_CFG_BOOT_DISC; + } + + // setup cheat and path + if(ocarinaChoice) + { + // Check if the .gct folder is on the same partition than the game, if not load the temporary .gct file. + if(strcmp(DeviceHandler::GetDevicePrefix(RealPath), DeviceHandler::GetDevicePrefix(Settings.Cheatcodespath)) == 0) + { + const char *CheatPath = strchr(Settings.Cheatcodespath, '/'); + if(!CheatPath) CheatPath = ""; + snprintf(dml_config->CheatPath, sizeof(dml_config->CheatPath), "%s%.6s.gct", CheatPath, (char *)gameHdr->id); + } + else if(gameHdr->type != TYPE_GAME_GC_DISC) + { + snprintf(dml_config->CheatPath, sizeof(dml_config->CheatPath), "DMLTemp.gct"); + } + + dml_config->Config |= DML_CFG_CHEATS | DML_CFG_CHEAT_PATH; + gprintf("DML: Loading cheat %s\n", dml_config->CheatPath); + } + + // other DML configs + if(dmlPADHookChoice) + dml_config->Config |= DML_CFG_PADHOOK; + if(dmlActivityLEDChoice) + dml_config->Config |= DML_CFG_ACTIVITY_LED; + if(dmlNMMChoice) + dml_config->Config |= dmlNMMChoice == ON ? DML_CFG_NMM : DML_CFG_NMM_DEBUG; + if(dmlDebugChoice) + dml_config->Config |= dmlDebugChoice == ON ? DML_CFG_DEBUGGER : DML_CFG_DEBUGGER | DML_CFG_DEBUGWAIT; + if(dmlWidescreenChoice) + dml_config->Config |= DML_CFG_FORCE_WIDE; + if(dmlScreenshotChoice) + { + dml_config->Config |= DML_CFG_SCREENSHOT; + dml_config->Config |= DML_CFG_PADHOOK; + } + if(bootDisc2 && IosLoader::GetDMLVersion() >= DML_VERSION_DM_2_6_0) + dml_config->Config |= DML_CFG_BOOT_DISC2; + + + // Setup Video Mode + if(dmlVideoChoice == DML_VIDEO_NONE) // No video mode + { + dml_config->VideoMode = DML_VID_NONE; + } + else + { + if(dmlVideoChoice == DML_VIDEO_AUTO) // Auto select video mode + { + dml_config->VideoMode = DML_VID_DML_AUTO; + Disc_SelectVMode(VIDEO_MODE_DISCDEFAULT, false, NULL, NULL); + } + else // Force user choice + { + Disc_SelectVMode(dmlVideoChoice-1, false, &dml_config->VideoMode, NULL); + if(!(dml_config->VideoMode & DML_VID_DML_AUTO)) + dml_config->VideoMode |= DML_VID_FORCE; + } + Disc_SetVMode(); + } + + if(dmlProgressivePatch) + dml_config->VideoMode |= DML_VID_PROG_PATCH; + + + DCFlushRange(dml_config, sizeof(DML_CFG)); + memcpy((u8*)DML_CONFIG_ADDRESS_V1_2, dml_config, sizeof(DML_CFG)); + DCFlushRange((u8*)DML_CONFIG_ADDRESS_V1_2, sizeof(DML_CFG)); + + // print the config set for DML + gprintf("DML: setup configuration 0x%X\n", dml_config->Config); + gprintf("DML: setup video mode 0x%X\n", dml_config->VideoMode); + + // Set Sram flags + bool progressive = (dml_config->VideoMode & DML_VID_FORCE_PROG) || (dml_config->VideoMode & DML_VID_PROG_PATCH); + PatchSram(languageChoice, true, progressive); + + /* NTSC-J Patch */ // Thanks to Fix94 + u8 *diskid = (u8 *) Disc_ID; + if(dmlJPNPatchChoice && diskid[3] == 'J') + *HW_PPCSPEED = 0x0002A9E0; + + gprintf("\nLoading BC for GameCube\n"); + WII_Initialize(); + return WII_LaunchTitle(0x0000000100000100ULL); +} + +int GameBooter::BootDevolution(struct discHdr *gameHdr) +{ + const char *RealPath = GCGames::Instance()->GetPath((const char *) gameHdr->id); + const char *LoaderName = "Devolution"; + + GameCFG * game_cfg = GameSettings.GetGameCFG(gameHdr->id); + s8 languageChoice = game_cfg->language == INHERIT ? Settings.language -1 : game_cfg->language; + u8 devoMCEmulation = game_cfg->DEVOMCEmulation == INHERIT ? Settings.DEVOMCEmulation : game_cfg->DEVOMCEmulation; + u8 devoActivityLEDChoice = game_cfg->DEVOActivityLED == INHERIT ? Settings.DEVOActivityLED : game_cfg->DEVOActivityLED; + u8 devoWidescreenChoice = game_cfg->DEVOWidescreen == INHERIT ? Settings.DEVOWidescreen : game_cfg->DEVOWidescreen; + u8 devoFZeroAXChoice = game_cfg->DEVOFZeroAX == INHERIT ? Settings.DEVOFZeroAX : game_cfg->DEVOFZeroAX; + u8 devoTimerFixChoice = game_cfg->DEVOTimerFix == INHERIT ? Settings.DEVOTimerFix : game_cfg->DEVOTimerFix; + u8 devoDButtonsChoice = game_cfg->DEVODButtons == INHERIT ? Settings.DEVODButtons : game_cfg->DEVODButtons; + u8 devoCropOverscanChoice = game_cfg->DEVOCropOverscan == INHERIT ? Settings.DEVOCropOverscan : game_cfg->DEVOCropOverscan; + u8 devoDiscDelayChoice = game_cfg->DEVODiscDelay == INHERIT ? Settings.DEVODiscDelay : game_cfg->DEVODiscDelay; + + if(gameHdr->type == TYPE_GAME_GC_DISC) + { + WindowPrompt(tr("Error:"), tr("To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings."), tr("OK")); + return -1; + } + + if(gameHdr->type == TYPE_GAME_GC_EXTRACTED) + { + WindowPrompt(tr("Error:"), fmt(tr("%s only accepts GameCube backups in ISO format."),LoaderName), tr("OK")); + return -1; + } + + if(!CheckAHBPROT()) + { + WindowPrompt(tr("Error:"), fmt(tr("%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder."),LoaderName), tr("OK")); + return -1; + } + + if(strncmp(DeviceHandler::PathToFSName(RealPath), "FAT", 3) != 0) + { + WindowPrompt(tr("Error:"), fmt(tr("To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition."),LoaderName), tr("OK")); + return -1; + } + + // Check if Devolution is available + u8 *loader_bin = NULL; + int DEVO_version = 0; + char DEVO_loader_path[100]; + snprintf(DEVO_loader_path, sizeof(DEVO_loader_path), "%sloader.bin", Settings.DEVOLoaderPath); + FILE *f = fopen(DEVO_loader_path, "rb"); + if(f) + { + fseek(f, 0, SEEK_END); + u32 size = ftell(f); + rewind(f); + loader_bin = (u8*)MEM2_alloc(size); + if(!loader_bin) + { + fclose(f); + WindowPrompt(tr("Error:"), tr("Devolution's loader.bin file can't be loaded."), tr("OK")); + return -1; + } + fread(loader_bin, 1, size, f); + + //read Devolution version + char version[5]; + fseek(f, 23, SEEK_SET); + fread(version, 1, 4, f); + char *ptr = strchr(version, ' '); + if(ptr) *ptr = 0; + else version[4] = 0; + DEVO_version = atoi(version); + + fclose(f); + } + else + { + WindowPrompt(tr("Error:"), tr("To run GameCube games with Devolution you need the loader.bin file in your Devolution Loader Path."), tr("OK")); + return -1; + } + + + // Devolution config + DEVO_CFG *devo_config = (DEVO_CFG*)0x80000020; + + char disc1[100]; + char disc2[100]; + bool multiDisc = false; + char DEVO_memCard[100]; + snprintf(disc1, sizeof(disc1), "%s", RealPath); + + snprintf(disc2, sizeof(disc2), "%s", RealPath); + char *pathPtr = strrchr(disc2, '/'); + if(pathPtr) *pathPtr = 0; + snprintf(disc2, sizeof(disc2), "%s/disc2.iso", disc2); + if(CheckFile(disc2)) + multiDisc = true; + + snprintf(DEVO_memCard, sizeof(DEVO_memCard), "%s", RealPath); // Set memory card folder to Disc1 folder + char *ptr = strrchr(DEVO_memCard, '/'); + if(ptr) *ptr = 0; + + // Make sure the directory exists + char devoPath[20]; + snprintf(devoPath, sizeof(devoPath), "%s:/apps/gc_devo", DeviceHandler::GetDevicePrefix(RealPath)); + CreateSubfolder(devoPath); + + // Get the starting cluster (and device ID) for the ISO file 1 + struct stat st1; + stat(disc1, &st1); + + // Get the starting cluster for the ISO file 2 + struct stat st2; + if(multiDisc) + stat(disc2, &st2); + + // setup Devolution + memset(devo_config, 0, sizeof(*devo_config)); + devo_config->signature = DEVO_SIG; + devo_config->version = DEVO_CONFIG_VERSION; + // st1.st_dev doesn't work with our current device type. It returns Wii_UMS 'WUMS' instead of Wii_USB 'WUSB'. + // Only last two letters are returned by DevkitPro, so we set them manually to Devolution config. + devo_config->device_signature = st1.st_dev == 'SD' ? 'SD' : 'SB'; // Set device type. + devo_config->disc1_cluster = st1.st_ino; // set starting cluster for first disc ISO file + if(multiDisc) + devo_config->disc2_cluster = st2.st_ino; // set starting cluster for second disc ISO file + + // Devolution configs + // use wifi logging if USB gecko is not found in slot B + // devo_config->options |= DEVO_CFG_WIFILOG; // removed on Tueidj request + if(devoWidescreenChoice && DEVO_version >= 188) + devo_config->options |= DEVO_CFG_WIDE; + if(!devoActivityLEDChoice && DEVO_version >= 142) + devo_config->options |= DEVO_CFG_NOLED; // ON by default + if(devoFZeroAXChoice && DEVO_version >= 196) + devo_config->options |= DEVO_CFG_FZERO_AX; + if(devoTimerFixChoice && DEVO_version >= 196) + devo_config->options |= DEVO_CFG_TIMER_FIX; + if(devoDButtonsChoice && DEVO_version >= 200) + devo_config->options |= DEVO_CFG_D_BUTTONS; + if (devoCropOverscanChoice && DEVO_version >= 234) + devo_config->options |= DEVO_CFG_CROP_OVERSCAN; + if (devoDiscDelayChoice && DEVO_version >= 234) + devo_config->options |= DEVO_CFG_DISC_DELAY; + // devo_config->options |= DEVO_CFG_PLAYLOG; // Playlog setting managed by USBLoaderGX features menu + + // check memory card + if(devoMCEmulation == DEVO_MC_OFF) + { + devo_config->memcard_cluster = 0; + snprintf(DEVO_memCard, sizeof(DEVO_memCard), "Original"); + } + else + { + if(devoMCEmulation == DEVO_MC_INDIVIDUAL) + { + snprintf(DEVO_memCard, sizeof(DEVO_memCard), "%s/memcard_%.6s.bin", DEVO_memCard, (const char *) gameHdr->id); + } + else // same for all games + { + snprintf(DEVO_memCard, sizeof(DEVO_memCard), "%s:/apps/gc_devo/memcard.bin", DeviceHandler::GetDevicePrefix(RealPath)); + } + + // check if file doesn't exist or is less than 512KB (59 Blocks) + struct stat st; + if (stat(DEVO_memCard, &st) == -1 || st.st_size < 1<<19) + { + // need to enlarge or create it + FILE *f = fopen(DEVO_memCard, "wb"); + if(f) + { + // make it 16MB + ShowProgress(tr("Please wait..."), 0, 0); + gprintf("Resizing memcard file...\n"); + fseek(f, (16 << 20) - 1, SEEK_SET); + fputc(0, f); + fclose(f); + if (stat(DEVO_memCard, &st)==-1 || st.st_size < 1<<19) + { + // it still isn't big enough. Give up. + st.st_ino = 0; + } + ProgressStop(); + } + else + { + // couldn't open or create the memory card file + st.st_ino = 0; + } + } + devo_config->memcard_cluster = st.st_ino; + } + + + // read 32 bytes of disc 1 to the start of MEM1 + FILE *iso_file = fopen(disc1, "rb"); + if(!iso_file) + { + WindowPrompt(tr("Error:"), tr("File not found."), tr("OK")); + return -1; + } + u8 *lowmem = (u8*)0x80000000; + fread(lowmem, 1, 32, iso_file); + fclose(iso_file); + + // setup video mode + Disc_SelectVMode(0, true, NULL, NULL); + Disc_SetVMode(); + + // Set sram flags + PatchSram(languageChoice, false, false); + + // flush disc ID and Devolution config out to memory + DCFlushRange(lowmem, 64); + + ExitApp(); + IosLoader::ReloadIosKeepingRights(58); // reload IOS 58 with AHBPROT rights + + gprintf("DEVO: Loading game: %s\n", disc1); + gprintf("DEVO: Memory Card: %s\n\n", DEVO_memCard); + gprintf("%.72s", (const char*)loader_bin + 4); + + u32 cpu_isr; + SYS_ResetSystem(SYS_SHUTDOWN, 0, 0); + _CPU_ISR_Disable( cpu_isr ); + __exception_closeall(); + LAUNCH_DEVO(); + _CPU_ISR_Restore( cpu_isr ); + return 0; +} + +int GameBooter::BootNintendont(struct discHdr *gameHdr) +{ + + char RealPath[100]; + if(gameHdr->type == TYPE_GAME_GC_DISC) + snprintf(RealPath, sizeof(RealPath), "di"); + else + snprintf(RealPath, sizeof(RealPath), "%s", GCGames::Instance()->GetPath((const char *) gameHdr->id)); + + const char *LoaderName = "Nintendont"; + + GameCFG * game_cfg = GameSettings.GetGameCFG(gameHdr->id); + s8 languageChoice = game_cfg->language == INHERIT ? Settings.language -1 : game_cfg->language; + u8 ocarinaChoice = game_cfg->ocarina == INHERIT ? Settings.ocarina : game_cfg->ocarina; + u8 multiDiscChoice = Settings.MultiDiscPrompt; + u8 ninVideoChoice = game_cfg->DMLVideo == INHERIT ? Settings.DMLVideo : game_cfg->DMLVideo; + u8 ninProgressivePatch = game_cfg->DMLProgPatch == INHERIT ? Settings.DMLProgPatch : game_cfg->DMLProgPatch; + u8 ninDeflickerChoice = game_cfg->NINDeflicker == INHERIT ? Settings.NINDeflicker : game_cfg->NINDeflicker; + u8 ninWidescreenChoice = game_cfg->DMLWidescreen == INHERIT ? Settings.DMLWidescreen : game_cfg->DMLWidescreen; + u8 ninMCEmulationChoice = game_cfg->NINMCEmulation == INHERIT ? Settings.NINMCEmulation : game_cfg->NINMCEmulation; + u8 ninMCSizeChoice = game_cfg->NINMCSize == INHERIT ? Settings.NINMCSize : game_cfg->NINMCSize; + u8 ninAutobootChoice = Settings.NINAutoboot; + u8 ninSettingsChoice = Settings.NINSettings; + u8 ninUSBHIDChoice = game_cfg->NINUSBHID == INHERIT ? Settings.NINUSBHID : game_cfg->NINUSBHID; + u8 ninMaxPadsChoice = game_cfg->NINMaxPads == INHERIT ? Settings.NINMaxPads : game_cfg->NINMaxPads; + u8 ninNativeSIChoice = game_cfg->NINNativeSI == INHERIT ? Settings.NINNativeSI : game_cfg->NINNativeSI; + u8 ninWiiUWideChoice = game_cfg->NINWiiUWide == INHERIT ? Settings.NINWiiUWide : game_cfg->NINWiiUWide; + u8 ninLEDChoice = game_cfg->NINLED == INHERIT ? Settings.NINLED : game_cfg->NINLED; + u8 ninDebugChoice = game_cfg->DMLDebug == INHERIT ? Settings.DMLDebug : game_cfg->DMLDebug; + u8 ninOSReportChoice = game_cfg->NINOSReport == INHERIT ? Settings.NINOSReport : game_cfg->NINOSReport; + u8 ninLogChoice = game_cfg->NINLog == INHERIT ? Settings.NINLog : game_cfg->NINLog; + u8 ninVideoScale = game_cfg->NINVideoScale == INHERIT ? Settings.NINVideoScale : game_cfg->NINVideoScale; + u8 ninVideoOffset = game_cfg->NINVideoOffset == INHERIT - 20 ? Settings.NINVideoOffset : game_cfg->NINVideoOffset; + u8 ninPal50PatchChoice = game_cfg->NINPal50Patch == INHERIT ? Settings.NINPal50Patch : game_cfg->NINPal50Patch; + u8 ninRemlimitChoice = game_cfg->NINRemlimit == INHERIT ? Settings.NINRemlimit : game_cfg->NINRemlimit; + u8 ninArcadeModeChoice = game_cfg->NINArcadeMode == INHERIT ? Settings.NINArcadeMode : game_cfg->NINArcadeMode; + u8 ninCCRumbleChoice = game_cfg->NINCCRumble == INHERIT ? Settings.NINCCRumble : game_cfg->NINCCRumble; + u8 ninSkipIPLChoice = game_cfg->NINSkipIPL == INHERIT ? Settings.NINSkipIPL : game_cfg->NINSkipIPL; + u8 ninBBAEmuChoice = game_cfg->NINBBA == INHERIT ? Settings.NINBBA : game_cfg->NINBBA; // ASA + u8 ninBBAProfileChoice = game_cfg->NINBBAPROF == INHERIT ? Settings.NINBBAPROF : game_cfg->NINBBAPROF; // ASA + + const char *ninLoaderPath = game_cfg->NINLoaderPath.size() == 0 ? Settings.NINLoaderPath : game_cfg->NINLoaderPath.c_str(); + + + if(!CheckAHBPROT()) + { + WindowPrompt(tr("Error:"), fmt(tr("%s requires AHB access! Please launch USBLoaderGX from HBC or from an updated channel or forwarder."),LoaderName), tr("OK")); + return -1; + } + + + // Check if Nintendont boot.dol is available + char NIN_loader_path[255]; + if(strncmp(RealPath, "usb", 3) == 0) // Nintendont r39 only + { + snprintf(NIN_loader_path, sizeof(NIN_loader_path), "%sloaderusb.dol", ninLoaderPath); + if(!CheckFile(NIN_loader_path)) + snprintf(NIN_loader_path, sizeof(NIN_loader_path), "%sbootusb.dol", ninLoaderPath); + } + if(strncmp(RealPath, "sd", 2) == 0 || !CheckFile(NIN_loader_path)) + { + snprintf(NIN_loader_path, sizeof(NIN_loader_path), "%sloader.dol", ninLoaderPath); + if(!CheckFile(NIN_loader_path)) + snprintf(NIN_loader_path, sizeof(NIN_loader_path), "%sboot.dol", ninLoaderPath); + } + if(!CheckFile(NIN_loader_path)) + { + // Nintendont boot.dol not found + WindowPrompt(tr("Error:"), tr("To run GameCube games with Nintendont you need the boot.dol file in your Nintendont Loader Path."), tr("OK")); + return -1; + } + gprintf("NIN: Loader path = %s \n",NIN_loader_path); + gprintf("NIN: Game path = %s \n",RealPath); + + // Check Nintendont version + u32 NIN_cfg_version = NIN_CFG_VERSION; + char NINVersion[7]= ""; + u32 NINRev = 0; + bool NINArgsboot = false; + NINRev = nintendontVersion(Settings.NINLoaderPath, NINVersion, sizeof(NINVersion)); + if(NINRev > 0) // Version available since 3.324 + { + gprintf("NIN: Nintendont revision = %d \n", NINRev); + + NINArgsboot = true; // no need to check argsboot string, 3.324+ supports it. + } + else + { + char NINBuildDate[21] = ""; + if(nintendontBuildDate(Settings.NINLoaderPath, NINBuildDate)) + { + //Current build date + struct tm time; + strptime(NINBuildDate, "%b %d %Y %H:%M:%S", &time); + const time_t NINLoaderTime = mktime(&time); + + // Alpha0.1 + strptime("Sep 20 2013 15:27:01", "%b %d %Y %H:%M:%S", &time); + if(NINLoaderTime == mktime(&time)) + { + WindowPrompt(tr("Error:"), tr("USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."), tr("Ok")); + return -1; + } + + // r01 - r40 + strptime("Mar 30 2014 12:33:44", "%b %d %Y %H:%M:%S", &time); // r42 - NIN_CFG_VERSION = 2 + if(NINLoaderTime < mktime(&time)) + { + gprintf("Nintendont r01 - r40 detected. Using CFG version 0x00000001\n"); + NIN_cfg_version = 1; + + strptime("Mar 29 2014 10:49:31", "%b %d %Y %H:%M:%S", &time); // r39 + if(NINLoaderTime < mktime(&time) && strncmp(RealPath, "usb", 3) == 0) + { + if(WindowPrompt(tr("Warning:"), tr("This Nintendont version does not support games on USB."), tr("Continue"), tr("Cancel")) == 0) + return -1; + } + } + + // v1.01 - v1.134 + strptime("Aug 5 2014 22:38:21", "%b %d %Y %H:%M:%S", &time); // v1.135 - NIN_CFG_VERSION = 3 + if(NINLoaderTime < mktime(&time) && NIN_cfg_version != 1) + { + gprintf("Nintendont v1.01 - v1.134 detected. Using CFG version 0x00000002\n"); + NIN_cfg_version = 2; + // no need to fake NIN_CFG struct size, the size is checked in nintendont only since v1.143 + } + else if(NINLoaderTime >= mktime(&time)) + NINRev = 135; + + // v2.200 to 2.207 + strptime("Nov 6 2014.17:33:30", "%b %d %Y %H:%M:%S", &time); // v1.208 + if(ninAutobootChoice && NINLoaderTime < mktime(&time)) + { + strptime("Oct 31 2014 21:14:47", "%b %d %Y %H:%M:%S", &time); // v1.200 + if(NINLoaderTime >= mktime(&time)) + { + WindowPrompt(tr("Warning:"), tr("This Nintendont version is not correctly supported. Auto boot disabled."), tr("Ok")); + ninAutobootChoice = OFF; + } + } + + // v2.259 - disc support + strptime("Dec 23 2014 17:28:56", "%b %d %Y %H:%M:%S", &time); // v1.259 + if(gameHdr->type == TYPE_GAME_GC_DISC && NINLoaderTime < mktime(&time)) + { + WindowPrompt(tr("Error:"), tr("To run GameCube games from Disc you need to set the GameCube mode to MIOS in the game settings."), tr("OK")); + return -1; + } + + // v3.304 - Controller.ini is now optional + strptime("Feb 23 2015 05:32:16", "%b %d %Y %H:%M:%S", &time); // v3.304 + if(NINLoaderTime >= mktime(&time)) + { + NINRev = 304; + } + + + // checks argsboot + if(ninAutobootChoice) + { + u8 *buffer = NULL; + u32 filesize = 0; + if(LoadFileToMem(NIN_loader_path, &buffer, &filesize)) + { + for(u32 i = 0; i < filesize; i += 0x10) + { + if((*(u32*)(buffer+i)) == 'args' && (*(u32*)(buffer+i+4)) == 'boot') + { + gprintf("NIN: argsboot found at %08x, using arguments instead of Nincfg.bin\n", i); + NINArgsboot = true; + break; + } + } + free(buffer); + } + } + } + else + { + int choice = WindowPrompt(tr("Warning:"), tr("USBloaderGX couldn't verify Nintendont boot.dol file. Launch this boot.dol anyway?"), tr("Yes"), tr("Cancel")); + if(choice == 0) + return -1; + } + } + + // needed since v3.354 CFG v4 to still work with old CFG version + if(NINRev >= 135 && NINRev < 354) + NIN_cfg_version = 3; + else if(NINRev >= 354 && NINRev < 358) + NIN_cfg_version = 4; + else if(NINRev >= 358 && NINRev < 368) + NIN_cfg_version = 5; + + + // Check USB device + if(gameHdr->type != TYPE_GAME_GC_DISC && strncmp(RealPath, "usb", 3) == 0) + { + // Check Main GameCube Path location + if(strncmp(DeviceHandler::PathToFSName(Settings.GameCubePath), "FAT", 3) != 0) + { + WindowPrompt(tr("Error:"), fmt(tr("To run GameCube games with %s you need to set your 'Main GameCube Path' to an USB FAT32 partition."),LoaderName), tr("OK")); + return -1; + } + + // Check the partition type + int USB_partNum = DeviceHandler::PathToDriveType(Settings.GameCubePath)-USB1; // Get partition number across all mounted device + int USBport_partNum = DeviceHandler::PartitionToPortPartition(USB_partNum); // Get partition position from corresponding USB port + PartitionHandle * usbHandle = DeviceHandler::Instance()->GetUSBHandleFromPartition(USB_partNum); // Open a handle on used USB port + + // GPT and EBR 0x0F support added on v3.400, primary type was required on old version. + if(NINRev < 400 && usbHandle->GetPartitionTableType(USBport_partNum) != MBR) + { + WindowPrompt(tr("Error:"), fmt(tr("To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition."),LoaderName), tr("OK")); + return -1; + } + + // Extended type EBR 0x05 was added in 4.406, only type 0x0F was working from 400 to 405 + if(NINRev > 400 && NINRev < 406 && usbHandle->GetPartitionTableType(USBport_partNum) == EBR && usbHandle->GetPartitionType(USBport_partNum) != 0x0F) + { + WindowPrompt(tr("Error:"), tr("Your current GameCube partition is not compatible. Please update Nintendont."), tr("OK")); + return -1; + } + + // check if the partition is the first FAT32 of the drive. ExFAT was added to nintendont 4.x but USBLoaderGX can't list games so no need to check that format. + bool found = false; + for(int partition = 0 ; partition <= USBport_partNum; partition++) + { + if(strncmp(usbHandle->GetFSName(partition), "FAT", 3) != 0) + continue; + + if(partition == USBport_partNum) + { + found = true; + break; + } + } + if(!found) + { + WindowPrompt(tr("Error:"), fmt(tr("To run GameCube games with %s you need to set your 'Main GameCube Path' on the first primary FAT32 partition."),LoaderName), tr("OK")); + return -1; + } + } + + // Set used device when launching game from disc + if(gameHdr->type == TYPE_GAME_GC_DISC) + { + if(Settings.GameCubeSource >= GC_SOURCE_AUTO && strncmp(Settings.GameCubePath, "usb", 3) == 0) + { + if(WindowPrompt("", tr("Which device do you want to use for Nintendont files?"), tr("SD"), tr("USB")) == 1) + snprintf(RealPath, sizeof(RealPath), "%s:/", DeviceHandler::GetDevicePrefix(Settings.GameCubeSDPath)); + else + snprintf(RealPath, sizeof(RealPath), "%s:/", DeviceHandler::GetDevicePrefix(Settings.GameCubePath)); + } + else if(Settings.GameCubeSource == GC_SOURCE_MAIN) + { + snprintf(RealPath, sizeof(RealPath), "%s:/", DeviceHandler::GetDevicePrefix(Settings.GameCubePath)); + } + else + snprintf(RealPath, sizeof(RealPath), "%s:/", DeviceHandler::GetDevicePrefix(Settings.GameCubeSDPath)); + } + + + // Check Ocarina and cheat file location. the .gct file need to be located on the same partition than the game. + if(ocarinaChoice && strcmp(DeviceHandler::GetDevicePrefix(RealPath), DeviceHandler::GetDevicePrefix(Settings.Cheatcodespath)) != 0) + { + char path[255], destPath[255]; + int res = -1; + snprintf(path, sizeof(path), "%s%.6s.gct", Settings.Cheatcodespath, (char *)gameHdr->id); + snprintf(destPath, sizeof(destPath), "%s:/NINTemp.gct", DeviceHandler::GetDevicePrefix(RealPath)); + + gprintf("NIN: Copying %s to %s \n", path, destPath); + res = CopyFile(path, destPath); + if(res < 0) + { + gprintf("NIN: Couldn't copy the file. ret %d. Ocarina Disabled\n", res); + RemoveFile(destPath); + ocarinaChoice = false; + } + } + + // Check kenobiwii.bin + if(NINRev < 336 && (ocarinaChoice || (ninDebugChoice && !isWiiU()))) + { + char kenobiwii_path[30]; + snprintf(kenobiwii_path, sizeof(kenobiwii_path), "%s:/sneek/kenobiwii.bin", DeviceHandler::GetDevicePrefix(RealPath)); + if(!CheckFile(kenobiwii_path)) + { + // try to copy kenobiwii from the other device + if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) != 0) + { + char kenobiwii_srcpath[30]; + + snprintf(kenobiwii_srcpath, sizeof(kenobiwii_srcpath), "%s:/sneek/kenobiwii.bin", strncmp(RealPath, "usb", 3) == 0 ? "sd" : DeviceHandler::GetDevicePrefix(Settings.GameCubePath)); + gprintf("kenobiwii source path = %s \n", kenobiwii_srcpath); + if(CheckFile(kenobiwii_srcpath)) + { + if(CopyFile(kenobiwii_srcpath, kenobiwii_path) < 0) + { + gprintf("NIN: Couldn't copy %s to %s.\n", kenobiwii_srcpath, kenobiwii_path); + RemoveFile(kenobiwii_path); + if(WindowPrompt(tr("Warning:"), fmt(tr("To use ocarina with %s you need the %s file."), LoaderName, kenobiwii_path), tr("Continue"), tr("Cancel")) == 0) + return -1; + } + } + else + { + gprintf("kenobiwii source path = %s Not found.\n", kenobiwii_srcpath); + if(WindowPrompt(tr("Warning:"), fmt(tr("To use ocarina with %s you need the %s file."), LoaderName, kenobiwii_path), tr("Continue"), tr("Cancel")) == 0) + return -1; + } + } + else + { + gprintf("kenobiwii path = %s Not found.\n", kenobiwii_path); + if(WindowPrompt(tr("Warning:"), fmt(tr("To use ocarina with %s you need the %s file."), LoaderName, kenobiwii_path), tr("Continue"), tr("Cancel")) == 0) + return -1; + } + } + } + + // Check controller.ini + if(ninUSBHIDChoice) + { + // Check controller.ini file in priority, then controllers folder, for compatibility with older nintendont versions. + char controllerini_path[30]; + snprintf(controllerini_path, sizeof(controllerini_path), "%s:/controller.ini", DeviceHandler::GetDevicePrefix(RealPath)); + if(!CheckFile(controllerini_path) && strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) != 0) + { + // try to copy controller.ini from the other device + char controllerini_srcpath[30]; + snprintf(controllerini_srcpath, sizeof(controllerini_srcpath), "%s:/controller.ini", strncmp(RealPath, "usb", 3) == 0 ? "sd" : DeviceHandler::GetDevicePrefix(Settings.GameCubePath)); + gprintf("Controller.ini source path = %s \n", controllerini_srcpath); + if(CheckFile(controllerini_srcpath)) + { + if(CopyFile(controllerini_srcpath, controllerini_path) < 0) + { + gprintf("NIN: Couldn't copy %s to %s.\n", controllerini_srcpath, controllerini_path); + RemoveFile(controllerini_path); + if(NINRev < 304) // HID is always enabled and controller.ini optional since r304 + { + if(WindowPrompt(tr("Warning:"), fmt(tr("To use HID with %s you need the %s file."), LoaderName, controllerini_path), tr("Continue"), tr("Cancel")) == 0) + return -1; + } + } + } + else // check controllers folder if no controller.ini found on root. + { + + // Check gamepath:/controllers/ folder + snprintf(controllerini_path, sizeof(controllerini_path), "%s:/controllers/", DeviceHandler::GetDevicePrefix(RealPath)); + if(!CheckFile(controllerini_path) && strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) != 0) + { + // try to copy controllers folder from the other device + char controllerini_srcpath[30]; + snprintf(controllerini_srcpath, sizeof(controllerini_srcpath), "%s:/controllers/", strncmp(RealPath, "usb", 3) == 0 ? "sd" : DeviceHandler::GetDevicePrefix(Settings.GameCubePath)); + gprintf("Controllers folder source path = %s \n", controllerini_srcpath); + if(CheckFile(controllerini_srcpath)) + { + if(CopyDirectory(controllerini_srcpath, controllerini_path) < 0) + { + gprintf("NIN: Couldn't copy %s to %s.\n", controllerini_srcpath, controllerini_path); + RemoveDirectory(controllerini_path); + } + } + else if(NINRev < 304) + { + snprintf(controllerini_path, sizeof(controllerini_path), "%s:/controller.ini", DeviceHandler::GetDevicePrefix(RealPath)); + if(WindowPrompt(tr("Warning:"), fmt(tr("To use HID with %s you need the %s file."), LoaderName, controllerini_path), tr("Continue"), tr("Cancel")) == 0) + return -1; + } + } + + } + } + } + + // Check if game has multi Discs + bool bootDisc2 = false; + if(multiDiscChoice && gameHdr->type != TYPE_GAME_GC_DISC && gameHdr->disc_no == 0) + { + char disc2Path[255]; + snprintf(disc2Path, sizeof(disc2Path), "%s", RealPath); + char *pathPtr = strrchr(disc2Path, '/'); + if(pathPtr) *pathPtr = 0; + snprintf(disc2Path, sizeof(disc2Path), "%s/disc2.iso", disc2Path); + if(CheckFile(disc2Path)) + { + int choice = WindowPrompt(gameHdr->title, tr("This game has multiple discs. Please select the disc to launch."), tr("Disc 1"), tr("Disc 2"), tr("Cancel")); + if(choice == 0) + return -1; + else if(choice == 2) + bootDisc2 = true; + } + } + const char *gcPath = strchr(RealPath, '/'); + if(!gcPath) gcPath = ""; + + char gamePath[255]; + snprintf(gamePath, sizeof(gamePath), "%s", gcPath); + + if(bootDisc2) + { + char *pathPtr = strrchr(gamePath, '/'); + if(pathPtr) *pathPtr = 0; + snprintf(gamePath, sizeof(gamePath), "%s/disc2.iso", gamePath); + } + + if(gameHdr->type == TYPE_GAME_GC_DISC) + { + snprintf(gamePath, sizeof(gamePath), "di"); + } + + + // Nintendont Config file settings + NIN_CFG *nin_config = NULL; + nin_config = (NIN_CFG *)MEM2_alloc(sizeof(NIN_CFG)); + if(!nin_config) + { + gprintf("Not enough memory to create nincfg.bin file.\n"); + WindowPrompt(tr("Error:"), tr("Could not write file."), tr("OK")); + return -1; + } + + memset(nin_config, 0, sizeof(NIN_CFG)); + + // Magic and CFG_Version for Nintendont + nin_config->Magicbytes = NIN_MAGIC; + nin_config->Version = NIN_cfg_version; + + + // Game path + strncpy(nin_config->GamePath, gamePath, sizeof(nin_config->GamePath)); + + // setup cheat and path + if(ocarinaChoice) + { + // Check if the .gct folder is on the same partition than the game, if not load the temporary .gct file. + if(strcmp(DeviceHandler::GetDevicePrefix(RealPath), DeviceHandler::GetDevicePrefix(Settings.Cheatcodespath)) == 0) + { + const char *CheatPath = strchr(Settings.Cheatcodespath, '/'); + if(!CheatPath) CheatPath = ""; + snprintf(nin_config->CheatPath, sizeof(nin_config->CheatPath), "%s%.6s.gct", CheatPath, (char *)gameHdr->id); + } + else + { + snprintf(nin_config->CheatPath, sizeof(nin_config->CheatPath), "/NINTemp.gct"); + } + + nin_config->Config |= NIN_CFG_CHEATS | NIN_CFG_CHEAT_PATH; + gprintf("NIN: Loading cheat %s\n", nin_config->CheatPath); + } + + + // Set other settings + if(ninDebugChoice && !isWiiU()) // only on Wii + nin_config->Config |= ninDebugChoice == ON ? NIN_CFG_DEBUGGER : NIN_CFG_DEBUGGER | NIN_CFG_DEBUGWAIT; + if(ninMCEmulationChoice) + nin_config->Config |= NIN_CFG_MEMCARDEMU; + if(ninWidescreenChoice) + nin_config->Config |= NIN_CFG_FORCE_WIDE; + if(ninProgressivePatch) + { + nin_config->Config |= NIN_CFG_FORCE_PROG; + nin_config->VideoMode |= NIN_VID_PROG; + } + if(ninAutobootChoice) + nin_config->Config |= NIN_CFG_AUTO_BOOT; + if(ninUSBHIDChoice) + nin_config->Config |= NIN_CFG_HID; // auto enabled by nintendont v2.152 and less on vWii + if(ninOSReportChoice) + nin_config->Config |= NIN_CFG_OSREPORT; + if(strncmp(RealPath, "usb", 3) == 0) + nin_config->Config |= NIN_CFG_USB; // r40+ + if(ninLEDChoice) + nin_config->Config |= NIN_CFG_LED; // r45+ + if(ninLogChoice) + nin_config->Config |= NIN_CFG_LOG; // v1.109+ + if(ninMCEmulationChoice == NIN_MC_MULTI) + nin_config->Config |= NIN_CFG_MC_MULTI; // v1.135+ + if(ninNativeSIChoice) + nin_config->Config |= NIN_CFG_NATIVE_SI; // v2.189+ + if(ninWiiUWideChoice) + nin_config->Config |= NIN_CFG_WIIU_WIDE; // v2.258+ + if(ninArcadeModeChoice) + nin_config->Config |= NIN_CFG_ARCADE_MODE; // v4.424+ Triforce Arcade Mode + if (ninCCRumbleChoice) + nin_config->Config |= NIN_CFG_CC_RUMBLE; // v4.431+ Classic Controller Rumble + if (ninSkipIPLChoice) + nin_config->Config |= NIN_CFG_SKIP_IPL; // v4.435+ Skip Gamecube BIOS + + // Max Pads + nin_config->MaxPads = ninMaxPadsChoice; // NIN_CFG_VERSION 2 r42 + + // GameID for MCEmu + memcpy(&nin_config->GameID, gameHdr->id, 4); // NIN_CFG_VERSION 2 r83 + + // GameID for Video mode DiscDefault + memcpy((u8 *)Disc_ID, gameHdr->id, 6); + DCFlushRange((u8 *)Disc_ID, 6); + + // Memory Card Emulation Blocs size with NIN_CFG v3 + if(NIN_cfg_version == 3) + nin_config->MemCardBlocks = ninMCSizeChoice; // NIN_CFG_VERSION 3 v1.135 + // Memory Card Emulation Blocs size + Aspect ratio with NIN_CFG v4 + else if(NIN_cfg_version >= 4) + { + nin_config->MemCardBlocksV4 = ninMCSizeChoice; // NIN_CFG_VERSION 4 v3.354 + nin_config->VideoScale = ninVideoScale; // v3.354+ + nin_config->VideoOffset = ninVideoOffset; // v3.354+ + } + + // Remove data read speed limiter + if(NIN_cfg_version >= 5 && ninRemlimitChoice) + nin_config->Config |= NIN_CFG_REMLIMIT; + + if (NIN_cfg_version >= 9 && ninBBAEmuChoice) //ASA + { + nin_config->Config |= NIN_CFG_BBA; // v6.489+ Enable BBA Emulation + nin_config->BBAProfile = ninBBAProfileChoice; // v6.489+ Which network connection to use for BBAEmu + } + + // Setup Video Mode + if(ninVideoChoice == DML_VIDEO_NONE) // No video mode changes + { + nin_config->VideoMode = NIN_VID_NONE; + } + else + { + if(ninVideoChoice == DML_VIDEO_AUTO) // Auto select video mode + { + Disc_SelectVMode(VIDEO_MODE_DISCDEFAULT, false, NULL, &nin_config->VideoMode); + nin_config->VideoMode = NIN_VID_AUTO; + } + else // Force user choice + { + Disc_SelectVMode(ninVideoChoice-1, false, NULL, &nin_config->VideoMode); + if(nin_config->VideoMode & NIN_VID_FORCE_MASK) + nin_config->VideoMode |= NIN_VID_FORCE; + + if (ninDeflickerChoice) + nin_config->VideoMode |= NIN_VID_FORCE_DF; // v2.208+ + + if (ninPal50PatchChoice && (nin_config->VideoMode & NIN_VID_FORCE_PAL50)) + nin_config->VideoMode |= NIN_VID_PATCH_PAL50; // v3.368+ + + if(nin_config->VideoMode & NIN_VID_PROG) + nin_config->Config |= NIN_CFG_FORCE_PROG; // Set Force_PROG bit in Config + } + Disc_SetVMode(); + } + + gprintf("NIN: Active device %s\n", nin_config->Config & NIN_CFG_USB ? "USB" : "SD"); + gprintf("NIN: config 0x%08x\n", nin_config->Config); + gprintf("NIN: Video mode 0x%08x\n", nin_config->VideoMode); + + // Set game language setting + if(languageChoice >= GC_ENGLISH && languageChoice <= GC_DUTCH) + { + nin_config->Language = languageChoice; + } + else // console default or other languages + { + nin_config->Language = NIN_LAN_AUTO; + if(CONF_GetLanguage() >= CONF_LANG_ENGLISH && CONF_GetLanguage() <= CONF_LANG_DUTCH) + { + nin_config->Language = CONF_GetLanguage()-1; + } + } + gprintf("NIN: Language 0x%08x \n", nin_config->Language); + + + // if WiiVC, force creation and use of nincfg.bin file to fix a nintendont bug if HID is connected before launching it. + if(isWiiVC) + { + ninSettingsChoice = ON; + NINArgsboot = OFF; + } + + // Delete existing nincfg.bin files + if(ninSettingsChoice == OFF) + { + char NINCfgPath[17]; + + // Nintendont loader partition + snprintf(NINCfgPath, sizeof(NINCfgPath), "%s:/nincfg.bin", DeviceHandler::GetDevicePrefix(NIN_loader_path)); + RemoveFile(NINCfgPath); + + // game partition + if(strncmp(NINCfgPath, RealPath, 4) != 0) + { + snprintf(NINCfgPath, sizeof(NINCfgPath), "%s:/nincfg.bin", DeviceHandler::GetDevicePrefix(RealPath)); + RemoveFile(NINCfgPath); + } + + } + else if(ninSettingsChoice == ON || !NINArgsboot) + { + // Nintendont Config file path + char NINCfgPath[17]; + snprintf(NINCfgPath, sizeof(NINCfgPath), "%s:/nincfg.bin", DeviceHandler::GetDevicePrefix(NIN_loader_path)); + gprintf("NIN: Cfg path : %s \n", NINCfgPath); + + //write config file to nintendont's partition root. + FILE *fp = fopen(NINCfgPath, "wb"); + if (fp) + { + fwrite (nin_config , sizeof(char), sizeof(NIN_CFG), fp); + fclose(fp); + } + else + { + gprintf("Could not open NINCfgPath in write mode"); + int choice = WindowPrompt(tr("Warning:"), tr("USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?"), tr("Yes"), tr("Cancel")); + if(choice == 0) + return -1; + } + + // Copy Nintendont Config file to game path + if(strncmp(NINCfgPath, RealPath, 2) != 0) + { + char NINDestPath[17]; + snprintf(NINDestPath, sizeof(NINDestPath), "%s:/nincfg.bin", DeviceHandler::GetDevicePrefix(RealPath)); + gprintf("NIN: Copying %s to %s...", NINCfgPath, NINDestPath); + if(CopyFile(NINCfgPath, NINDestPath) < 0) + { + gprintf("\nError: Couldn't copy %s to %s.\n", NINCfgPath, NINDestPath); + RemoveFile(NINDestPath); + if(WindowPrompt(tr("Warning:"), tr("USBloaderGX couldn't write Nintendont config file. Launch Nintendont anyway?"), tr("Yes"), tr("Cancel")) == 0) + return -1; + } + gprintf("done\n"); + } + } + + if(NINArgsboot) + { + // initialize homebrew and arguments + u8 *buffer = NULL; + u32 filesize = 0; + LoadFileToMem(NIN_loader_path, &buffer, &filesize); + if(!buffer) + { + return -1; + } + FreeHomebrewBuffer(); + CopyHomebrewMemory(buffer, 0, filesize); + + AddBootArgument(NIN_loader_path); + AddBootArgument((char*)nin_config, sizeof(NIN_CFG)); + + // Launch Nintendont + return !(BootHomebrewFromMem() < 0); + } + else + { + // Launch Nintendont + return !(BootHomebrew(NIN_loader_path) < 0); + } +} + +int GameBooter::BootNeek(struct discHdr *gameHdr) +{ + struct discHdr gameHeader; + memcpy(&gameHeader, gameHdr, sizeof(struct discHdr)); + + GameCFG * game_cfg = GameSettings.GetGameCFG(gameHdr->id); + u8 ocarinaChoice = game_cfg->ocarina == INHERIT ? Settings.ocarina : game_cfg->ocarina; + u64 returnToChoice = game_cfg->returnTo; + const char *NandEmuPath = game_cfg->NandEmuPath.size() == 0 ? Settings.NandEmuChanPath : game_cfg->NandEmuPath.c_str(); + bool autoboot = true; + bool NK2O_isInstalled = false; + char tempPath[100] = ""; + int ret = -1; + + // Check all settings first before loading kernel + + // Check kernel.bin + int neekMode = neekIsNeek2o(NandEmuPath); // -1 = kernel.bin not found, 0 = neek, 1 = neek2o + if(neekMode == -1) + { + WindowPrompt(tr("Error:"), tr("Neek kernel file not found."), tr("OK")); + return -1; + } + if(neekMode == 0) + { + if(WindowPrompt(tr("Warning:"), tr("Current neek files are not neek2o. Game autoboot disabled."), tr("Continue"), tr("Cancel")) == 0) + return -1; + autoboot = false; + } + + // Set current EmuNAND path as default for neek2o. + if(neekMode == 1) + { + ret = neek2oSetNAND(NandEmuPath); + gprintf("NEEK: Setting EmuNAND in nandcfg.bin : %d \n", ret); + if(ret < 0) + { + WindowPrompt(tr("Error:"), tr("Neek NAND path selection failed."), tr("OK")); + return -1; + } + } + + // check and prepare EmuNAND path for neek + char neekNandPath[256] = ""; + neekPathFormat(neekNandPath, NandEmuPath, sizeof(neekNandPath)); + + // check if the nand path is compatible with current neek mode. + if(neekMode == 0 && strlen(neekNandPath) > 0) + { + WindowPrompt(tr("Error:"), tr("You need neek2o to load EmuNAND from sub-folders."), tr("OK")); + return -1; + } + + // Check if emuNAND path is on SD + if(neekMode == 1 && isWiiU() && strncmp(NandEmuPath, "sd", 2) == 0) // neek2o on SD is not supported with the vWii leaked version of neek2o. Users could use it on Wii too, but they should be using r96. + { + if(WindowPrompt(tr("Warning:"), tr("Neek2o does not support 'Emulated NAND Channel Path' on SD! Please setup Uneek2o instead."), tr("Continue"), tr("Cancel")) == 0) + return -1; + } + + // check partition compatibility - TODO : confirm incompatibility with each check + + // Check if EmuNAND partition is on USB devices + if(strncmp(NandEmuPath, "usb", 3) == 0) + { + // Todo: add uStealth'd HDD check here, might need neek version detection too. + + // Check partition format // Assume SD is always FAT32 + if(strncmp(DeviceHandler::PathToFSName(NandEmuPath), "FAT", 3) != 0) + { + WindowPrompt(tr("Error:"), tr("To use neek you need to set your 'Emulated NAND Channel Path' to a FAT32 partition."), tr("OK")); + return -1; + } + + // Check if the partition is the first primary partition on the drive - TODO : verify if it also needs to be the first partition of the drive. + bool found = false; + int USB_partNum = DeviceHandler::PathToDriveType(NandEmuPath)-USB1; + int USBport_partNum = DeviceHandler::PartitionToPortPartition(USB_partNum); + int usbport = DeviceHandler::PartitionToUSBPort(USB_partNum); + PartitionHandle * usbHandle = DeviceHandler::Instance()->GetUSBHandleFromPartition(USB_partNum); + for(int partition = 0 ; partition <= USBport_partNum; partition++) + { + if(usbHandle->GetPartitionTableType(partition) != MBR) + continue; + + if(partition == USBport_partNum) + { + found = true; + break; + } + } + if(!found) + { + WindowPrompt(tr("Error:"), tr("To use neek you need to set your 'Emulated NAND Channel Path' on the first primary partition of the Hard Drive."), tr("OK")); + return -1; + } + + // Check HDD sector size. Only 512 bytes/sector is supported by neek? + if(neekMode == 0 && hdd_sector_size[usbport] != BYTES_PER_SECTOR) // neek2o supports 3TB+ HDD + { + WindowPrompt(tr("Error:"), tr("To use neek you need to use a 512 bytes/sector Hard Drive."), tr("OK")); + return -1; + } + } + + // Set ocarina file. + if(ocarinaChoice) + { + if(WindowPrompt(tr("Warning:"), tr("Ocarina is not supported with neek2o yet. Launch game anyway?"), tr("Continue"), tr("Cancel")) == 0) + return -1; + } + + if(!returnToChoice) + { + // delete residual "return to" file if last shutdown was unclean. + snprintf(tempPath, sizeof(tempPath), "%s:/sneek/reload.sys", DeviceHandler::GetDevicePrefix(NandEmuPath)); + if(CheckFile(tempPath)) + RemoveFile(tempPath); + } + else + { + snprintf(tempPath, sizeof(tempPath), "%s/title/00010001/4e4b324f/content/title.tmd", NandEmuPath); + if(CheckFile(tempPath)) + NK2O_isInstalled = true; + } + + // Every checks passed successfully. Continue execution. + + // Load neek kernel.bin + if(neekLoadKernel(NandEmuPath) == false) + { + WindowPrompt(tr("Error:"), tr("Neek kernel loading failed."), tr("OK")); + return -1; + } + + // all is good so far, exit the loader, set the settings and boot neek. + ExitApp(); + + // Set Neek2o settings + NEEK_CFG *neek_config = (NEEK_CFG *) NEEK_CONFIG_ADDRESS; + memset(neek_config, 0, sizeof(NEEK_CFG)); + + // Magic and version for Neek2o + neek_config->magic = NEEK_MAGIC; + + // Set NAND path + snprintf(neek_config->nandpath, sizeof(neek_config->nandpath), "%s", neekNandPath); + neek_config->config |= NCON_EXT_NAND_PATH ; // specify a nand path in case default NAND set in nandcfg.bin failed + // neek_config->config |= NCON_HIDE_EXT_PATH; // set nand path as temporary (attention: "return to" loads channel from the default NAND path) + + // Set TitleID to return to + if(autoboot && returnToChoice) + { + // Todo : allow user to select the channel to return to. + if(NK2O_isInstalled) + { + neek_config->returnto = TITLE_ID(0x00010001, 'NK2O'); // Currently forced to NK2O user channel + neek_config->config |= NCON_EXT_RETURN_TO; // enable "return to" patch + } + + if(isWiiU()) + { + neek_config->returnto = TITLE_ID(0x00010002, 'HCVA'); // Currently forced to "Return to WiiU" system channel + neek_config->config |= NCON_EXT_RETURN_TO; // enable "return to" patch + } + } + + // Set GameID - Channels + if(autoboot && gameHeader.type == TYPE_GAME_EMUNANDCHAN) + neek_config->titleid = gameHeader.tid; + + // Set GameID - Wii ISO + else if(autoboot && (gameHeader.type == TYPE_GAME_WII_IMG || gameHeader.type == TYPE_GAME_WII_DISC)) // This autoobot method doesn't work in neek2o r96 + { + neek_config->gamemagic = 0x5d1c9ea3; // Wii game + neek_config->gameid = (u32)gameHeader.id; // wbfs GameID4 to autoboot + neek_config->config |= NCON_EXT_BOOT_GAME; // Boot di Game + } + + // Set GameID - GameCube ISO + else if(autoboot && (gameHeader.type == TYPE_GAME_GC_IMG || gameHdr->type == TYPE_GAME_GC_EXTRACTED)) // not implemented yet + { + neek_config->gamemagic = 0xC2339F3D; // gamecube games + neek_config->gameid = (u32)gameHeader.id; // GameCube GameID4 to autoboot + neek_config->config |= NCON_EXT_BOOT_GAME; // Boot di Game + + // set DML setttings in Neek config2 + // see how to boot neek for DM/L games + } + + //set a custom di folder + //snprintf(neek_config->dipath, sizeof(neek_config->dipath), "/sneek/vwii"); // Set path for di.bin and diconfig.bin + //neek_config->config |= NCON_EXT_DI_PATH; // Use custom di path + + DCFlushRange(neek_config, sizeof(NEEK_CFG)); + + gprintf("NEEK: Settings:"); + hexdump((u8*) NEEK_CONFIG_ADDRESS, sizeof(NEEK_CFG)); + + if(neekBoot() == -1) + Sys_BackToLoader(); + return 0; +} + +void GameBooter::PatchSram(int language, bool patchVideoMode, bool progressive) +{ + syssram *sram = __SYS_LockSram(); + + // Setup language flag + if(language >= GC_ENGLISH && language <= GC_DUTCH) + { + sram->lang = language; + } + else // console default + { + sram->lang = GC_ENGLISH; + if(CONF_GetLanguage() >= CONF_LANG_ENGLISH && CONF_GetLanguage() <= CONF_LANG_DUTCH) + { + sram->lang = CONF_GetLanguage()-1; + } + } + gprintf("Sram: Language set to 0x%02x\n", sram->lang); + + // Setup Video mode flags + if(patchVideoMode) + { + if(progressive) + sram->flags |= 0x80; //set progressive flag + else + sram->flags &= 0x7F; //clear progressive flag + + if (*Video_Mode == VI_NTSC) + { + sram->flags &= ~1; // Clear bit 0 to set the video mode to NTSC + sram->ntd &= 0xBF; //clear pal60 flag + } + else + { + sram->flags |= 1; // Set bit 0 to set the video mode to PAL + sram->ntd |= 0x40; //set pal60 flag + } + + gprintf("Sram: flags set to 0x%02x\n", sram->flags); + gprintf("Sram: ntd set to 0x%02x\n", sram->ntd); + } + + __SYS_UnlockSram(1); // 1 -> write changes + while(!__SYS_SyncSram()) + usleep(100); + + + // Log Sram's first 20 bytes +/* char srambuff[64]; + sram = __SYS_LockSram(); + memcpy(srambuff, sram, 20); + __SYS_UnlockSram(0); + + int i; + gprintf("SRAM Hex View\n\n"); + gprintf(" \t\t 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); + for (i=0;i<20;i++) + { + if( (i%16) == 0 ) + gprintf("\n0x%d0h\t\t", i/16); + + gprintf("%02X ", srambuff[i]); + } +*/ +} diff --git a/source/usbloader/GameBooter.hpp b/source/usbloader/GameBooter.hpp new file mode 100644 index 0000000..39bd9af --- /dev/null +++ b/source/usbloader/GameBooter.hpp @@ -0,0 +1,41 @@ +/**************************************************************************** + * Copyright (C) 2009-2011 Dimok + * + * 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 GAMEBOOTER_HPP_ +#define GAMEBOOTER_HPP_ + +#include +#include "usbloader/disc.h" + +class GameBooter +{ + public: + static int BootGame(struct discHdr *gameHdr); + static int BootGCMode(struct discHdr *gameHdr); + private: + static void SetupAltDOL(u8 * gameID, u8 &alternatedol, u32 &alternatedoloffset); + static void SetupNandEmu(u8 NandEmuMode, const char *NandEmuPath, struct discHdr &gameHeader); + static int SetupDisc(struct discHdr &gameHeader); + static u32 BootPartition(char * dolpath, u8 videoselected, u8 alternatedol, u32 alternatedoloffset); + static void ShutDownDevices(int gameUSBPort); + static int BootDIOSMIOS(struct discHdr *gameHdr); + static int BootDevolution(struct discHdr *gameHdr); + static int BootNintendont(struct discHdr *gameHdr); + static int BootNeek(struct discHdr *gameHdr); + static void PatchSram(int language, bool patchVideoMode, bool progressive); +}; + +#endif diff --git a/source/usbloader/GameList.cpp b/source/usbloader/GameList.cpp new file mode 100644 index 0000000..ff720c0 --- /dev/null +++ b/source/usbloader/GameList.cpp @@ -0,0 +1,437 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include "GUI/gui_searchbar.h" +#include "usbloader/wbfs.h" +#include "GameCube/GCGames.h" +#include "settings/newtitles.h" +#include "settings/CSettings.h" +#include "settings/CGameSettings.h" +#include "settings/CGameStatistics.h" +#include "settings/GameTitles.h" +#include "settings/CGameCategories.hpp" +#include "FreeTypeGX.h" +#include "GameList.h" +#include "memory/memory.h" +#include "Channels/channels.h" + +enum { DISABLED, ENABLED, HIDEFORBIDDEN }; + +GameList gameList; + +void GameList::clear() +{ + GameFilter.clear(); + FullGameList.clear(); + GamePartitionList.clear(); + FilteredList.clear(); + //! Clear memory of the vector completely + std::vector().swap(FilteredList); + std::vector().swap(FullGameList); + std::vector().swap(GamePartitionList); +} + +struct discHdr * GameList::GetDiscHeader(const char * gameID) const +{ + if(!gameID) return NULL; + + for (u32 i = 0; i < FilteredList.size(); ++i) + { + if(strncasecmp(gameID, (const char *) FilteredList[i]->id, 6) == 0) + return FilteredList[i]; + } + + return NULL; +} + +int GameList::GetPartitionNumber(const u8 *gameID) const +{ + if(!gameID) return -1; + + for (u32 i = 0; i < FullGameList.size(); ++i) + { + if(strncasecmp((const char *) gameID, (const char *) FullGameList[i].id, 6) == 0) + return GamePartitionList[i]; + } + + return -1; +} + +void GameList::RemovePartition(int part) +{ + for(u32 i = 0; i < GamePartitionList.size(); ++i) + { + if(GamePartitionList[i] == part) + { + FullGameList.erase(FullGameList.begin()+i); + GamePartitionList.erase(GamePartitionList.begin()+i); + --i; + } + } + + if(FullGameList.size() > 0) + FilterList(); +} + +int GameList::InternalReadList(int part) +{ + // Retrieve all stuff from WBFS + u32 cnt = 0; + + int ret = WBFS_GetCount(part, &cnt); + if (ret < 0) return -1; + + // We are done here if no games are there + if(cnt == 0) + return 0; + + /* Buffer length */ + u32 len = sizeof(struct discHdr) * cnt; + + /* Allocate memory */ + struct discHdr *buffer = (struct discHdr *) allocate_memory( len ); + if (!buffer) return -1; + + /* Clear buffer */ + memset(buffer, 0, len); + + /* Get header list */ + ret = WBFS_GetHeaders(part, buffer, cnt, sizeof(struct discHdr)); + if (ret < 0) + { + free(buffer); + return -1; + } + + u32 oldSize = FullGameList.size(); + std::vector PartGameList(cnt); + memcpy(&PartGameList[0], buffer, len); + free(buffer); + + for (u32 i = 0; i < PartGameList.size(); i++) + { + for(u32 j = 0; j < FullGameList.size(); j++) + { + if(strncasecmp((const char *) PartGameList[i].id, (const char *) FullGameList[j].id, 6) == 0) + { + PartGameList.erase(PartGameList.begin()+i); + --i; + break; + } + } + } + FullGameList.resize(oldSize+PartGameList.size()); + memcpy(&FullGameList[oldSize], &PartGameList[0], PartGameList.size()*sizeof(struct discHdr)); + + GamePartitionList.resize(oldSize+PartGameList.size()); + + for(u32 i = oldSize; i < GamePartitionList.size(); ++i) + GamePartitionList[i] = part; + + return PartGameList.size(); +} + +int GameList::ReadGameList() +{ + // Clear list + FullGameList.clear(); + GamePartitionList.clear(); + //! Clear memory of the vector completely + std::vector().swap(FullGameList); + std::vector().swap(GamePartitionList); + + int cnt = 0; + + if(!Settings.MultiplePartitions) + { + cnt = InternalReadList(Settings.partition); + } + else + { + int partitions = DeviceHandler::GetUSBPartitionCount(); + + for(int part = 0; part < partitions; ++part) + { + int ret = InternalReadList(part); + if(ret > 0) cnt += ret; + } + } + + return cnt; +} + +void GameList::InternalFilterList(std::vector &FullList) +{ + for (u32 i = 0; i < FullList.size(); ++i) + { + struct discHdr *header = &FullList[i]; + + /* Register game */ + NewTitles::Instance()->CheckGame(header->id); + + /* Filters */ + if (Settings.GameSort & SORT_FAVORITE) + { + GameStatus * GameStats = GameStatistics.GetGameStatus(header->id); + if (Settings.marknewtitles) + { + bool isNew = NewTitles::Instance()->IsNew(header->id); + if (!isNew && (!GameStats || GameStats->FavoriteRank == 0)) continue; + } + else + { + if (!GameStats || GameStats->FavoriteRank == 0) continue; + } + } + + //ignore uLoader cfg "iso". i was told it is "__CFG_" but not confirmed + if (strncasecmp((char*) header->id, "__CFG_", 6) == 0) + continue; + + GameCFG * GameConfig = GameSettings.GetGameCFG(header); + + /* Rating based parental control method */ + if (Settings.parentalcontrol != PARENTAL_LVL_ADULT && !Settings.godmode) + { + if (GameConfig && GameConfig->parentalcontrol > Settings.parentalcontrol) + continue; + + // Check game rating in GameTDB, since the default Wii parental control setting is enabled + int rating = GameTitles.GetParentalRating((char *) header->id); + if (rating > Settings.parentalcontrol) + continue; + } + + //! Per game lock method + if(!Settings.godmode && GameConfig && GameConfig->Locked) + continue; + + //! Category filter + u32 n; + int allType = DISABLED; + // verify the display mode for category "All" + for(n = 0; n < Settings.EnabledCategories.size(); ++n) + { + if(Settings.EnabledCategories[n] == 0) + { + allType = ENABLED; // All = Enabled + break; + } + } + for(n = 0; n < Settings.ForbiddenCategories.size(); ++n) + { + if(Settings.ForbiddenCategories[n] == 0) + { + allType = HIDEFORBIDDEN; // All = Enabled but hide Forbidden categories + break; + } + } + + if(allType == DISABLED) + { + // Remove TitleID if it contains a forbidden categories + for(n = 0; n < Settings.ForbiddenCategories.size(); ++n) + { + if(GameCategories.isInCategory((char *) header->id, Settings.ForbiddenCategories[n])) + break; + } + if(n < Settings.ForbiddenCategories.size()) + continue; + + // Remove TitleID is it doesn't contain a required categories + for(n = 0; n < Settings.RequiredCategories.size(); ++n) + { + if(!GameCategories.isInCategory((char *) header->id, Settings.RequiredCategories[n])) + break; + } + if(n < Settings.RequiredCategories.size()) + continue; + + // If there's no required categories, verify if the TitleID should be kept or removed + if(Settings.RequiredCategories.size() == 0) + { + for(n = 0; n < Settings.EnabledCategories.size(); ++n) + { + if(GameCategories.isInCategory((char *) header->id, Settings.EnabledCategories[n])) + break; + } + if(n == Settings.EnabledCategories.size()) + continue; + } + } + + if(allType == HIDEFORBIDDEN) + { + // Remove TitleID if it contains a forbidden categories + for(n = 0; n < Settings.ForbiddenCategories.size(); ++n) + { + if(GameCategories.isInCategory((char *) header->id, Settings.ForbiddenCategories[n])) + if(Settings.ForbiddenCategories[n] >0) + break; + } + if(n < Settings.ForbiddenCategories.size()) + continue; + } + + FilteredList.push_back(header); + } +} + +int GameList::FilterList(const wchar_t * gameFilter) +{ + if((Settings.LoaderMode & MODE_WIIGAMES) && (FullGameList.size() == 0)) + ReadGameList(); + + if (gameFilter) + GameFilter.assign(gameFilter); + + FilteredList.clear(); + + // Filter current game list if selected + if(Settings.LoaderMode & MODE_WIIGAMES) + InternalFilterList(FullGameList); + + // Filter gc game list if selected + if(Settings.LoaderMode & MODE_GCGAMES) + InternalFilterList(GCGames::Instance()->GetHeaders()); + + // Filter nand channel list if selected + if(Settings.LoaderMode & MODE_NANDCHANNELS) + InternalFilterList(Channels::Instance()->GetNandHeaders()); + + // Filter emu nand channel list if selected + if(Settings.LoaderMode & MODE_EMUCHANNELS) + InternalFilterList(Channels::Instance()->GetEmuHeaders()); + + NewTitles::Instance()->Save(); + GuiSearchBar::FilterList(FilteredList, GameFilter); + + SortList(); + + return FilteredList.size(); +} + +void GameList::InternalLoadUnfiltered(std::vector &FullList) +{ + for (u32 i = 0; i < FullList.size(); ++i) + { + struct discHdr *header = &FullList[i]; + + /* Register game */ + NewTitles::Instance()->CheckGame(header->id); + + FilteredList.push_back(header); + } +} + +int GameList::LoadUnfiltered() +{ + if((Settings.LoaderMode & MODE_WIIGAMES) && (FullGameList.size() == 0)) + ReadGameList(); + + GameFilter.clear(); + FilteredList.clear(); + + // Filter current game list if selected + if(Settings.LoaderMode & MODE_WIIGAMES) + InternalLoadUnfiltered(FullGameList); + + // Filter gc game list if selected + if(Settings.LoaderMode & MODE_GCGAMES) + InternalLoadUnfiltered(GCGames::Instance()->GetHeaders()); + + // Filter nand channel list if selected + if(Settings.LoaderMode & MODE_NANDCHANNELS) + InternalLoadUnfiltered(Channels::Instance()->GetNandHeaders()); + + // Filter emu nand channel list if selected + if(Settings.LoaderMode & MODE_EMUCHANNELS) + InternalLoadUnfiltered(Channels::Instance()->GetEmuHeaders()); + + NewTitles::Instance()->Save(); + GuiSearchBar::FilterList(FilteredList, GameFilter); + + SortList(); + + return FilteredList.size(); +} + +void GameList::SortList() +{ + if (FilteredList.size() < 2) return; + + if (Settings.GameSort & SORT_PLAYCOUNT) + { + std::sort(FilteredList.begin(), FilteredList.end(), PlaycountSortCallback); + } + else if(Settings.GameSort & SORT_RANKING) + { + std::sort(FilteredList.begin(), FilteredList.end(), RankingSortCallback); + } + else if(Settings.GameSort & SORT_PLAYERS) + { + std::sort(FilteredList.begin(), FilteredList.end(), PlayersSortCallback); + } + else + { + std::sort(FilteredList.begin(), FilteredList.end(), NameSortCallback); + } +} + +bool GameList::NameSortCallback(const struct discHdr *a, const struct discHdr *b) +{ + return (strcasecmp(GameTitles.GetTitle((struct discHdr *) a), GameTitles.GetTitle((struct discHdr *) b)) < 0); +} + +bool GameList::PlaycountSortCallback(const struct discHdr *a, const struct discHdr *b) +{ + int count1 = GameStatistics.GetPlayCount(a->id); + int count2 = GameStatistics.GetPlayCount(b->id); + + if (count1 == count2) return NameSortCallback(a, b); + + return (count1 > count2); +} + +bool GameList::RankingSortCallback(const struct discHdr *a, const struct discHdr *b) +{ + int fav1 = GameStatistics.GetFavoriteRank(a->id); + int fav2 = GameStatistics.GetFavoriteRank(b->id); + + if (fav1 == fav2) return NameSortCallback(a, b); + + return (fav1 > fav2); +} + +bool GameList::PlayersSortCallback(const struct discHdr *a, const struct discHdr *b) +{ + int count1 = GameTitles.GetPlayersCount((const char *) a->id); + int count2 = GameTitles.GetPlayersCount((const char *) b->id); + + if (count1 == count2) return NameSortCallback(a, b); + + return (count1 > count2); +} diff --git a/source/usbloader/GameList.h b/source/usbloader/GameList.h new file mode 100644 index 0000000..293c9a6 --- /dev/null +++ b/source/usbloader/GameList.h @@ -0,0 +1,56 @@ +#ifndef GAME_LIST_H_ +#define GAME_LIST_H_ + +#include +#include "Controls/DeviceHandler.hpp" +#include "wstring.hpp" +#include "usbloader/disc.h" + +class GameList +{ + public: + GameList() : selectedGame(0) { }; + int ReadGameList(); + int size() const { return FilteredList.size(); } + int GameCount() const { return FullGameList.size(); } + int FilterList(const wchar_t * gameFilter = NULL); + int LoadUnfiltered(); + struct discHdr * at(int i) const { return operator[](i); } + struct discHdr * operator[](int i) const { if (i < 0 || i >= (int) FilteredList.size()) return NULL; return FilteredList[i]; } + struct discHdr * GetDiscHeader(const char * gameID) const; + const wchar_t * GetCurrentFilter() const { return GameFilter.c_str(); } + void SortList(); + void clear(); + bool operator!() const { return (FullGameList.size() == 0); } + //! Gamelist scrolling operators + int operator+=(int i) { return (selectedGame = (selectedGame+i) % FilteredList.size()); } + int operator-=(int i) { return (selectedGame = (selectedGame-i+FilteredList.size()) % FilteredList.size()); } + int operator++() { return (selectedGame = (selectedGame+1) % FilteredList.size()); } + int operator--() { return (selectedGame = (selectedGame-1+FilteredList.size()) % FilteredList.size()); } + int operator++(int i) { return operator++(); } + int operator--(int i) { return operator--(); } + struct discHdr * GetCurrentSelected() const { return operator[](selectedGame); } + int GetPartitionNumber(const u8 *gameid) const; + int GetGameFS(const u8 *gameID) const { return DeviceHandler::Instance()->GetFilesystemType(USB1+GetPartitionNumber(gameID)); } + void RemovePartition(int part_num); + std::vector &GetFilteredList(void) { return FilteredList; } + std::vector &GetFullGameList(void) { return FullGameList; } + protected: + int InternalReadList(int part); + void InternalFilterList(std::vector &FullList); + void InternalLoadUnfiltered(std::vector &FullList); + static bool NameSortCallback(const struct discHdr *a, const struct discHdr *b); + static bool PlaycountSortCallback(const struct discHdr *a, const struct discHdr *b); + static bool RankingSortCallback(const struct discHdr *a, const struct discHdr *b); + static bool PlayersSortCallback(const struct discHdr *a, const struct discHdr *b); + + wString GameFilter; + int selectedGame; + std::vector FilteredList; + std::vector FullGameList; + std::vector GamePartitionList; +}; + +extern GameList gameList; + +#endif diff --git a/source/usbloader/GetMissingGameFiles.cpp b/source/usbloader/GetMissingGameFiles.cpp new file mode 100644 index 0000000..25fe5d7 --- /dev/null +++ b/source/usbloader/GetMissingGameFiles.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include "FileOperations/fileops.h" +#include "usbloader/GameList.h" +#include "wstring.hpp" +#include "gecko.h" + +extern struct discHdr *dvdheader; + +/************************************************************************************** + * FindMissingFiles + * Inputs: + * path - Path to search in with. example "SD:/covers/" + * fileext - the file extension. example ".png" + * MissingFilesList - string vector where the IDs of missing game files will be put in. + **************************************************************************************/ +int GetMissingGameFiles(const char * path, const char * fileext, std::vector & MissingFilesList) +{ + char gameID[7]; + char filepath[512]; + MissingFilesList.clear(); + wString oldFilter(gameList.GetCurrentFilter()); + + //! make sure that all games are added to the gamelist + gameList.LoadUnfiltered(); + + for (int i = 0; i < gameList.size(); ++i) + { + struct discHdr* header = gameList[i]; + snprintf(gameID, sizeof(gameID), "%s", (char *) header->id); + snprintf(filepath, sizeof(filepath), "%s/%s%s", path, gameID, fileext); + + if (CheckFile(filepath)) + continue; + + //! Not found. Try 4 ID path. + gameID[4] = '\0'; + snprintf(filepath, sizeof(filepath), "%s/%s%s", path, gameID, fileext); + + if (CheckFile(filepath)) + continue; + + //! Not found. Try 3 ID path. + gameID[3] = '\0'; + snprintf(filepath, sizeof(filepath), "%s/%s%s", path, gameID, fileext); + + if (CheckFile(filepath)) + continue; + + //! Not found add to missing list + snprintf(gameID, sizeof(gameID), "%s", (char *) header->id); + MissingFilesList.push_back(std::string(gameID)); + } + + if(dvdheader) + { + snprintf(gameID, sizeof(gameID), "%s", (char *) dvdheader->id); + snprintf(filepath, sizeof(filepath), "%s/%s%s", path, gameID, fileext); + + if (!CheckFile(filepath)) { + //! Not found, add missing dvd header to list + MissingFilesList.push_back(std::string(gameID)); + } + } + + //! Bring game list to the old state + gameList.FilterList(oldFilter.c_str()); + + gprintf(" = %i", MissingFilesList.size()); + + return MissingFilesList.size(); +} diff --git a/source/usbloader/GetMissingGameFiles.hpp b/source/usbloader/GetMissingGameFiles.hpp new file mode 100644 index 0000000..1b08a7f --- /dev/null +++ b/source/usbloader/GetMissingGameFiles.hpp @@ -0,0 +1,14 @@ +#ifndef GETMISSINGGAMEFILES_HPP_ +#define GETMISSINGGAMEFILES_HPP_ + +/************************************************************************************** + * FindMissingFiles + * This function can be used for any files that are game related: .png, .wip, .gct, ... + * Inputs: + * path - Path to search in with. example "SD:/covers/" + * fileext - the file extension. example ".png" + * List - string vector where the IDs of missing game files will be put in. + **************************************************************************************/ +int GetMissingGameFiles(const char * path, const char * fileext, std::vector & List); + +#endif diff --git a/source/usbloader/MountGamePartition.cpp b/source/usbloader/MountGamePartition.cpp new file mode 100644 index 0000000..e4aace8 --- /dev/null +++ b/source/usbloader/MountGamePartition.cpp @@ -0,0 +1,176 @@ +#include +#include + +#include "FileOperations/fileops.h" +#include "Controls/DeviceHandler.hpp" +#include "wad/nandtitle.h" +#include "system/IosLoader.h" +#include "menu/menus.h" +#include "wpad.h" +#include "usbloader/wbfs.h" +#include "usbloader/GameList.h" +#include "settings/GameTitles.h" +#include "xml/GameTDB.hpp" +#include "utils/ShowError.h" + +static int FindGamePartition() +{ + int partCount = DeviceHandler::GetUSBPartitionCount(); + + // Loop through all WBFS partitions first to check them in case IOS249 Rev < 18 + for(int i = 0; i < partCount; ++i) + { + if(DeviceHandler::GetFilesystemType(USB1+i) != PART_FS_WBFS) + continue; + + if (WBFS_OpenPart(i) == 0) + { + Settings.partition = i; + return 0; + } + } + + int firstValidPartition = -1; + + if(IosLoader::IsWaninkokoIOS() && NandTitles.VersionOf(TITLE_ID(1, IOS_GetVersion())) < 18) + return -1; + + // Loop through FAT/NTFS/EXT partitions, and find the first partition with games on it (if there is one) + for(int i = 0; i < partCount; ++i) + { + if(DeviceHandler::GetFilesystemType(USB1+i) != PART_FS_NTFS && + DeviceHandler::GetFilesystemType(USB1+i) != PART_FS_FAT && + DeviceHandler::GetFilesystemType(USB1+i) != PART_FS_EXT) + { + continue; + } + + if (WBFS_OpenPart(i) != 0) + continue; + + u32 count; + // Get the game count... + WBFS_GetCount(i, &count); + + if (count > 0) + { + Settings.partition = i; + return 0; + } + + if(firstValidPartition < 0) + firstValidPartition = i; + + WBFS_Close(i); + } + + if(firstValidPartition >= 0) + { + Settings.partition = firstValidPartition; + return 0; + } + + return -1; +} + +static int PartitionChoice() +{ + int ret = -1; + + int choice = WindowPrompt(tr( "No WBFS or FAT/NTFS/EXT partition found" ), tr( "You can select or format a partition or use the channel loader mode." ), tr( "Select" ), tr( "Format" ), tr( "Channels" )); + if (choice == 0) + { + Settings.LoaderMode = MODE_NANDCHANNELS; + return 0; + } + else if(choice == 1) + { + int part_num = SelectPartitionMenu(); + if(part_num >= 0) + { + if(IosLoader::IsWaninkokoIOS() && NandTitles.VersionOf(TITLE_ID(1, IOS_GetVersion())) < 18 && + (DeviceHandler::GetFilesystemType(USB1+part_num) == PART_FS_NTFS || + DeviceHandler::GetFilesystemType(USB1+part_num) == PART_FS_FAT || + DeviceHandler::GetFilesystemType(USB1+part_num) == PART_FS_EXT)) + { + WindowPrompt(tr("Warning:"), tr("You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk."), tr("OK")); + } + + ret = WBFS_OpenPart(part_num); + + Settings.partition = part_num; + Settings.Save(); + } + } + else if(choice == 2) + { + while(ret < 0 || ret == -666) + { + int part_num = SelectPartitionMenu(); + if(part_num >= 0) + ret = FormatingPartition(tr( "Formatting, please wait..." ), part_num); + } + } + + return ret; +} + +/**************************************************************************** + * MountGamePartition + ***************************************************************************/ +int MountGamePartition(bool ShowGUI) +{ + s32 ret = -1; + gprintf("MountGamePartition()\n"); + + s32 wbfsinit = WBFS_Init(WBFS_DEVICE_USB); + + if(Settings.LoaderMode & MODE_WIIGAMES) + { + if (wbfsinit < 0) + { + if(ShowGUI) + ShowError("%s %s", tr( "USB Device not initialized." ), tr("Switching to channel list mode.")); + + Settings.LoaderMode &= ~MODE_WIIGAMES; + Settings.LoaderMode |= MODE_NANDCHANNELS; + } + else + { + if(Settings.MultiplePartitions) + ret = WBFS_OpenAll(); + else if(!Settings.FirstTimeRun) + ret = WBFS_OpenPart(Settings.partition); + + if(ret < 0) + ret = FindGamePartition(); + + if(ret < 0) + { + if(ShowGUI) + PartitionChoice(); + else + Settings.LoaderMode = MODE_NANDCHANNELS; + } + } + } + + gprintf("\tDisc_Init\n"); + ret = Disc_Init(); + if (ret < 0) + { + if(ShowGUI) + WindowPrompt(tr( "Error !" ), tr( "Could not initialize DIP module!" ), tr( "OK" )); + Sys_LoadMenu(); + } + + gprintf("LoadTitlesFromGameTDB\n"); + //! gameList is loaded in GameTitles.LoadTitlesFromGameTDB after cache file load + //! for speed up purpose. If titles override active, load game list here. + if(Settings.titlesOverride) + GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path); + else + gameList.LoadUnfiltered(); + + return ret; +} diff --git a/source/usbloader/MountGamePartition.h b/source/usbloader/MountGamePartition.h new file mode 100644 index 0000000..4782bed --- /dev/null +++ b/source/usbloader/MountGamePartition.h @@ -0,0 +1,6 @@ +#ifndef MOUNTGAMEPARTITION_H_ +#define MOUNTGAMEPARTITION_H_ + +int MountGamePartition(bool ShowGUI = true); + +#endif diff --git a/source/usbloader/NandEmu.cpp b/source/usbloader/NandEmu.cpp new file mode 100644 index 0000000..8e1c260 --- /dev/null +++ b/source/usbloader/NandEmu.cpp @@ -0,0 +1,271 @@ +/***************************************** +* This code is from Mighty Channel 11 +* which is based on the TriiForce source. +* Modifications by Dimok. +*****************************************/ +#include +#include +#include +#include + +#include "system/IosLoader.h" +#include "utils/tools.h" +#include "gecko.h" +#include "NandEmu.h" + +/* 'NAND Device' structure */ +typedef struct { + /* Device name */ + const char *name; + + /* Mode value */ + u32 mode; + + /* Un/mount command */ + u32 mountCmd; + u32 umountCmd; +} nandDevice; + +static nandDevice ndevList[] = +{ + { "Disable", 0, 0x00, 0x00 }, + { "SD/SDHC Card", 1, 0xF0, 0xF1 }, + { "USB 2.0 Mass Storage Device", 2, 0xF2, 0xF3 }, +}; + +/* Buffer */ +static const char fs[] ATTRIBUTE_ALIGN(32) = "/dev/fs"; +static const char fat[] ATTRIBUTE_ALIGN(32) = "fat"; +static u32 inbuf[8] ATTRIBUTE_ALIGN(32); +static u32 partition ATTRIBUTE_ALIGN(32) = 0; +static u32 mode ATTRIBUTE_ALIGN(32) = 0; +static char path[32] ATTRIBUTE_ALIGN(32) = "\0"; +static int fullmode = 0; +static int mounted = 0; + +static s32 Nand_Mount(nandDevice *dev) +{ + s32 fd, ret; + u32 inlen = 0; + ioctlv *vector = NULL; + int rev = IOS_GetRevision(); + + /* Open FAT module */ + fd = IOS_Open(fat, 0); + if (fd < 0) + return fd; + + + if(rev >= 21 && rev != 65280) // stub version from nintendo + { + // NOTE: + // The official cIOSX rev21 by Waninkoko ignores the partition argument + // and the nand is always expected to be on the 1st partition. + // However this way earlier d2x betas having revision 21 take in + // consideration the partition argument. + inlen = 1; + + /* Allocate memory */ + vector = (ioctlv *) memalign(32, sizeof(ioctlv)); + if(vector == NULL) + { + /* Close FAT module */ + IOS_Close(fd); + return -2; + } + + vector[0].data = &partition; + vector[0].len = sizeof(u32); + } + /* Mount device */ + ret = IOS_Ioctlv(fd, dev->mountCmd, inlen, 0, vector); + + /* Close FAT module */ + IOS_Close(fd); + + /* Free memory */ + free(vector); + + return ret; +} + +static s32 Nand_Unmount(nandDevice *dev) +{ + s32 fd, ret; + + // Open FAT module + fd = IOS_Open(fat, 0); + if (fd < 0) + return fd; + + // Unmount device + ret = IOS_Ioctlv(fd, dev->umountCmd, 0, 0, NULL); + + // Close FAT module + IOS_Close(fd); + + return ret; +} + +static s32 Nand_Enable(nandDevice *dev) +{ + s32 fd, ret; + ioctlv *vector = NULL; + int rev = IOS_GetRevision(); + + // Open /dev/fs + fd = IOS_Open(fs, 0); + if (fd < 0) + return fd; + + if (IOS_GetRevision() >= 18) + { + //FULL NAND emulation since rev18 + //needed for reading images on triiforce mrc folder using ISFS commands + mode = dev->mode | fullmode; + } + else + { + mode = dev->mode; + } + + if(rev >= 21 && rev != 65280) // stub version from nintendo + { + // NOTE: + // The official cIOSX rev21 by Waninkoko provides an undocumented feature + // to set nand path when mounting the device. + // This feature has been discovered during d2x development. + + /* Allocate memory */ + vector = (ioctlv *)memalign(32, sizeof(ioctlv)*2); + if(vector == NULL) + { + /* Close FAT module */ + IOS_Close(fd); + return -2; + } + + vector[0].data = &mode; + vector[0].len = sizeof(u32); + vector[1].data = path; + vector[1].len = sizeof(path); + + ret = IOS_Ioctlv(fd, 100, 2, 0, vector); + + /* Free memory */ + free(vector); + } + else + { + memset(inbuf, 0, sizeof(inbuf)); + inbuf[0] = dev->mode; + ret = IOS_Ioctl(fd, 100, inbuf, sizeof(inbuf), NULL, 0); + } + + // Close /dev/fs + IOS_Close(fd); + + return ret; +} + +static s32 Nand_Disable(void) +{ + s32 fd, ret; + + // Open /dev/fs + fd = IOS_Open(fs, 0); + if (fd < 0) + return fd; + + // Set input buffer + mode = 0; + + // Disable NAND emulator + ret = IOS_Ioctl(fd, 100, &mode, sizeof(mode), NULL, 0); + + // Close /dev/fs + IOS_Close(fd); + + return ret; +} + +s32 Enable_Emu(int selection) +{ + if(!IosLoader::IsD2X() && IOS_GetRevision() < 17) + return -1; + + if(mounted != 0) + return -1; + + s32 ret; + nandDevice *ndev = NULL; + ndev = &ndevList[selection]; + + ret = Nand_Mount(ndev); + if (ret < 0) + { + gprintf(" ERROR Mount! (ret = %d)\n", ret); + return ret; + + } + + ret = Nand_Enable(ndev); + if (ret < 0) + { + gprintf(" ERROR Enable! (ret = %d)\n", ret); + return ret; + } + mounted = selection; + return 0; +} + +s32 Disable_Emu() +{ + if(!IosLoader::IsD2X() && IOS_GetRevision() < 17) + return -1; + + if(mounted==0) + return 0; + + nandDevice *ndev = NULL; + ndev = &ndevList[mounted]; + + Nand_Disable(); + Nand_Unmount(ndev); + + mounted = 0; + + return 0; +} + +void Set_Partition(int p) +{ + partition = p; +} + +void Set_Path(const char* p) +{ + int i = 0; + + while(p[i] != '\0' && i < 31) + { + path[i] = p[i]; + i++; + } + while(path[i-1] == '/') + { + path[i-1] = '\0'; + --i; + } + path[i] = '\0'; +} + +void Set_FullMode(int fm) +{ + fullmode = fm ? 0x100 : 0; +} + +const char* Get_Path(void) +{ + return path; +} diff --git a/source/usbloader/NandEmu.h b/source/usbloader/NandEmu.h new file mode 100644 index 0000000..a53cb4c --- /dev/null +++ b/source/usbloader/NandEmu.h @@ -0,0 +1,16 @@ +#ifndef _NAND_EMU_H_ +#define _NAND_EMU_H_ + +#define REAL_NAND 0 +#define EMU_SD 1 +#define EMU_USB 2 + +/* Prototypes */ +s32 Enable_Emu(int selection); +s32 Disable_Emu(); +void Set_Partition(int); +void Set_Path(const char*); +void Set_FullMode(int); +const char* Get_Path(void); + +#endif diff --git a/source/usbloader/SavePath.cpp b/source/usbloader/SavePath.cpp new file mode 100644 index 0000000..6dc151c --- /dev/null +++ b/source/usbloader/SavePath.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** + * Copyright (C) 2011 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include "settings/CSettings.h" +#include "usbloader/disc.h" +#include "usbloader/wbfs.h" +#include "FileOperations/fileops.h" +#include "gecko.h" + +void CreateTitleTMD(const char *path, const struct discHdr *hdr) +{ + wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) hdr->id); + if (!disc) + return; + + wiidisc_t *wdisc = wd_open_disc((s32(*)(void *, u32, u32, void *)) wbfs_disc_read, disc); + if (!wdisc) + { + WBFS_CloseDisc(disc); + return; + } + + u8 *titleTMD = wd_extract_file(wdisc, ONLY_GAME_PARTITION, (char *) "TMD"); + int tmd_size = wdisc->extracted_size; + + wd_close_disc(wdisc); + WBFS_CloseDisc(disc); + + if(!titleTMD) + return; + + FILE *f = fopen(path, "wb"); + if(f) + { + fwrite(titleTMD, 1, tmd_size, f); + fclose(f); + gprintf("Written Game Title TDM to: %s\n", path); + } + + free(titleTMD); +} + +static void CreateNandPath(const char *path) +{ + if(CheckFile(path)) + return; + + gprintf("Creating Nand Path: %s\n", path); + CreateSubfolder(path); +} + +void CreateSavePath(const struct discHdr *hdr, const char *NandEmuPath) +{ + char nandPath[512]; + + snprintf(nandPath, sizeof(nandPath), "%s/import", NandEmuPath); + CreateNandPath(nandPath); + + snprintf(nandPath, sizeof(nandPath), "%s/meta", NandEmuPath); + CreateNandPath(nandPath); + + snprintf(nandPath, sizeof(nandPath), "%s/shared1", NandEmuPath); + CreateNandPath(nandPath); + + snprintf(nandPath, sizeof(nandPath), "%s/shared2", NandEmuPath); + CreateNandPath(nandPath); + + snprintf(nandPath, sizeof(nandPath), "%s/sys", NandEmuPath); + CreateNandPath(nandPath); + + snprintf(nandPath, sizeof(nandPath), "%s/ticket", NandEmuPath); + CreateNandPath(nandPath); + + snprintf(nandPath, sizeof(nandPath), "%s/tmp", NandEmuPath); + CreateNandPath(nandPath); + + const char *titlePath = "title/00010000"; + + if( memcmp(hdr->id, "RGWX41", 6) == 0 || memcmp(hdr->id, "RGWP41", 6) == 0 || + memcmp(hdr->id, "RGWJ41", 6) == 0 || memcmp(hdr->id, "RGWE41", 6) == 0) + { + titlePath = "title/00010004"; + } + + if(hdr->type == TYPE_GAME_NANDCHAN || hdr->type == TYPE_GAME_EMUNANDCHAN) + titlePath = "title/00010001"; + + snprintf(nandPath, sizeof(nandPath), "%s/%s/%02x%02x%02x%02x/data", NandEmuPath, titlePath, hdr->id[0], hdr->id[1], hdr->id[2], hdr->id[3]); + CreateNandPath(nandPath); + + snprintf(nandPath, sizeof(nandPath), "%s/%s/%02x%02x%02x%02x/content", NandEmuPath, titlePath, hdr->id[0], hdr->id[1], hdr->id[2], hdr->id[3]); + CreateNandPath(nandPath); + + strcat(nandPath, "/title.tmd"); + if(!CheckFile(nandPath)) + CreateTitleTMD(nandPath, hdr); +} diff --git a/source/usbloader/SavePath.h b/source/usbloader/SavePath.h new file mode 100644 index 0000000..fa6aedb --- /dev/null +++ b/source/usbloader/SavePath.h @@ -0,0 +1,9 @@ +#ifndef SAVEPATH_H_ +#define SAVEPATH_H_ + +#include "usbloader/disc.h" + +void CreateTitleTMD(const char *path, const struct discHdr *hdr); +void CreateSavePath(const struct discHdr *hdr, const char *NandEmuPath); + +#endif diff --git a/source/usbloader/WDMFile.cpp b/source/usbloader/WDMFile.cpp new file mode 100644 index 0000000..4c54158 --- /dev/null +++ b/source/usbloader/WDMFile.cpp @@ -0,0 +1,75 @@ +#include +#include +#include "WDMFile.hpp" + +static inline int GetNumber(const char * line) +{ + while(*line == ' ') line++; + + if(line[0] == '0' && (line[1] == 'x' || line[1] == 'X')) + return strtol(line, 0, 16); + else + return strtol(line, 0, 10); +} + +WDMFile::WDMFile(const char * path) +{ + FILE * file = fopen(path, "rb"); + if(!file) + return; + + char line[255]; + int entry_number = 0; + int counter = 0; + WDMEntry Entry; + + while (fgets(line, sizeof(line), file)) + { + if(line[0] == '#' || line[0] == '\0') + continue; + + entry_number++; + + if(entry_number < 3) + continue; + + if(counter == 0) + { + int strlength = strlen(line); + while(strlength > 0 && (line[strlength-1] == '\n' || line[strlength-1] == '\r' || line[strlength-1] == ' ')) + { + line[strlength-1] = '\0'; + strlength--; + } + + Entry.ReplaceName = line; + } + else if(counter == 1) + { + int strlength = strlen(line); + while(strlength > 0 && (line[strlength-1] == '\n' || line[strlength-1] == '\r' || line[strlength-1] == ' ')) + { + line[strlength-1] = '\0'; + strlength--; + } + + Entry.DolName = line; + } + else if(counter == 2) + { + Entry.Parameter = GetNumber(line); + WDMEntries.push_back(Entry); + } + else if(counter == 3) + { + //This is actually the place where submenus are described + //But we skip it because its never used + counter = 0; + continue; + } + + counter++; + } + + fclose(file); +} diff --git a/source/usbloader/WDMFile.hpp b/source/usbloader/WDMFile.hpp new file mode 100644 index 0000000..5e0a876 --- /dev/null +++ b/source/usbloader/WDMFile.hpp @@ -0,0 +1,30 @@ +#ifndef WDMFILE_HPP_ +#define WDMFILE_HPP_ + +#include +#include +#include +#include + +using namespace std; + +class WDMFile +{ + public: + WDMFile(const char * filepath); + const char * GetDolName(int pos) const { if(pos >= 0 && pos < (int) WDMEntries.size()) return WDMEntries[pos].DolName.c_str(); else return NULL; }; + const char * GetReplaceName(int pos) const { if(pos >= 0 && pos < (int) WDMEntries.size()) return WDMEntries[pos].ReplaceName.c_str(); else return NULL; }; + int GetParameter(int pos) const { if(pos >= 0 && pos < (int) WDMEntries.size()) return WDMEntries[pos].Parameter; else return 0; }; + int size() const { return WDMEntries.size(); }; + private: + struct WDMEntry + { + string DolName; + string ReplaceName; + int Parameter; + }; + + vector WDMEntries; +}; + +#endif diff --git a/source/usbloader/alternatedol.c b/source/usbloader/alternatedol.c new file mode 100644 index 0000000..bf8d7d2 --- /dev/null +++ b/source/usbloader/alternatedol.c @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include + +#include "patches/gamepatches.h" +#include "apploader.h" +#include "wdvd.h" +#include "fstfile.h" + +typedef struct _dolheader +{ + u32 text_pos[7]; + u32 data_pos[11]; + u32 text_start[7]; + u32 data_start[11]; + u32 text_size[7]; + u32 data_size[11]; + u32 bss_start; + u32 bss_size; + u32 entry_point; +} dolheader; + +static bool Remove_001_Protection(void *Address, int Size) +{ + u8 SearchPattern[16] = { 0x40, 0x82, 0x00, 0x0C, 0x38, 0x60, 0x00, 0x01, 0x48, 0x00, 0x02, 0x44, 0x38, 0x61, 0x00, 0x18 }; + u8 PatchData[16] = { 0x40, 0x82, 0x00, 0x04, 0x38, 0x60, 0x00, 0x01, 0x48, 0x00, 0x02, 0x44, 0x38, 0x61, 0x00, 0x18 }; + + void *Addr = Address; + void *Addr_end = Address + Size; + + while (Addr <= Addr_end - sizeof(SearchPattern)) + { + if (memcmp(Addr, SearchPattern, sizeof(SearchPattern)) == 0) + { + memcpy(Addr, PatchData, sizeof(PatchData)); + return true; + } + Addr += 4; + } + return false; +} + +bool Load_Dol(void **buffer, int* dollen, const char * filepath) +{ + int ret; + FILE* file; + void* dol_buffer; + + char fullpath[200]; + char gameidbuffer6[7]; + memset(gameidbuffer6, 0, 7); + memcpy(gameidbuffer6, (char*) 0x80000000, 6); + snprintf(fullpath, 200, "%s%s.dol", filepath, gameidbuffer6); + + file = fopen(fullpath, "rb"); + if (file == NULL) + { + fclose(file); + return false; + } + + int filesize; + fseek(file, 0, SEEK_END); + filesize = ftell(file); + fseek(file, 0, SEEK_SET); + + dol_buffer = malloc(filesize); + if (dol_buffer == NULL) + { + fclose(file); + return false; + } + ret = fread(dol_buffer, 1, filesize, file); + if (ret != filesize) + { + free(dol_buffer); + fclose(file); + return false; + } + fclose(file); + + *buffer = dol_buffer; + *dollen = filesize; + return true; +} + +u32 load_dol_image(void *dolstart) +{ + if (!dolstart) + return 0; + + u32 i; + dolheader *dolfile = (dolheader *) dolstart; + + for (i = 0; i < 7; i++) + { + if ((!dolfile->text_size[i]) || (dolfile->text_start[i] < 0x100)) continue; + + memmove((void *) dolfile->text_start[i], dolstart + dolfile->text_pos[i], dolfile->text_size[i]); + RegisterDOL((u8 *) dolfile->text_start[i], dolfile->text_size[i]); + Remove_001_Protection((void *) dolfile->data_start[i], dolfile->data_size[i]); + DCFlushRange((void *) dolfile->data_start[i], dolfile->data_size[i]); + ICInvalidateRange((void *) dolfile->text_start[i], dolfile->text_size[i]); + } + + for (i = 0; i < 11; i++) + { + if ((!dolfile->data_size[i]) || (dolfile->data_start[i] < 0x100)) continue; + + memmove((void *) dolfile->data_start[i], dolstart + dolfile->data_pos[i], dolfile->data_size[i]); + RegisterDOL((u8 *) dolfile->data_start[i], dolfile->data_size[i]); + Remove_001_Protection((void *) dolfile->data_start[i], dolfile->data_size[i]); + DCFlushRange((void *) dolfile->data_start[i], dolfile->data_size[i]); + } + + return dolfile->entry_point; +} + +u32 Load_Dol_from_disc(u32 offset) +{ + s32 ret; + dolheader * dolfile; + u8 * buffer; + u32 pos, size; + u32 i; + u32 entrypoint; + u64 doloffset = ((u64) offset) << 2; + + dolfile = (dolheader *) memalign(32, sizeof(dolheader)); + if (dolfile == NULL) + return 0; + + memset(dolfile, 0, sizeof(dolheader)); + + ret = WDVD_Read(dolfile, sizeof(dolheader), doloffset); + if(ret < 0) + { + free(dolfile); + return 0; + } + + entrypoint = dolfile->entry_point; + if (entrypoint == 0) + { + free(dolfile); + return 0; + } + + for (i = 0; i < 7; ++i) + { + if ((!dolfile->text_size[i]) || (dolfile->text_start[i] < 0x100)) continue; + + buffer = (u8 *) dolfile->text_start[i]; + size = dolfile->text_size[i]; + pos = dolfile->text_pos[i]; + + ret = WDVD_Read(buffer, size, doloffset+pos); + if(ret < 0) + { + free(dolfile); + return 0; + } + + RegisterDOL((u8 *) buffer, size); + Remove_001_Protection(buffer, size); + DCFlushRange(buffer, size); + ICInvalidateRange(buffer, size); + } + + for (i = 0; i < 11; ++i) + { + if ((!dolfile->data_size[i]) || (dolfile->data_start[i] < 0x100)) continue; + + buffer = (u8 *) dolfile->data_start[i]; + size = dolfile->data_size[i]; + pos = dolfile->data_pos[i]; + + ret = WDVD_Read(buffer, size, doloffset+pos); + if(ret < 0) + { + free(dolfile); + return 0; + } + + RegisterDOL((u8 *) buffer, size); + Remove_001_Protection(buffer, size); + DCFlushRange(buffer, size); + } + + free(dolfile); + + return entrypoint; + +} diff --git a/source/usbloader/alternatedol.h b/source/usbloader/alternatedol.h new file mode 100644 index 0000000..5195f3d --- /dev/null +++ b/source/usbloader/alternatedol.h @@ -0,0 +1,18 @@ +#ifndef _ALTERNATEDOL_H_ +#define _ALTERNATEDOL_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* not the full path is needed here, the path where the dol is */ +bool Load_Dol(void **buffer, int* dollen, const char * filepath); +u32 load_dol_image(void *dolstart); +u32 Load_Dol_from_disc(u32 offset); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/usbloader/apploader.c b/source/usbloader/apploader.c new file mode 100644 index 0000000..d48a536 --- /dev/null +++ b/source/usbloader/apploader.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include + +#include "apploader.h" +#include "wdvd.h" +#include "wpad.h" +#include "disc.h" +#include "alternatedol.h" +#include "fstfile.h" +#include "gecko.h" +#include "patches/gamepatches.h" +#include "patches/wip.h" +#include "settings/SettingsEnums.h" + +/* Apploader function pointers */ +typedef int (*app_main)(void **dst, int *size, int *offset); +typedef void (*app_init)(void(*report)(const char *fmt, ...)); +typedef void *(*app_final)(); +typedef void (*app_entry)(void(**init)(void(*report)(const char *fmt, ...)), int(**main)(), void *(**final)()); + +/* Apploader pointers */ +static u8 *appldr = (u8 *) 0x81200000; + +/* Constants */ +#define APPLDR_OFFSET 0x2440 + +/* Variables */ +static u32 buffer[0x20] ATTRIBUTE_ALIGN( 32 ); + +s32 Apploader_Run(entry_point *entry, char * dolpath, u8 alternatedol, u32 alternatedoloffset) +{ + app_entry appldr_entry; + app_init appldr_init; + app_main appldr_main; + app_final appldr_final; + + u32 appldr_len; + s32 ret; + gprintf("\nApploader_Run() started\n"); + + /* Read apploader header */ + ret = WDVD_Read(buffer, 0x20, APPLDR_OFFSET); + if (ret < 0) return ret; + + /* Calculate apploader length */ + appldr_len = buffer[5] + buffer[6]; + + /* Read apploader code */ + ret = WDVD_Read(appldr, appldr_len, APPLDR_OFFSET + 0x20); + if (ret < 0) return ret; + + /* Set apploader entry function */ + appldr_entry = (app_entry) buffer[4]; + + /* Call apploader entry */ + appldr_entry(&appldr_init, &appldr_main, &appldr_final); + + /* Initialize apploader */ + appldr_init(gprintf); + + for (;;) + { + void *dst = NULL; + int len = 0, offset = 0; + + /* Run apploader main function */ + ret = appldr_main(&dst, &len, &offset); + if (!ret) break; + + /* Read data from DVD */ + WDVD_Read(dst, len, (u64) (offset << 2)); + + RegisterDOL((u8 *) dst, len); + + DCFlushRange(dst, len); + } + + *entry = appldr_final(); + + /** Load alternate dol if set **/ + if (alternatedol == ALT_DOL_FROM_SD_USB) + { + ClearDOLList(); + wip_reset_counter(); + void *dolbuffer = NULL; + int dollen = 0; + + bool dolloaded = Load_Dol(&dolbuffer, &dollen, dolpath); + if (dolloaded) + *entry = (entry_point) load_dol_image(dolbuffer); + + if (dolbuffer) free(dolbuffer); + } + else if (alternatedol == ALT_DOL_FROM_GAME && alternatedoloffset != 0) + { + ClearDOLList(); + wip_reset_counter(); + FST_ENTRY *fst = (FST_ENTRY *) *(u32 *) 0x80000038; + + //! Check if it's inside the limits + if(alternatedoloffset >= fst[0].filelen) + return 0; + + *entry = (entry_point) Load_Dol_from_disc(fst[alternatedoloffset].fileoffset); + } + + return 0; +} diff --git a/source/usbloader/apploader.h b/source/usbloader/apploader.h new file mode 100644 index 0000000..867b70f --- /dev/null +++ b/source/usbloader/apploader.h @@ -0,0 +1,19 @@ +#ifndef _APPLOADER_H_ +#define _APPLOADER_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Entry point */ + typedef void (*entry_point)(void); + + /* Prototypes */ + s32 Apploader_Run(entry_point *entry, char * dolpath, u8 alternatedol, u32 alternatedoloffset); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/usbloader/disc.c b/source/usbloader/disc.c new file mode 100644 index 0000000..e035007 --- /dev/null +++ b/source/usbloader/disc.c @@ -0,0 +1,526 @@ +#include +#include +#include +#include +#include + +#include "patches/gamepatches.h" +#include "patches/wip.h" +#include "apploader.h" +#include "disc.h" +#include "video.h" +#include "wdvd.h" +#include "frag.h" +#include "alternatedol.h" +#include "memory/memory.h" +#include "wbfs.h" +#include "settings/SettingsEnums.h" +#include "GameCube/DML_Config.h" +#include "GameCube/NIN_Config.h" +#include "gecko.h" + +// Global app entry point +extern u32 AppEntrypoint; + +/* Constants */ +#define PTABLE_OFFSET 0x40000 +#define WII_MAGIC 0x5D1C9EA3 + +/* Disc pointers */ +static u32 *buffer = (u32 *) 0x93000000; +static u8 *diskid = (u8 *) Disc_ID; +static u32 rmode_reg = 0; +GXRModeObj *rmode = NULL; + +void Disc_SetLowMem(void) +{ + /* Setup low memory */ + *Sys_Magic = 0x0D15EA5E; // Standard Boot Code + *Sys_Version = 0x00000001; // Version + *Arena_L = 0x00000000; // Arena Low + *BI2 = 0x817E5480; // BI2 + *Bus_Speed = 0x0E7BE2C0; // Console Bus Speed + *CPU_Speed = 0x2B73A840; // Console CPU Speed + + /* Setup low memory */ + *Assembler = 0x38A00040; // Assembler + *(u32 *) 0x800000E4 = 0x80431A80; // OS_Thread + *Dev_Debugger = 0x81800000; // Dev Debugger Monitor Address + *Simulated_Mem = 0x01800000; // Simulated Memory Size + *(vu32 *) 0xCD00643C = 0x00000000; // 32Mhz on Bus + + int iosVer = IOS_GetVersion(); + if(iosVer != 222 && iosVer != 223 && iosVer != 224 && iosVer != 225 && IOS_GetRevision() >= 18) + *GameID_Address = 0x80000000; // Game ID Address + + /* Copy disc ID */ + memcpy((void *) Online_Check, (void *) Disc_ID, 4); +} + +void Disc_SelectVMode(u8 videoselected, bool devolution, u32 *dml_VideoMode, u32 *nin_VideoMode) +{ + rmode = VIDEO_GetPreferredMode(0); + + /* Get video mode configuration */ + bool progressive = (CONF_GetProgressiveScan() > 0) && VIDEO_HaveComponentCable(); + bool PAL60 = CONF_GetEuRGB60() > 0; + u32 tvmode = CONF_GetVideo(); + + + /* Select video mode register: GameCube Devolution only */ + if(devolution) + { + if (diskid[3] =='E' || diskid[3] =='J') + { + if (CONF_GetVideo() == CONF_VIDEO_PAL) + { + rmode_reg = VI_EURGB60; + rmode = &TVEurgb60Hz480IntDf; + } + else + { + rmode_reg = VI_NTSC; + rmode = &TVNtsc480IntDf; + } + } + else + { + rmode_reg = VI_PAL; + rmode = &TVPal528IntDf; + } + return; + } + + /* Select video mode register: Wii and GameCube MIOS */ + switch (tvmode) + { + case CONF_VIDEO_PAL: + rmode_reg = PAL60 ? VI_EURGB60 : VI_PAL; + rmode = progressive ? &TVEurgb60Hz480Prog : (PAL60 ? &TVEurgb60Hz480IntDf : &TVPal528IntDf); + if(dml_VideoMode) *dml_VideoMode = progressive ? DML_VID_FORCE_PROG : (PAL60 ? DML_VID_FORCE_PAL60 : DML_VID_FORCE_PAL50); + if(nin_VideoMode) *nin_VideoMode = progressive ? NIN_VID_FORCE_PAL60 | NIN_VID_PROG : (PAL60 ? NIN_VID_FORCE_PAL60 : NIN_VID_FORCE_PAL50); + break; + + case CONF_VIDEO_MPAL: + rmode_reg = VI_MPAL; + rmode = progressive ? &TVEurgb60Hz480Prog : &TVMpal480IntDf; + if(nin_VideoMode) *nin_VideoMode = progressive ? NIN_VID_FORCE_MPAL | NIN_VID_PROG : NIN_VID_FORCE_MPAL; + break; + + case CONF_VIDEO_NTSC: + rmode_reg = VI_NTSC; + rmode = progressive ? &TVNtsc480Prog : &TVNtsc480IntDf; + if(dml_VideoMode) *dml_VideoMode = progressive ? DML_VID_FORCE_PROG : DML_VID_FORCE_NTSC; + if(nin_VideoMode) *nin_VideoMode = progressive ? NIN_VID_FORCE_NTSC | NIN_VID_PROG : NIN_VID_FORCE_NTSC; + break; + } + + switch (videoselected) + { + default: + case VIDEO_MODE_DISCDEFAULT: // DEFAULT (DISC/GAME) + /* Select video mode */ + switch (diskid[3]) + { + // PAL + case 'D': + case 'F': + case 'P': + case 'X': + case 'Y': + rmode_reg = PAL60 ? VI_EURGB60 : VI_PAL; + rmode = progressive ? &TVEurgb60Hz480Prog : (PAL60 ? &TVEurgb60Hz480IntDf : &TVPal528IntDf); + if(dml_VideoMode) *dml_VideoMode = progressive ? DML_VID_FORCE_PROG : (PAL60 ? DML_VID_FORCE_PAL60 : DML_VID_FORCE_PAL50); + if(nin_VideoMode) *nin_VideoMode = progressive ? NIN_VID_FORCE_PAL60 | NIN_VID_PROG : (PAL60 ? NIN_VID_FORCE_PAL60 : NIN_VID_FORCE_PAL50); + break; + // NTSC + case 'E': + case 'J': + rmode_reg = VI_NTSC; + rmode = progressive ? &TVNtsc480Prog : &TVNtsc480IntDf; + if(dml_VideoMode) *dml_VideoMode = progressive ? DML_VID_FORCE_PROG : DML_VID_FORCE_NTSC; + if(nin_VideoMode) *nin_VideoMode = progressive ? NIN_VID_FORCE_NTSC | NIN_VID_PROG : NIN_VID_FORCE_NTSC; + break; + default: + if(dml_VideoMode) *dml_VideoMode = DML_VID_DML_AUTO; + if(nin_VideoMode) *nin_VideoMode = NIN_VID_AUTO; + break; + } + break; + case VIDEO_MODE_PAL50: // PAL50 + rmode = &TVPal528IntDf; + rmode_reg = VI_PAL; + if(dml_VideoMode) *dml_VideoMode = DML_VID_FORCE_PAL50; + if(nin_VideoMode) *nin_VideoMode = NIN_VID_FORCE_PAL50; + break; + case VIDEO_MODE_PAL60: // PAL60 + rmode = &TVEurgb60Hz480IntDf; + rmode_reg = VI_EURGB60; + if(dml_VideoMode) *dml_VideoMode = DML_VID_FORCE_PAL60; + if(nin_VideoMode) *nin_VideoMode = NIN_VID_FORCE_PAL60; + break; + case VIDEO_MODE_NTSC: // NTSC + rmode = &TVNtsc480IntDf; + rmode_reg = VI_NTSC; + if(dml_VideoMode) *dml_VideoMode = DML_VID_FORCE_NTSC; + if(nin_VideoMode) *nin_VideoMode = NIN_VID_FORCE_NTSC; + break; + case VIDEO_MODE_PAL480P: + rmode = &TVEurgb60Hz480Prog; + rmode_reg = VI_EURGB60; + if(dml_VideoMode) *dml_VideoMode = DML_VID_FORCE_PROG | DML_VID_PROG_PATCH; + if(nin_VideoMode) *nin_VideoMode = NIN_VID_FORCE_PAL60 | NIN_VID_PROG; + break; + case VIDEO_MODE_NTSC480P: + rmode = &TVNtsc480Prog; + rmode_reg = VI_NTSC; + if(dml_VideoMode) *dml_VideoMode = DML_VID_FORCE_PROG | DML_VID_PROG_PATCH; + if(nin_VideoMode) *nin_VideoMode = NIN_VID_FORCE_NTSC | NIN_VID_PROG; + break; + case VIDEO_MODE_SYSDEFAULT: // AUTO PATCH TO SYSTEM + break; + } +} + +void Disc_SetVMode(void) +{ + /* Set video mode register */ + *Video_Mode = rmode_reg; + DCFlushRange((void *) Video_Mode, 4); + + /* Set video mode */ + if (rmode != NULL) + VIDEO_Configure(rmode); + + /* Setup video */ + VIDEO_SetBlack(TRUE); + VIDEO_Flush(); + VIDEO_WaitVSync(); + if (rmode->viTVMode & VI_NON_INTERLACE) + VIDEO_WaitVSync(); + else while(VIDEO_GetNextField()) + VIDEO_WaitVSync(); +} + +void __Disc_SetTime(void) +{ + /* Extern */ + extern void settime(u64); + + /* Set proper time */ + settime(secs_to_ticks( time( NULL ) - 946684800 )); +} + +s32 Disc_FindPartition(u64 *outbuf) +{ + u64 offset = 0, table_offset = 0; + + u32 cnt, nb_partitions; + s32 ret; + + /* Read partition info */ + ret = WDVD_UnencryptedRead(buffer, 0x20, PTABLE_OFFSET); + if (ret < 0) return ret; + + /* Get data */ + nb_partitions = buffer[0]; + table_offset = buffer[1] << 2; + + /* Read partition table */ + ret = WDVD_UnencryptedRead(buffer, 0x20, table_offset); + if (ret < 0) return ret; + + /* Find game partition */ + for (cnt = 0; cnt < nb_partitions; cnt++) + { + u32 type = buffer[cnt * 2 + 1]; + + /* Game partition */ + if (!type) offset = buffer[cnt * 2] << 2; + } + + /* No game partition found */ + if (!offset) return -1; + + /* Set output buffer */ + *outbuf = offset; + + return 0; +} + +s32 Disc_Init(void) +{ + /* Init DVD subsystem */ + return WDVD_Init(); +} + +s32 Disc_Open(void) +{ + s32 ret; + + /* Reset drive */ + ret = WDVD_Reset(); + if (ret < 0) return ret; + + /* Read disc ID */ + return WDVD_ReadDiskId(diskid); +} + +s32 Disc_Wait(void) +{ + u32 cover = 0; + s32 ret; + + /* Wait for disc */ + while (!(cover & 0x2)) + { + /* Get cover status */ + ret = WDVD_GetCoverStatus(&cover); + if (ret < 0) return ret; + } + + return 0; +} + +s32 Disc_SetUSB(const u8 *id) +{ + /* Set USB mode */ + return WDVD_SetUSBMode((u8 *) id, -1); +} + +s32 Disc_ReadHeader(void *outbuf) +{ + /* Read disc header */ + return WDVD_UnencryptedRead(outbuf, sizeof(struct discHdr), 0); +} + +s32 Disc_IsWii(void) +{ + struct discHdr *header = (struct discHdr *) buffer; + + s32 ret; + + /* Read disc header */ + ret = Disc_ReadHeader(header); + if (ret < 0) return ret; + + /* Check magic word */ + if (header->magic != WII_MAGIC) return -1; + + return 0; +} + +s32 Disc_Mount(struct discHdr *header) +{ + if(!header) + return -1; + + gprintf("\nDiscMount() "); + s32 ret; + + u8 tmpBuff[0x60]; + memcpy(tmpBuff, diskid, 0x60); // Make a backup of the first 96 bytes at 0x80000000 + + Disc_SetUSB(NULL); + + ret = WDVD_Reset(); + if(ret < 0) + return ret; + + ret = WDVD_ReadDiskId(diskid); + if(ret < 0) + return ret; + + ret = WDVD_UnencryptedRead(diskid, 0x60, 0x00); + if(ret < 0) + return ret; + + memcpy(header, diskid, sizeof(struct discHdr)); + memcpy(diskid, tmpBuff, 0x60); // Put the backup back, or games won't load + + if(header->magic == 0x5D1C9EA3) + { + header->type = TYPE_GAME_WII_DISC; + return 0; + } + + if(header->gc_magic == 0xC2339F3D) + { + header->type = TYPE_GAME_GC_DISC; + return 0; + } + + return -1; +} + +s32 Disc_JumpToEntrypoint(s32 hooktype, u32 dolparameter) +{ + /* Set an appropiate video mode */ + Disc_SetVMode(); + + /* Set time */ + __Disc_SetTime(); + + /* Shutdown IOS subsystems */ + extern void __exception_closeall(); + u32 level = IRQ_Disable(); + __IOS_ShutdownSubsystems(); + __exception_closeall(); + + /* Originally from tueidj - taken from NeoGamme (thx) */ + *(vu32*)0xCC003024 = dolparameter != 0 ? dolparameter : 1; + + if(AppEntrypoint == 0x3400) + { + if(hooktype) + { + asm volatile ( + "lis %r3, returnpoint@h\n" + "ori %r3, %r3, returnpoint@l\n" + "mtlr %r3\n" + "lis %r3, 0x8000\n" + "ori %r3, %r3, 0x18A8\n" + "nop\n" + "mtctr %r3\n" + "bctr\n" + "returnpoint:\n" + "bl DCDisable\n" + "bl ICDisable\n" + "li %r3, 0\n" + "mtsrr1 %r3\n" + "lis %r4, AppEntrypoint@h\n" + "ori %r4,%r4,AppEntrypoint@l\n" + "lwz %r4, 0(%r4)\n" + "mtsrr0 %r4\n" + "rfi\n" + ); + } + else + { + asm volatile ( + "isync\n" + "lis %r3, AppEntrypoint@h\n" + "ori %r3, %r3, AppEntrypoint@l\n" + "lwz %r3, 0(%r3)\n" + "mtsrr0 %r3\n" + "mfmsr %r3\n" + "li %r4, 0x30\n" + "andc %r3, %r3, %r4\n" + "mtsrr1 %r3\n" + "rfi\n" + ); + } + } + else if (hooktype) + { + asm volatile ( + "lis %r3, AppEntrypoint@h\n" + "ori %r3, %r3, AppEntrypoint@l\n" + "lwz %r3, 0(%r3)\n" + "mtlr %r3\n" + "lis %r3, 0x8000\n" + "ori %r3, %r3, 0x18A8\n" + "nop\n" + "mtctr %r3\n" + "bctr\n" + ); + } + else + { + asm volatile ( + "lis %r3, AppEntrypoint@h\n" + "ori %r3, %r3, AppEntrypoint@l\n" + "lwz %r3, 0(%r3)\n" + "mtlr %r3\n" + "blr\n" + ); + } + + IRQ_Restore(level); + + return 0; +} + +void PatchCountryStrings(void *Address, int Size) +{ + u8 SearchPattern[4] = { 0x00, 0x00, 0x00, 0x00 }; + u8 PatchData[4] = { 0x00, 0x00, 0x00, 0x00 }; + u8 *Addr = (u8*) Address; + + int wiiregion = CONF_GetRegion(); + + switch (wiiregion) + { + case CONF_REGION_JP: + SearchPattern[0] = 0x00; + SearchPattern[1] = 0x4A; // J + SearchPattern[2] = 0x50; // P + break; + case CONF_REGION_EU: + SearchPattern[0] = 0x02; + SearchPattern[1] = 0x45; // E + SearchPattern[2] = 0x55; // U + break; + case CONF_REGION_KR: + SearchPattern[0] = 0x04; + SearchPattern[1] = 0x4B; // K + SearchPattern[2] = 0x52; // R + break; + case CONF_REGION_CN: + SearchPattern[0] = 0x05; + SearchPattern[1] = 0x43; // C + SearchPattern[2] = 0x4E; // N + break; + case CONF_REGION_US: + default: + SearchPattern[0] = 0x01; + SearchPattern[1] = 0x55; // U + SearchPattern[2] = 0x53; // S + break; + } + + switch (diskid[3]) + { + case 'J': + PatchData[1] = 0x4A; // J + PatchData[2] = 0x50; // P + break; + + case 'D': + case 'F': + case 'P': + case 'X': + case 'Y': + PatchData[1] = 0x45; // E + PatchData[2] = 0x55; // U + break; + + case 'E': + default: + PatchData[1] = 0x55; // U + PatchData[2] = 0x53; // S + break; + } + + while (Size >= 4) + { + if (Addr[0] == SearchPattern[0] && Addr[1] == SearchPattern[1] && Addr[2] == SearchPattern[2] && Addr[3] + == SearchPattern[3]) + { + //*Addr = PatchData[0]; + Addr += 1; + *Addr = PatchData[1]; + Addr += 1; + *Addr = PatchData[2]; + Addr += 1; + //*Addr = PatchData[3]; + Addr += 1; + Size -= 4; + } + else + { + Addr += 4; + Size -= 4; + } + } +} diff --git a/source/usbloader/disc.h b/source/usbloader/disc.h new file mode 100644 index 0000000..afb639a --- /dev/null +++ b/source/usbloader/disc.h @@ -0,0 +1,77 @@ +#ifndef _DISC_H_ +#define _DISC_H_ + +#include /* for define ATTRIBUTE_PACKED */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Disc header structure */ + struct discHdr + { + /* Game ID */ + u8 id[6]; + + /* Game Disc number */ + u8 disc_no; + + /* Game version */ + u8 disc_ver; + + /* Audio streaming */ + u8 streaming; + u8 bufsize; + + /* Padding */ + u8 is_ciso; + + /* Unused, on channel list mode this is the full 64 bit tid */ + u64 tid; + + /* Unused, using in loader internally to detect title type */ + u8 type; + + /* rest of unused */ + u8 unused[4]; + + /* Magic word */ + u32 magic; + + /* Padding */ + u32 gc_magic; + + /* Game title */ + char title[64]; + + /* Encryption/Hashing */ + u8 encryption; + u8 h3_verify; + + /* Padding */ + u8 unused3[30]; + } ATTRIBUTE_PACKED; + + /* Prototypes */ + s32 Disc_Init(void); + s32 Disc_Open(void); + s32 Disc_Wait(void); + void Disc_SetLowMem(void); + s32 Disc_SetUSB(const u8 *); + s32 Disc_ReadHeader(void *); + s32 Disc_IsWii(void); + s32 Disc_FindPartition(u64 *outbuf); + s32 Disc_Mount(struct discHdr *header); + void PatchCountryStrings(void *Address, int Size); + void Disc_SelectVMode(u8 videoselected, bool devolution, u32 *dml_VideoMode, u32 *nin_VideoMode); + void Disc_SetVMode(void); + s32 Disc_JumpToEntrypoint(s32 hooktype, u32 dolparameter); + + extern GXRModeObj *rmode; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/usbloader/frag.c b/source/usbloader/frag.c new file mode 100644 index 0000000..a26d6ae --- /dev/null +++ b/source/usbloader/frag.c @@ -0,0 +1,290 @@ +#include +#include +#include +#include +#include + +#include "libs/libwbfs/libwbfs.h" +#include "libs/libfat/fatfile_frag.h" +#include "libs/libntfs/ntfsfile_frag.h" +#include "libs/libext2fs/ext2_frag.h" + +#include "usbloader/wbfs.h" +#include "usbloader/wdvd.h" +#include "usbloader/usbstorage2.h" +#include "frag.h" +#include "sys.h" +#include "gecko.h" + +#define SAFE_FREE(x) if(x) { free(x); x = NULL; } + +static FragList *frag_list = NULL; + +void frag_init(FragList *ff, int maxnum) +{ + memset(ff, 0, sizeof(Fragment) * (maxnum+1)); + ff->maxnum = maxnum; +} + +void frag_dump(FragList *ff) +{ + u32 i; + gprintf("frag list: %d %d 0x%x\n", ff->num, ff->size, ff->size); + for (i=0; inum; i++) { + if (i>10) { + gprintf("...\n"); + break; + } + gprintf(" %d : %8x %8x %8x\n", i, + ff->frag[i].offset, + ff->frag[i].count, + ff->frag[i].sector); + } +} + +int frag_append(void *f, u32 offset, u32 sector, u32 count) +{ + FragList *ff = (FragList *) f; + int n; + if (count) { + n = ff->num - 1; + if (ff->num > 0 + && ff->frag[n].offset + ff->frag[n].count == offset + && ff->frag[n].sector + ff->frag[n].count == sector) + { + // merge + ff->frag[n].count += count; + } + else + { + // add + if (ff->num >= ff->maxnum) { + // too many fragments + return -500; + } + n = ff->num; + ff->frag[n].offset = offset; + ff->frag[n].sector = sector; + ff->frag[n].count = count; + ff->num++; + } + } + ff->size = offset + count; + return 0; +} + +int frag_concat(FragList *ff, FragList *src) +{ + u32 i; + int ret; + u32 size = ff->size; + //printf("concat: %d %d <- %d %d\n", ff->num, ff->size, src->num, src->size); + for (i=0; inum; i++) { + ret = frag_append(ff, size + src->frag[i].offset, + src->frag[i].sector, src->frag[i].count); + if (ret) return ret; + } + ff->size = size + src->size; + //printf("concat: -> %d %d\n", ff->num, ff->size); + return 0; +} + +// in case a sparse block is requested, +// the returned poffset might not be equal to requested offset +// the difference should be filled with 0 +int frag_get(FragList *ff, u32 offset, u32 count, u32 *poffset, u32 *psector, u32 *pcount) +{ + u32 i; + u32 delta; + //printf("frag_get(%u %u)\n", offset, count); + for (i=0; inum; i++) { + if (ff->frag[i].offset <= offset && ff->frag[i].offset + ff->frag[i].count > offset) + { + delta = offset - ff->frag[i].offset; + *poffset = offset; + *psector = ff->frag[i].sector + delta; + *pcount = ff->frag[i].count - delta; + if (*pcount > count) + *pcount = count; + return 0; + } + if (ff->frag[i].offset > offset + && ff->frag[i].offset < offset + count) + { + delta = ff->frag[i].offset - offset; + *poffset = ff->frag[i].offset; + *psector = ff->frag[i].sector; + *pcount = ff->frag[i].count; + count -= delta; + if (*pcount > count) + *pcount = count; + return 0; + } + } + // not found + if (offset + count > ff->size) { + // error: out of range! + return -1; + } + // if inside range, then it must be just sparse, zero filled + // return empty block at the end of requested + *poffset = offset + count; + *psector = 0; + *pcount = 0; + + return 0; +} + +int frag_remap(FragList *ff, FragList *log, FragList *phy) +{ + u32 i; + int ret; + u32 offset; + u32 sector; + u32 count; + u32 delta; + for (i=0; inum; i++) { + delta = 0; + count = 0; + do { + ret = frag_get(phy, + log->frag[i].sector + delta + count, + log->frag[i].count - delta - count, + &offset, §or, &count); + if (ret) return ret; // error + delta = offset - log->frag[i].sector; + ret = frag_append(ff, log->frag[i].offset + delta, sector, count); + if (ret) return ret; // error + } while (count + delta < log->frag[i].count); + } + return 0; +} + +int get_frag_list_for_file(char *fname, u8 *id, const u8 wbfs_part_fs, const u32 lba_offset, const u32 hdd_sector_size) +{ + struct stat st; + FragList *fs = NULL; + FragList *fa = NULL; + FragList *fw = NULL; + int ret; + u32 i, j; + int is_wbfs = 0; + int ret_val = -1; + + if (strcasecmp(strrchr(fname,'.'), ".wbfs") == 0) { + is_wbfs = 1; + } + + fs = malloc(sizeof(FragList)); + fa = malloc(sizeof(FragList)); + fw = malloc(sizeof(FragList)); + + frag_init(fa, MAX_FRAG); + + for (i=0; i<10; i++) { + frag_init(fs, MAX_FRAG); + if (i > 0) { + fname[strlen(fname)-1] = '0' + i; + if (stat(fname, &st) == -1) break; + } + if (wbfs_part_fs == PART_FS_FAT) { + ret = _FAT_get_fragments(fname, &frag_append, fs); + if (ret) { + // don't return failure, let it fallback to old method + //ret_val = ret; + ret_val = 0; + goto out; + } + } else if (wbfs_part_fs == PART_FS_NTFS) { + ret = _NTFS_get_fragments(fname, &frag_append, fs); + if (ret) { + ret_val = ret; + goto out; + } + // offset to start of partition + for (j=0; jnum; j++) { + fs->frag[j].sector += lba_offset; + } + } else if (wbfs_part_fs == PART_FS_EXT) { + ret = _EXT2_get_fragments(fname, &frag_append, fs); + if (ret) { + ret_val = ret; + goto out; + } + // offset to start of partition + for (j=0; jnum; j++) { + fs->frag[j].sector += lba_offset; + } + } else if (wbfs_part_fs == PART_FS_WBFS) { + // if wbfs file format, remap. + wbfs_disc_t *d = WBFS_OpenDisc(id); + if (!d) { ret_val = -4; WBFS_CloseDisc(d); goto out; } + ret = wbfs_get_fragments(d, &frag_append, fs, hdd_sector_size); + WBFS_CloseDisc(d); + if (ret) { ret_val = -5; goto out; } + } + frag_concat(fa, fs); + } + + frag_list = memalign(32, (sizeof(FragList)+31)&(~31)); + frag_init(frag_list, MAX_FRAG); + if (is_wbfs) { + // if wbfs file format, remap. + wbfs_disc_t *d = WBFS_OpenDisc(id); + if (!d) { ret_val = -4; goto out; } + frag_init(fw, MAX_FRAG); + ret = wbfs_get_fragments(d, &frag_append, fw, hdd_sector_size); + if (ret) { ret_val = -5; goto out; } + WBFS_CloseDisc(d); + // DEBUG: frag_list->num = MAX_FRAG-10; // stress test + ret = frag_remap(frag_list, fw, fa); + if (ret) { ret_val = -6; goto out; } + } else { + // .iso does not need remap just copy + memcpy(frag_list, fa, sizeof(FragList)); + } + + ret_val = 0; + +out: + if (ret_val) { + // error + SAFE_FREE(frag_list); + } + SAFE_FREE(fs); + SAFE_FREE(fa); + SAFE_FREE(fw); + + return ret_val; +} + +int get_frag_list(u8 *id) +{ + return WBFS_GetFragList(id); +} + +int set_frag_list(u8 *id) +{ + if (frag_list == NULL) { + return -2; + } + + // (+1 for header which is same size as fragment) + int size = sizeof(Fragment) * (frag_list->num + 1); + + gprintf("Calling WDVD_SetFragList, frag list size %d\n", size); + int ret = WDVD_SetFragList(WBFS_MIN_DEVICE, frag_list, size); + + free(frag_list); + frag_list = NULL; + + if (ret) + return ret; + + // verify id matches + char discid[32] ATTRIBUTE_ALIGN(32); + memset(discid, 0, sizeof(discid)); + ret = WDVD_UnencryptedRead(discid, 32, 0); + gprintf("Reading ID after setting fraglist: %s (expected: %s)\n", discid, id); + return (strncasecmp((char *) id, discid, 6) != 0) ? -3 : 0; +} diff --git a/source/usbloader/frag.h b/source/usbloader/frag.h new file mode 100644 index 0000000..57c7fed --- /dev/null +++ b/source/usbloader/frag.h @@ -0,0 +1,50 @@ +#ifndef _FRAG_H_ +#define _FRAG_H_ +// worst case wbfs fragmentation scenario: +// 9GB (dual layer) / 2mb (wbfs sector size) = 4608 +#define MAX_FRAG 20000 +// max that ehcmodule_frag will allow at the moment is about: +// 40000/4/3-1 = 21844 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gctypes.h" + +typedef struct +{ + u32 offset; // file offset, in sectors unit + u32 sector; + u32 count; +} Fragment; + +typedef struct +{ + u32 size; // num sectors + u32 num; // num fragments + u32 maxnum; + Fragment frag[MAX_FRAG]; +} FragList; + +void frag_init(FragList *ff, int maxnum); +void frag_dump(FragList *ff); +int frag_append(void *ff, u32 offset, u32 sector, u32 count); +int frag_concat(FragList *ff, FragList *src); + +// in case a sparse block is requested, +// the returned poffset might not be equal to requested offset +// the difference should be filled with 0 +int frag_get(FragList *ff, u32 offset, u32 count, u32 *poffset, u32 *psector, u32 *pcount); + +int frag_remap(FragList *ff, FragList *log, FragList *phy); + +int get_frag_list_for_file(char *fname, u8 *id, const u8 wbfs_part_fs, const u32 lba_offset, const u32 hdd_sector_size); +int get_frag_list(u8 *id); +int set_frag_list(u8 *id); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/usbloader/fstfile.c b/source/usbloader/fstfile.c new file mode 100644 index 0000000..16fb930 --- /dev/null +++ b/source/usbloader/fstfile.c @@ -0,0 +1,48 @@ +#include + +#include "fstfile.h" + +char *fstfiles(FST_ENTRY *fst, u32 index) +{ + u32 count = fst[0].filelen; + u32 stringoffset; + if (index < count) + { + stringoffset = *(u32 *) &(fst[index]) % (256 * 256 * 256); + return (char *) ((u32) fst + count * 12 + stringoffset); + } + else + { + return NULL; + } +} + +char *fstfilename(u32 index) +{ + FST_ENTRY *fst = (FST_ENTRY *) *(u32 *) 0x80000038; + u32 count = fst[0].filelen; + u32 stringoffset; + if (index < count) + { + stringoffset = *(u32 *) &(fst[index]) % (256 * 256 * 256); + return (char *) (*(u32 *) 0x80000038 + count * 12 + stringoffset); + } + else + { + return NULL; + } +} + +u32 fstfileoffset(u32 index) +{ + FST_ENTRY *fst = (FST_ENTRY *) *(u32 *) 0x80000038; + u32 count = fst[0].filelen; + if (index < count) + { + return fst[index].fileoffset; + } + else + { + return 0; + } +} diff --git a/source/usbloader/fstfile.h b/source/usbloader/fstfile.h new file mode 100644 index 0000000..5e4350e --- /dev/null +++ b/source/usbloader/fstfile.h @@ -0,0 +1,25 @@ +#ifndef _FSTFILE_H_ +#define _FSTFILE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct + { + u8 filetype; + char name_offset[3]; + u32 fileoffset; + u32 filelen; + }__attribute__( ( packed ) ) FST_ENTRY; + + char *fstfiles(FST_ENTRY *fst, u32 index); + char *fstfilename(u32 index); + u32 fstfileoffset(u32 index); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/usbloader/neek.cpp b/source/usbloader/neek.cpp new file mode 100644 index 0000000..87ae8d4 --- /dev/null +++ b/source/usbloader/neek.cpp @@ -0,0 +1,483 @@ +/**************************************************************************** + * Copyright (C) 2015 Cyan + * + * 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 +#include +#include + +#include "neek.hpp" +#include "memory/mem2.h" +#include "Controls/DeviceHandler.hpp" +#include "FileOperations/fileops.h" +#include "settings/CSettings.h" +#include "sys.h" +#include "gecko.h" + +typedef struct { + u32 hdrsize; + u32 loadersize; + u32 elfsize; + u32 argument; +} ioshdr; + +#define MEM_REG_BASE 0xd8b4000 +#define MEM_PROT (MEM_REG_BASE + 0x20a) +#define TITLE_ID(x,y) (((u64)(x) << 32) | (y)) + +static u32 *kernel = NULL; + +static inline void disable_memory_protection(void) { + write32(MEM_PROT, read32(MEM_PROT) & 0x0000FFFF); +} + +bool neekLoadKernel (const char* nandpath) +{ + gprintf( "NEEK: Loading Kernel.bin... "); + char kernelPath[30]; + if(isWiiU()) + snprintf(kernelPath, sizeof(kernelPath), "%s:/sneek/vwiikernel.bin", DeviceHandler::GetDevicePrefix(nandpath)); + if(!isWiiU() || !CheckFile(kernelPath)) + snprintf(kernelPath, sizeof(kernelPath), "%s:/sneek/kernel.bin", DeviceHandler::GetDevicePrefix(nandpath)); + if(!CheckFile(kernelPath)) + { + gprintf("File not found.\n"); + return false; + } + + FILE *f = NULL; + f = fopen(kernelPath, "rb"); + if(!f) + { + gprintf("Failed loading file %s.\n", kernelPath); + return false; + } + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + rewind(f); + + // Allocate kernel to mem2 + kernel = (u32 *) MEM2_alloc(fsize); + if(!kernel) + { + return false; + } + + fread(kernel, 1, fsize, f); + //((ioshdr*)kernel)->argument = 0x42; // set argument size + DCFlushRange(kernel, fsize); + + gprintf("Loaded to 0x%08x, size: %d\n", kernel, fsize); + gprintf("NEEK: offset memory address: %08x\n", (u32)kernel - 0x80000000); // offset + + fclose(f); + return true; +} + +/* +static void neekClearKernel(void) +{ + if(kernel) + MEM2_free(kernel); + kernel = NULL; +} +*/ + +int neekBoot(void) +{ + gprintf("Booting S/Uneek !!\n"); + if(kernel == NULL) + { + gprintf("Kernel not loaded !! Exiting...\n"); + return -1; + } + + /** boot mini without BootMii IOS code by Crediar. **/ + + disable_memory_protection(); + unsigned int i = 0x939F02F0; + unsigned char ES_ImportBoot2[16] = + { 0x68, 0x4B, 0x2B, 0x06, 0xD1, 0x0C, 0x68, 0x8B, 0x2B, 0x00, 0xD1, 0x09, 0x68, 0xC8, 0x68, 0x42 }; + + if( memcmp( (void*)(i), ES_ImportBoot2, sizeof(ES_ImportBoot2) ) != 0 ) + for( i = 0x939F0000; i < 0x939FE000; i+=4 ) + if( memcmp( (void*)(i), ES_ImportBoot2, sizeof(ES_ImportBoot2) ) == 0 ) + break; + + if(i >= 0x939FE000) + { + gprintf("ES_ImportBoot2 not patched !! Exiting...\n"); + //SYS_ResetSystem( SYS_RETURNTOMENU, 0, 0 ); + return -1; + } + + DCInvalidateRange( (void*)i, 0x20 ); + + *(vu32*)(i+0x00) = 0x48034904; // LDR R0, 0x10, LDR R1, 0x14 + *(vu32*)(i+0x04) = 0x477846C0; // BX PC, NOP + *(vu32*)(i+0x08) = 0xE6000870; // SYSCALL + *(vu32*)(i+0x0C) = 0xE12FFF1E; // BLR + //*(vu32*)(i+0x10) = 0x11000000; // kernel offset from 0x80000000. Kernel loaded to (void *)0x91000000 + *(vu32*)(i+0x10) = (u32)kernel - 0x80000000; // kernel offset + *(vu32*)(i+0x14) = 0x0000FF01; // version + + DCFlushRange( (void*)i, 0x20 ); + __IOS_ShutdownSubsystems(); + + s32 fd = IOS_Open( "/dev/es", 0 ); + + u8 *buffer = (u8*)memalign( 32, 0x100 ); + memset( buffer, 0, 0x100 ); + + IOS_IoctlvAsync( fd, 0x1F, 0, 0, (ioctlv*)buffer, NULL, NULL ); + return 0; + +} + +/**************************************************************************** + * neekIsNeek2o + * + * Detects Kernel.bin format + * + * @return values : + * -1 : kernel.bin not found + * 0 : sneek or uneek kernel.bin + * 1 : sneek2o or uneek2o kernel.bin + ***************************************************************************/ +int neekIsNeek2o(const char* nandpath) +{ + int found = 0; + char tempPath[100]; + if(isWiiU()) + snprintf(tempPath, sizeof(tempPath), "%s:/sneek/vwiikernel.bin", DeviceHandler::GetDevicePrefix(nandpath)); + + if(!isWiiU() || !CheckFile(tempPath)) + snprintf(tempPath, sizeof(tempPath), "%s:/sneek/kernel.bin", DeviceHandler::GetDevicePrefix(nandpath)); + + if(!CheckFile(tempPath)) + return -1; + + u8 *buffer = NULL; + u32 filesize = 0; + const char* str = "NEEK2O"; + if(LoadFileToMem(tempPath, &buffer, &filesize)) + { + for(u32 i = filesize-strlen(str); i > 0; i--) + { + if( memcmp(buffer+i, str, strlen(str)) == 0) + { + found = 1; + break; + } + } + } + else + return -1; + + if(buffer) + free(buffer); + + return found; +} + +/**************************************************************************** + * neekPathFormat + * + * Convert and trim full path to path format used by neek + ***************************************************************************/ +int neekPathFormat(char* nandpath_out, const char* nandpath_in, u32 len) +{ + const char* neekNandPathTemp = strchr(nandpath_in, '/'); + if(!neekNandPathTemp) + return -1; + + snprintf(nandpath_out, len, "%s", neekNandPathTemp); + + if(nandpath_out[strlen(nandpath_out)-1] == '/') + *(strrchr(nandpath_out, '/')) = '\0'; // remove trailing slash + + return 1; +} + +/**************************************************************************** + * neek2oSetBootSettings + * + * Generate the neek2o autoboot settings + * + * neek_config: Pointer to cfg + * TitleID : Full path to Channel (00010001 + ABCD) or ID4 for Wii/GC games (00000000 + ID) + * Magic : 0x0 for channel, 0x5d1c9ea3 for Wii game, 0xC2339F3D for gamecube and quadforce games + * returnTo : true/false to return to another neek channel instead of system menu + * nandpath : Set a different temporary Nand Path to use (full path to nand) + * + ***************************************************************************/ +bool neek2oSetBootSettings(NEEK_CFG* neek_config, u64 TitleID, u32 Magic, u64 returnto, const char* nandpath ) +{ + if(!neek_config) + return false; + + char tmpPath[100]; + memset(neek_config, 0, sizeof(NEEK_CFG)); + + // Magic and version for DML + neek_config->magic = NEEK_MAGIC; + + // GameID + if(!Magic) + neek_config->titleid = TitleID; // Set channel ID + else + { + neek_config->gameid = (u32)TitleID; // Wii or Gamecube title ID4 to autoboot + neek_config->gamemagic = Magic; // set to 0x5d1c9ea3 for Wii game, 0xC2339F3D for gamecube and quadforce games + neek_config->config |= NCON_EXT_BOOT_GAME ; // set Disc booting + } + + // Return to + if(returnto) + { + // check if NK2O is installed + snprintf(tmpPath, sizeof(tmpPath), "%s/title/00010001/4e4b324f/content/title.tmd", nandpath != NULL ? nandpath : Settings.NandEmuChanPath); + if(CheckFile(tmpPath)) + { + neek_config->returnto = TITLE_ID(0x00010001, 'NK2O'); // Currently forced to NK2O user channel + neek_config->config |= NCON_EXT_RETURN_TO; // enable "return to" patch + } + + if(isWiiU()) + { + neek_config->returnto = TITLE_ID(0x00010002, 'HCVA');// Currently forced to "Return to WiiU" system channel + neek_config->config |= NCON_EXT_RETURN_TO; // enable "return to" patch + } + } + + if(!(neek_config->config & NCON_EXT_RETURN_TO)) + { + // delete residual "return to" file if last shutdown was unclean. + snprintf(tmpPath, sizeof(tmpPath), "%s:/sneek/reload.sys", DeviceHandler::GetDevicePrefix(nandpath)); + if(CheckFile(tmpPath)) + RemoveFile(tmpPath); + } + + if(nandpath && strlen(nandpath) > 0) + { + // ensure path is correct format + char neekNandPath[256] = ""; + if(neekPathFormat(neekNandPath, nandpath, sizeof(neekNandPath))) + { + snprintf(neek_config->nandpath, sizeof(neek_config->nandpath), "%s", neekNandPath); + neek_config->config |= NCON_EXT_NAND_PATH ; // Use custom nand path + // neek_config->config |= NCON_HIDE_EXT_PATH; // Set custom nand path as temporary + } + } + + //set a custom di folder + //snprintf(neek_config->dipath, sizeof(neek_config->dipath), "/sneek/vwii"); // Set path for di.bin and diconfig.bin + //neek_config->config |= NCON_EXT_DI_PATH; // Use custom di path + + DCFlushRange(neek_config, sizeof(NEEK_CFG)); + + //hexdump(neek_config, sizeof(NEEK_CFG)); + + return true; +} + + +/**************************************************************************** + * neek2oSetNAND + * + * Generates nandcfg.bin if missing and adds missing EmuNAND path + * Sets default EmuNAND path for neek2o + * + * @return values : + * -1 : error + * x : Default path set to EmuNAND number x + ***************************************************************************/ +int neek2oSetNAND(const char* nandpath) +{ + // format path string for neek + char neekNandPath[256] = ""; + if(neekPathFormat(neekNandPath, nandpath, sizeof(neekNandPath)) < 0) + return -1; + + FILE *f = NULL; + u32 ret = -1; + bool found = false; + u32 i = 0; + + char nandconfigPath[100]; + snprintf(nandconfigPath, sizeof(nandconfigPath), "%s:/sneek/nandcfg.bin", DeviceHandler::GetDevicePrefix(nandpath)); + + // vWii neek2o - different filename but not the same format? + //if(isWiiU()) + // snprintf(nandconfigPath, sizeof(nandconfigPath), "%s:/sneek/vwiincfg.bin", DeviceHandler::GetDevicePrefix(nandpath)); + +#ifdef DEBUG + gprintf("nandconfigPath : %s\n", nandconfigPath); +#endif + + // create the file if it doesn't exist + if(!CheckFile(nandconfigPath) || FileSize(nandconfigPath) < NANDCONFIG_HEADER_SIZE+1) + { + u8* nandConfigHeader[NANDCONFIG_HEADER_SIZE]; + memset(nandConfigHeader, 0, NANDCONFIG_HEADER_SIZE); + + f = fopen(nandconfigPath, "wb"); + if(!f) + { + gprintf("Failed creating file %s.\n", nandconfigPath); + return -1; + } + + // create an empty header with 0 NAND + fwrite(nandConfigHeader, 1, NANDCONFIG_HEADER_SIZE, f); + fclose(f); + } + + f = fopen(nandconfigPath, "rb"); + if(!f) + { + gprintf("Failed loading file %s.\n", nandconfigPath); + return -1; + } + + fseek(f , 0 , SEEK_END); + u32 filesize = ftell(f); + rewind(f); + + /* Allocate memory */ + NandConfig *nandCfg = (NandConfig *) MEM2_alloc(filesize); + if (!nandCfg) + { + fclose (f); + return -1; + } + + // Read the file + ret = fread (nandCfg, 1, filesize, f); + if(ret != filesize) + { + gprintf("Failed loading file %s to Mem.\n", nandconfigPath); + fclose (f); + MEM2_free(nandCfg); + return -1; + } + +#ifdef DEBUG + hexdump(nandCfg, NANDCONFIG_HEADER_SIZE); +#endif + + // don't parse if wrong file + if(nandCfg->NandCnt > NANDCONFIG_MAXNAND || nandCfg->NandSel > nandCfg->NandCnt) // wrong header, delete file. + { + fclose(f); + MEM2_free(nandCfg); + RemoveFile(nandconfigPath); // delete corrupted file. + return -1; + } + +#ifdef DEBUG + // List found nands from the file + gprintf("NandCnt = %d\n", nandCfg->NandCnt); + gprintf("NandSel = %d\n", nandCfg->NandSel); + for( i = 0 ; i < nandCfg->NandCnt ; i++) + { + gprintf("Path %d = %s %s\n", i, &nandCfg->Nands[i], strcmp((const char *)&nandCfg->Nands[i], neekNandPath) == 0 ? "found" : ""); + } +#endif + + for( i = 0 ; i < nandCfg->NandCnt ; i++) + { + if(strcmp((const char *)&nandCfg->Nands[i], neekNandPath) == 0) + { + found = true; + break; + } + } + + if(found) // NAND path already present in nandcfg.bin + { + // set selected nand in header if different + if(nandCfg->NandSel != i) + { + nandCfg->NandSel = i; + nandCfg->Padding1 = i; // same value? + DCFlushRange(nandCfg, NANDCONFIG_HEADER_SIZE); +#ifdef DEBUG + gprintf("new nandCfg->sel = %d", nandCfg->NandSel); + hexdump(nandCfg, NANDCONFIG_HEADER_SIZE); +#endif + freopen(nandconfigPath, "wb", f); + ret = fwrite(nandCfg, sizeof(char), filesize, f); // Write full file + } + } + else // new NAND path to nandcfg.bin + { + NandInfo * newNand = (NandInfo *) MEM2_alloc(sizeof(NandInfo)); + if(newNand) + { + memset(newNand, 0, sizeof(NandInfo)); + snprintf(newNand->Path, sizeof(newNand->Path), neekNandPath); + snprintf(newNand->Name, sizeof(newNand->Name), strlen(neekNandPath) == 0 ? "root" : strrchr(neekNandPath, '/')+1); + snprintf(newNand->DiPath, sizeof(newNand->DiPath), "/sneek"); + DCFlushRange(newNand, sizeof(NandInfo)); +#ifdef DEBUG + gprintf("new nandCfg"); + hexdump(newNand, sizeof(NandInfo)); +#endif + nandCfg->NandCnt++; + nandCfg->NandSel = ++i; + + // prevent NAND selection bigger than number of NANDs. + if(nandCfg->NandSel >= nandCfg->NandCnt) + { + nandCfg->NandSel = nandCfg->NandCnt -1; + i--; + } + + freopen(nandconfigPath, "wb", f); + ret = fwrite(nandCfg, sizeof(char), filesize, f); // Write full file + ret = fwrite(newNand,1,sizeof(NandInfo),f); // append new NANDInfo + if(ret != sizeof(NandInfo)) + gprintf("Writing new NAND info failed\n"); + + MEM2_free(newNand); + } + } + + // verify the header is correctly written + freopen(nandconfigPath, "rb", f); + ret = fread (nandCfg, 1, NANDCONFIG_HEADER_SIZE, f); + if(ret != NANDCONFIG_HEADER_SIZE) + { + gprintf("Failed loading file %s to Mem.\n", nandconfigPath); + fclose (f); + MEM2_free(nandCfg); + return -1; + } + ret = nandCfg->NandSel; + fclose (f); + MEM2_free(nandCfg); +#ifdef DEBUG + gprintf("verify header:\n"); + hexdump(nandCfg, NANDCONFIG_HEADER_SIZE); +#endif + if(ret == i) + return ret ; + + return -1; +} diff --git a/source/usbloader/neek.hpp b/source/usbloader/neek.hpp new file mode 100644 index 0000000..2c48c60 --- /dev/null +++ b/source/usbloader/neek.hpp @@ -0,0 +1,88 @@ +/**************************************************************************** + * Copyright (C) 2015 Cyan + * + * 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 NEEK_CONFIG_H_ +#define NEEK_CONFIG_H_ + +#include + +#define NEEK_MAGIC 0x666c6f77 // 'FLOW'. 0x47414d45 'GAME' autoboot disc? +#define NEEK_CONFIG_ADDRESS 0x81200000 + +typedef struct _NEEK_CFG +{ + u32 magic; // always has to be 0x666c6f77 + u64 titleid; // the full path of the NAND title to boot (both folder names) + u32 config; // see below + u64 returnto; // same as titleid above + u32 gameid; // game for DI to autoboot use 4-digit game id + u32 gamemagic; // set to 0x5d1c9ea3 for Wii game, 0xC2339F3D for gamecube games + char dipath[256]; // string specifying path DI should use to find games (/wbfs/ or usb1/wbfs?) + char nandpath[256]; // string specifying where the emuNAND is stored if it's not in the normal place. (/nands/ or usb1/nands/ ?) +} NEEK_CFG; + +enum neekconfig +{ + NCON_EXT_DI_PATH = (1<<0), // 1 if you're using/specifying dipath + NCON_EXT_NAND_PATH = (1<<1), // 1 if you're using/specifying nandpath + NCON_HIDE_EXT_PATH = (1<<2), // 1 to have it not SAVE the last used custom path? + NCON_EXT_RETURN_TO = (1<<3), // 1 if you're using returnto + NCON_EXT_BOOT_GAME = (1<<4), // 1 if you're using gameid +}; + +#define NANDCONFIG_MAXNAND 8 +#define NANDCONFIG_HEADER_SIZE 0x10 +#define NANDCONFIG_NANDINFO_SIZE 0x100 + +typedef struct +{ + char Path[128]; + char Name[64]; + char DiPath[64]; +} NandInfo; + +typedef struct _NandConfig +{ + u32 NandCnt; + u32 NandSel; + u32 Padding1; + u32 Padding2; + NandInfo Nands[]; +} NandConfig; + + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +bool neekLoadKernel(const char* nandpath); +int neekBoot(void); + +int neekIsNeek2o(const char* nandpath); +int neekPathFormat(char* nandpath_out, const char* nandpath_in, u32 len); +bool neek2oSetBootSettings(NEEK_CFG* neek_config, u64 TitleID, u32 Magic, u64 returnto, const char* nandpath ); +int neek2oSetNAND(const char* nandpath); + +#ifdef __cplusplus +} +#endif + + + +#endif diff --git a/source/usbloader/playlog.c b/source/usbloader/playlog.c new file mode 100644 index 0000000..b2c6fcb --- /dev/null +++ b/source/usbloader/playlog.c @@ -0,0 +1,166 @@ +/* + PLAYLOG.C + This code allows to modify play_rec.dat in order to store the + game time in Wii's log correctly. + + by Marc + Thanks to tueidj for giving me some hints on how to do it :) + Most of the code was taken from here: + http://forum.wiibrew.org/read.php?27,22130 + + Modified by Dimok +*/ + +#include +#include +#include +#include +#include "gecko.h" +#include "utils/tools.h" + +#define SECONDS_TO_2000 946684800LL +#define TICKS_PER_SECOND 60750000LL + +//! Should be 32 byte aligned +static const char PLAYRECPATH[] ATTRIBUTE_ALIGN(32) = "/title/00000001/00000002/data/play_rec.dat"; + +typedef struct _PlayRec +{ + u32 checksum; + union + { + u32 data[31]; + struct + { + u16 name[42]; + u64 ticks_boot; + u64 ticks_last; + char title_id[6]; + char unknown[18]; + } ATTRIBUTE_PACKED; + }; +} PlayRec; + +// Thanks to Dr. Clipper +static u64 getWiiTime(void) +{ + time_t uTime = time(NULL); + return TICKS_PER_SECOND * (uTime - SECONDS_TO_2000); +} + +int Playlog_Create(void) +{ + s32 fd = IOS_Open(PLAYRECPATH, IPC_OPEN_RW); + if(fd >= 0) + { + //exists + IOS_Close(fd); + return 0; + } + + ISFS_Initialize(); + + //In case the play_rec.dat wasn´t found create one and try again + int ret = ISFS_CreateFile(PLAYRECPATH, 0, 3, 3, 3); + if(ret >= 0) + ISFS_SetAttr(PLAYRECPATH, 0x1000, 1, 0, 3, 3, 3); + + ISFS_Deinitialize(); + + return ret; +} + +int Playlog_Update(const char * ID, const u16 * title) +{ + if(!ID || !title) + return -1; + + //If not started from SystemMenu, create playlog + Playlog_Create(); + + s32 fd = -1, res = -1; + u32 sum = 0; + u8 i; + + //Open play_rec.dat + fd = IOS_Open(PLAYRECPATH, IPC_OPEN_RW); + if(fd == -106) + { + //In case the play_rec.dat wasn´t found create one and try again + int ret = Playlog_Create(); + if(ret < 0) + return ret; + + fd = IOS_Open(PLAYRECPATH, IPC_OPEN_RW); + } + + if(fd < 0) + return res; + + PlayRec * playrec_buf = memalign(32, ALIGN32(sizeof(PlayRec))); //! Should be 32 byte aligned + if(!playrec_buf) + { + IOS_Close(fd); + return res; + } + + memset(playrec_buf, 0, sizeof(PlayRec)); + + u64 stime = getWiiTime(); + playrec_buf->ticks_boot = stime; + playrec_buf->ticks_last = stime; + + //Update channel name and ID + memcpy(playrec_buf->name, title, 84); + memcpy(playrec_buf->title_id, ID, 6); + + //Calculate and update checksum + for(i = 0; i < 31; i++) + sum += playrec_buf->data[i]; + + playrec_buf->checksum = sum; + + //Write play_rec.dat + if(IOS_Write(fd, playrec_buf, sizeof(PlayRec)) == sizeof(PlayRec)) + res = 0; + + IOS_Close(fd); + + free(playrec_buf); + + return res; +} + +int Playlog_Delete(void) +{ + s32 res = -1; + + //Open play_rec.dat + s32 fd = IOS_Open(PLAYRECPATH, IPC_OPEN_RW); + if(fd < 0) + return fd; + + PlayRec * playrec_buf = memalign(32, ALIGN32(sizeof(PlayRec))); + if(!playrec_buf) + goto cleanup; + + //Read play_rec.dat + if(IOS_Read(fd, playrec_buf, sizeof(PlayRec)) != sizeof(PlayRec)) + goto cleanup; + + if(IOS_Seek(fd, 0, 0) < 0) + goto cleanup; + + // invalidate checksum + playrec_buf->checksum = 0; + + if(IOS_Write(fd, playrec_buf, sizeof(PlayRec)) != sizeof(PlayRec)) + goto cleanup; + + res = 0; + +cleanup: + free(playrec_buf); + IOS_Close(fd); + return res; +} diff --git a/source/usbloader/playlog.h b/source/usbloader/playlog.h new file mode 100644 index 0000000..7a13f64 --- /dev/null +++ b/source/usbloader/playlog.h @@ -0,0 +1,18 @@ +#ifndef PLAYLOG_H_ +#define PLAYLOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int Playlog_Create(void); +int Playlog_Update(const char * ID, const u16 * title); +int Playlog_Delete(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/usbloader/sdhc.c b/source/usbloader/sdhc.c new file mode 100644 index 0000000..7ecf536 --- /dev/null +++ b/source/usbloader/sdhc.c @@ -0,0 +1,215 @@ +#include +#include +#include +#include + +#include "sdhc.h" + +/* IOCTL comamnds */ +#define IOCTL_SDHC_INIT 0x01 +#define IOCTL_SDHC_READ 0x02 +#define IOCTL_SDHC_WRITE 0x03 +#define IOCTL_SDHC_ISINSERTED 0x04 + +#define SDHC_HEAPSIZE 0x8000 +#define SDHC_MEM2_SIZE 0x10000 + +int sdhc_mode_sd = 0; + +/* Variables */ +static char fs[] ATTRIBUTE_ALIGN( 32 ) = "/dev/sdio/sdhc"; + +static s32 hid = -1, fd = -1; +static u32 sector_size = SDHC_SECTOR_SIZE; +static void *sdhc_buf2; + +extern void* SYS_AllocArena2MemLo(u32 size, u32 align); + +bool SDHC_Init(void) +{ + s32 ret; + + if (sdhc_mode_sd) + { + return __io_wiisd.startup(); + } + + /* Already open */ + if (fd >= 0) return true; + + /* Create heap */ + if (hid < 0) + { + hid = iosCreateHeap(SDHC_HEAPSIZE); + if (hid < 0) goto err; + } + + // allocate buf2 + if (sdhc_buf2 == NULL) + { + sdhc_buf2 = SYS_AllocArena2MemLo(SDHC_MEM2_SIZE, 32); + } + + /* Open SDHC device */ + fd = IOS_Open(fs, 0); + if (fd < 0) goto err; + + /* Initialize SDHC */ + ret = IOS_IoctlvFormat(hid, fd, IOCTL_SDHC_INIT, ":"); + if (ret) goto err; + + return true; + + err: + /* Close SDHC device */ + if (fd >= 0) + { + IOS_Close(fd); + fd = -1; + } + + return false; +} + +bool SDHC_Close(void) +{ + if (sdhc_mode_sd) + { + return __io_wiisd.shutdown(); + } + + /* Close SDHC device */ + if (fd >= 0) + { + IOS_Close(fd); + fd = -1; + } + + /*if (hid > 0) { + iosDestroyHeap(hid); + hid = -1; + }*/ + + return true; +} + +bool SDHC_IsInserted(void) +{ + s32 ret; + if (sdhc_mode_sd) + { + return __io_wiisd.isInserted(); + } + + /* Check if SD card is inserted */ + ret = IOS_IoctlvFormat(hid, fd, IOCTL_SDHC_ISINSERTED, ":"); + + return (!ret) ? true : false; +} + +bool SDHC_ReadSectors(u32 sector, u32 count, void *buffer) +{ + //printf("SD-R(%u %u)\n", sector, count); + if (sdhc_mode_sd) + { + return __io_wiisd.readSectors(sector, count, buffer); + } + + void *buf = (void *) buffer; + u32 len = (sector_size * count); + + s32 ret; + + /* Device not opened */ + if (fd < 0) return false; + + /* Buffer not aligned */ + if ((u32) buffer & 0x1F) + { + /* Allocate memory */ + //buf = iosAlloc(hid, len); + buf = sdhc_buf2; + if (!buf) return false; + } + + /* Read data */ + ret = IOS_IoctlvFormat(hid, fd, IOCTL_SDHC_READ, "ii:d", sector, count, buf, len); + + /* Copy data */ + if (buf != buffer) + { + memcpy(buffer, buf, len); + //iosFree(hid, buf); + } + + return (!ret) ? true : false; +} + +bool SDHC_WriteSectors(u32 sector, u32 count, void *buffer) +{ + if (sdhc_mode_sd) + { + return __io_wiisd.writeSectors(sector, count, buffer); + } + + void *buf = (void *) buffer; + u32 len = (sector_size * count); + + s32 ret; + + /* Device not opened */ + if (fd < 0) return false; + + /* Buffer not aligned */ + if ((u32) buffer & 0x1F) + { + /* Allocate memory */ + //buf = iosAlloc(hid, len); + buf = sdhc_buf2; + if (!buf) return false; + + /* Copy data */ + memcpy(buf, buffer, len); + } + + /* Read data */ + ret = IOS_IoctlvFormat(hid, fd, IOCTL_SDHC_WRITE, "ii:d", sector, count, buf, len); + + /* Free memory */ + //if (buf != buffer) + // iosFree(hid, buf); + + return (!ret) ? true : false; +} + +bool SDHC_ClearStatus(void) +{ + return true; +} + +bool __io_SDHC_Close(void) +{ + // do nothing. + return true; +} + +bool __io_SDHC_NOP(void) +{ + // do nothing. + return true; +} + +const DISC_INTERFACE __io_sdhc = { DEVICE_TYPE_WII_SD, FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE + | FEATURE_WII_SD, (FN_MEDIUM_STARTUP) &SDHC_Init, (FN_MEDIUM_ISINSERTED) &SDHC_IsInserted, + (FN_MEDIUM_READSECTORS) &SDHC_ReadSectors, (FN_MEDIUM_WRITESECTORS) &SDHC_WriteSectors, + (FN_MEDIUM_CLEARSTATUS) &SDHC_ClearStatus, + //(FN_MEDIUM_SHUTDOWN)&SDHC_Close + (FN_MEDIUM_SHUTDOWN) &__io_SDHC_Close }; + +const DISC_INTERFACE __io_sdhc_ro = { DEVICE_TYPE_WII_SD, FEATURE_MEDIUM_CANREAD | FEATURE_WII_SD, + (FN_MEDIUM_STARTUP) &SDHC_Init, (FN_MEDIUM_ISINSERTED) &SDHC_IsInserted, + (FN_MEDIUM_READSECTORS) &SDHC_ReadSectors, (FN_MEDIUM_WRITESECTORS) &__io_SDHC_NOP, // &SDHC_WriteSectors, + (FN_MEDIUM_CLEARSTATUS) &SDHC_ClearStatus, + //(FN_MEDIUM_SHUTDOWN)&SDHC_Close + (FN_MEDIUM_SHUTDOWN) &__io_SDHC_Close }; + diff --git a/source/usbloader/sdhc.h b/source/usbloader/sdhc.h new file mode 100644 index 0000000..5d3d4bb --- /dev/null +++ b/source/usbloader/sdhc.h @@ -0,0 +1,23 @@ +#ifndef _SDHC_H_ +#define _SDHC_H_ + +/* Constants */ +#define SDHC_SECTOR_SIZE 0x200 + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Prototypes */ + bool SDHC_Init(void); + bool SDHC_Close(void); + bool SDHC_ReadSectors(u32, u32, void *); + bool SDHC_WriteSectors(u32, u32, void *); + extern int sdhc_mode_sd; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/usbloader/splits.c b/source/usbloader/splits.c new file mode 100644 index 0000000..f4ec9e0 --- /dev/null +++ b/source/usbloader/splits.c @@ -0,0 +1,348 @@ +// by oggzee + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "splits.h" + +#define off64_t off_t +#define FMT_llu "%llu" +#define FMT_lld "%lld" + +#define split_error(x) do { printf("\nsplit error: %s\n\n",x); } while(0) + +// 1 cluster less than 4gb +u64 OPT_split_size = (u64) 4LL * 1024 * 1024 * 1024 - 32 * 1024; +// 1 cluster less than 2gb +//u64 OPT_split_size = (u64)2LL * 1024 * 1024 * 1024 - 32 * 1024; + +//split_info_t split; + +void split_get_fname(split_info_t *s, int idx, char *fname) +{ + strcpy(fname, s->fname); + if (idx == 0 && s->create_mode) + { + strcat(fname, ".tmp"); + } + else if (idx > 0) + { + char *c = fname + strlen(fname) - 1; + *c = '0' + idx; + } +} + +int split_open_file(split_info_t *s, int idx) +{ + int fd = s->fd[idx]; + if (fd >= 0) return fd; + char fname[1024]; + split_get_fname(s, idx, fname); + //char *mode = s->create_mode ? "wb+" : "rb+"; + int mode = s->create_mode ? (O_CREAT | O_RDWR) : O_RDWR; + //printf("SPLIT OPEN %s %s %d\n", fname, mode, idx); //Wpad_WaitButtons(); + //f = fopen(fname, mode); + fd = open(fname, mode); + if (fd < 0) return -1; + if (idx > 0 && s->create_mode) + { + printf("%s Split: %d %s \n", s->create_mode ? "Create" : "Read", idx, fname); + } + s->fd[idx] = fd; + return fd; +} + +// faster as it uses larger chunks than ftruncate internally +int write_zero(int fd, off_t size) +{ + int buf[0x4000]; //64kb + int chunk; + int ret; + memset(buf, 0, sizeof(buf)); + while (size) + { + chunk = size; + if (chunk > (int) sizeof(buf)) chunk = sizeof(buf); + ret = write(fd, buf, chunk); + //printf("WZ %d %d / %lld \n", ret, chunk, size); + size -= chunk; + if (ret < 0) return ret; + } + return 0; +} + +int split_fill(split_info_t *s, int idx, u64 size) +{ + int fd = split_open_file(s, idx); + off64_t fsize = lseek(fd, 0, SEEK_END); + if (fsize < (s64) size) + { + //printf("TRUNC %d "FMT_lld"\n", idx, size); Wpad_WaitButtons(); + //ftruncate(fd, size); + write_zero(fd, size - fsize); + return 1; + } + return 0; +} + +int split_get_file(split_info_t *s, u32 lba, u32 *sec_count, int fill) +{ + int fd; + if (lba >= s->total_sec) + { + fprintf(stderr, "SPLIT: invalid sector %u / %u\n", (unsigned int)lba, (unsigned int)s->total_sec); + return -1; + } + int idx; + idx = lba / s->split_sec; + if (idx >= s->max_split) + { + fprintf(stderr, "SPLIT: invalid split %d / %d\n", idx, s->max_split - 1); + return -1; + } + fd = s->fd[idx]; + if (fd < 0) + { + // opening new, make sure all previous are full + int i; + for (i = 0; i < idx; i++) + { + if (split_fill(s, i, s->split_size)) + { + printf("FILL %d\n", i); + } + } + fd = split_open_file(s, idx); + } + if (fd < 0) + { + fprintf(stderr, "SPLIT %d: no file\n", idx); + return -1; + } + u32 sec = lba % s->split_sec; // inside file + off64_t off = (off64_t ) sec * 512; + // num sectors till end of file + u32 to_end = s->split_sec - sec; + if (*sec_count > to_end) *sec_count = to_end; + if (s->create_mode) + { + if (fill) + { + // extend, so that read will be succesfull + split_fill(s, idx, off + 512 * (*sec_count)); + } + else + { + // fill up so that write continues from end of file + // shouldn't be necessary, but libfat looks buggy + // and this is faster + split_fill(s, idx, off); + } + } + lseek(fd, off, SEEK_SET); + return fd; +} + +s32 split_read_sector(void *_fp, u32 lba, u32 count, void*buf) +{ + split_info_t *s = _fp; + int fd; + u64 off = lba; + off *= 512ULL; + int i; + u32 chunk; + size_t ret; + //fprintf(stderr,"READ %d %d\n", lba, count); + for (i = 0; i < (int) count; i += chunk) + { + chunk = count - i; + fd = split_get_file(s, lba + i, &chunk, 1); + if (fd < 0) + { + fprintf(stderr, "\n\n"FMT_lld" %d %p\n", off, (int)count, _fp); + split_error( "error seeking in disc partition" ); + return 1; + } + void *ptr = ((u8 *) buf) + (i * 512); + ret = read(fd, ptr, chunk * 512); + if (ret != chunk * 512) + { + fprintf(stderr, "error reading %u %u [%u] %u = %u\n", (unsigned int)lba, (unsigned int)count, i, (unsigned int)chunk, ret); + split_error( "error reading disc" ); + return 1; + } + } + return 0; +} + +s32 split_write_sector(void *_fp, u32 lba, u32 count, void*buf) +{ + split_info_t *s = _fp; + int fd; + u64 off = lba; + off *= 512ULL; + int i; + u32 chunk; + size_t ret; + //printf("WRITE %d %d %p \n", lba, count, buf); + for (i = 0; i < (int) count; i += chunk) + { + chunk = count - i; + fd = split_get_file(s, lba + i, &chunk, 0); + //if (chunk != count) + // fprintf(stderr, "WRITE CHUNK %d %d/%d\n", lba+i, chunk, count); + if (fd < 0 || !chunk) + { + fprintf(stderr, "\n\n"FMT_lld" %d %p\n", off, (int)count, _fp); + split_error( "error seeking in disc partition" ); + return 1; + } + //if (fwrite(buf+i*512, 512ULL, chunk, f) != chunk) { + //printf("write %d %p %d \n", fd, buf+i*512, chunk * 512); + void *ptr = ((u8 *) buf) + (i * 512); + ret = write(fd, ptr, chunk * 512); + //printf("write ret = %d \n", ret); + if (ret != chunk * 512) + { + split_error( "error writing disc" ); + return 1; + } + } + return 0; +} + +void split_init(split_info_t *s, char *fname) +{ + int i; + char *p; + //fprintf(stderr, "SPLIT_INIT %s\n", fname); + memset(s, 0, sizeof(*s)); + for (i = 0; i < MAX_SPLIT; i++) + { + s->fd[i] = -1; + } + strcpy(s->fname, fname); + s->max_split = 1; + p = strrchr(fname, '.'); + if (p && (strcasecmp(p, ".wbfs") == 0)) + { + s->max_split = MAX_SPLIT; + } +} + +void split_set_size(split_info_t *s, u64 split_size, u64 total_size) +{ + s->total_size = total_size; + s->split_size = split_size; + s->total_sec = total_size / 512; + s->split_sec = split_size / 512; +} + +void split_close(split_info_t *s) +{ + int i; + char fname[1024]; + char tmpname[1024]; + for (i = 0; i < s->max_split; i++) + { + if (s->fd[i] >= 0) + { + close(s->fd[i]); + } + } + if (s->create_mode) + { + split_get_fname(s, -1, fname); + split_get_fname(s, 0, tmpname); + rename(tmpname, fname); + } + memset(s, 0, sizeof(*s)); +} + +int split_create(split_info_t *s, char *fname, u64 split_size, u64 total_size, bool overwrite) +{ + int i; + int fd; + char sname[1024]; + int error = 0; + split_init(s, fname); + s->create_mode = 1; + // check if any file already exists + for (i = -1; i < s->max_split; i++) + { + split_get_fname(s, i, sname); + if (overwrite) + { + remove(sname); + } + else + { + fd = open(sname, O_RDONLY); + if (fd >= 0) + { + fprintf(stderr, "Error: file already exists: %s\n", sname); + close(fd); + error = 1; + } + } + } + if (error) + { + split_init(s, ""); + return -1; + } + split_set_size(s, split_size, total_size); + return 0; +} + +int split_open(split_info_t *s, char *fname) +{ + int i; + u64 size = 0; + u64 total_size = 0; + u64 split_size = 0; + int fd; + split_init(s, fname); + for (i = 0; i < s->max_split; i++) + { + fd = split_open_file(s, i); + if (fd < 0) + { + if (i == 0) goto err; + break; + } + // check previous size - all splits except last must be same size + if (i > 0 && size != split_size) + { + fprintf(stderr, "split %d: invalid size "FMT_lld"", i, size); + goto err; + } + // get size + //fseeko(f, 0, SEEK_END); + //size = ftello(f); + size = lseek(fd, 0, SEEK_END); + // check sector alignment + if (size % 512) + { + fprintf(stderr, "split %d: size ("FMT_lld") not sector (512) aligned!", i, size); + } + // first sets split size + if (i == 0) + { + split_size = size; + } + total_size += size; + } + split_set_size(s, split_size, total_size); + return 0; + err: split_close(s); + return -1; +} + diff --git a/source/usbloader/splits.h b/source/usbloader/splits.h new file mode 100644 index 0000000..6be34bd --- /dev/null +++ b/source/usbloader/splits.h @@ -0,0 +1,43 @@ +#ifndef _SPLITS_H +#define _SPLITS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define MAX_SPLIT 10 + + typedef struct split_info + { + char fname[1024]; + //FILE *f[MAX_SPLIT]; + int fd[MAX_SPLIT]; + //u64 fsize[MAX_SPLIT]; + u32 split_sec; + u32 total_sec; + u64 split_size; + u64 total_size; + int create_mode; + int max_split; + } split_info_t; + + void split_get_fname(split_info_t *s, int idx, char *fname); + //FILE *split_open_file(split_info_t *s, int idx); + //FILE *split_get_file(split_info_t *s, u32 lba, u32 *sec_count, int fill); + int split_open_file(split_info_t *s, int idx); + int split_get_file(split_info_t *s, u32 lba, u32 *sec_count, int fill); + int split_fill(split_info_t *s, int idx, u64 size); + s32 split_read_sector(void *_fp, u32 lba, u32 count, void*buf); + s32 split_write_sector(void *_fp, u32 lba, u32 count, void*buf); + void split_init(split_info_t *s, char *fname); + void split_set_size(split_info_t *s, u64 split_size, u64 total_size); + void split_close(split_info_t *s); + int split_open(split_info_t *s, char *fname); + int split_create(split_info_t *s, char *fname, u64 split_size, u64 total_size, bool overwrite); + +#ifdef __cplusplus +} +#endif + +#endif //_SPLITS_H diff --git a/source/usbloader/usbstorage2.c b/source/usbloader/usbstorage2.c new file mode 100644 index 0000000..ed09034 --- /dev/null +++ b/source/usbloader/usbstorage2.c @@ -0,0 +1,331 @@ +/*------------------------------------------------------------- + + usbstorage_starlet.c -- USB mass storage support, inside starlet + Copyright (C) 2011 Dimok + Copyright (C) 2011 Rodries + Copyright (C) 2009 Kwiirk + + If this driver is linked before libogc, this will replace the original + usbstorage driver by svpe from libogc + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + -------------------------------------------------------------*/ + +#include +#include +#include +#include +#include "usbstorage2.h" +#include "memory/mem2.h" +#include "gecko.h" + + +/* IOCTL commands */ +#define UMS_BASE (('U'<<24)|('M'<<16)|('S'<<8)) +#define USB_IOCTL_UMS_INIT (UMS_BASE+0x1) +#define USB_IOCTL_UMS_GET_CAPACITY (UMS_BASE+0x2) +#define USB_IOCTL_UMS_READ_SECTORS (UMS_BASE+0x3) +#define USB_IOCTL_UMS_WRITE_SECTORS (UMS_BASE+0x4) +#define USB_IOCTL_UMS_READ_STRESS (UMS_BASE+0x5) +#define USB_IOCTL_UMS_SET_VERBOSE (UMS_BASE+0x6) +#define USB_IOCTL_UMS_UMOUNT (UMS_BASE+0x10) +#define USB_IOCTL_UMS_WATCHDOG (UMS_BASE+0x80) + +#define USB_IOCTL_UMS_TESTMODE (UMS_BASE+0x81) +#define USB_IOCTL_SET_PORT (UMS_BASE+0x83) + +#define WBFS_BASE (('W'<<24)|('F'<<16)|('S'<<8)) +#define USB_IOCTL_WBFS_OPEN_DISC (WBFS_BASE+0x1) +#define USB_IOCTL_WBFS_READ_DISC (WBFS_BASE+0x2) +#define USB_IOCTL_WBFS_SET_DEVICE (WBFS_BASE+0x50) +#define USB_IOCTL_WBFS_SET_FRAGLIST (WBFS_BASE+0x51) + +#define isMEM2Buffer(p) (((u32) p & 0x10000000) != 0) + +#define MAX_SECTOR_SIZE 4096 +#define MAX_BUFFER_SECTORS 128 +#define UMS_HEAPSIZE 2*1024 + +/* Variables */ +static char fs[] ATTRIBUTE_ALIGN(32) = "/dev/usb2"; +static char fs2[] ATTRIBUTE_ALIGN(32) = "/dev/usb123"; +static char fs3[] ATTRIBUTE_ALIGN(32) = "/dev/usb/ehc"; + +static u8 * mem2_ptr = NULL; +static s32 hid = -1, fd = -1; +static u32 usb2_port = -1; //current USB port +bool hddInUse[2] = { false, false }; +u32 hdd_sector_size[2] = { 512, 512 }; + +s32 USBStorage2_Init(u32 port) +{ + if(hddInUse[port]) + return 0; + + /* Create heap */ + if (hid < 0) + { + hid = iosCreateHeap(UMS_HEAPSIZE); + if (hid < 0) return IPC_ENOMEM; + } + + /* Open USB device */ + if (fd < 0) fd = IOS_Open(fs, 0); + if (fd < 0) fd = IOS_Open(fs2, 0); + if (fd < 0) fd = IOS_Open(fs3, 0); + if (fd < 0) return fd; + + USBStorage2_SetPort(port); + + /* Initialize USB storage */ + IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_INIT, ":"); + + /* Get device capacity */ + if (USBStorage2_GetCapacity(port, &hdd_sector_size[port]) == 0) + return IPC_ENOENT; + + hddInUse[port] = true; + + return 0; // 0->HDD, 1->DVD +} + +void USBStorage2_Deinit() +{ + /* Close USB device */ + if (fd >= 0) + { + IOS_Close(fd); // not sure to close the fd is needed + fd = -1; + } +} + +s32 USBStorage2_SetPort(u32 port) +{ + //! Port = 2 is handle in the loader, no need to handle it in cIOS + if(port > 1) + return -1; + + if(port == usb2_port) + return 0; + + s32 ret = -1; + usb2_port = port; + + gprintf("Changing USB port to port %i....\n", port); + //must be called before USBStorage2_Init (default port 0) + if (fd >= 0) + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_SET_PORT, "i:", usb2_port); + + return ret; +} + +s32 USBStorage2_GetPort() +{ + return usb2_port; +} + +s32 USBStorage2_GetCapacity(u32 port, u32 *_sector_size) +{ + if (fd >= 0) + { + s32 ret; + u32 sector_size = 0; + USBStorage2_SetPort(port); + + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_GET_CAPACITY, ":i", §or_size); + + if (ret && _sector_size) *_sector_size = sector_size; + + return ret; + } + + return IPC_ENOENT; +} + +s32 USBStorage2_ReadSectors(u32 port, u32 sector, u32 numSectors, void *buffer) +{ + u8 *buf = (u8 *) buffer; + s32 ret = -1; + + /* Device not opened */ + if (fd < 0) return fd; + + if (!mem2_ptr) + mem2_ptr = (u8 *) MEM2_alloc(MAX_SECTOR_SIZE * MAX_BUFFER_SECTORS); + + USBStorage2_SetPort(port); + + s32 read_secs, read_size; + + while(numSectors > 0) + { + read_secs = numSectors > MAX_BUFFER_SECTORS ? MAX_BUFFER_SECTORS : numSectors; + read_size = read_secs*hdd_sector_size[port]; + + // Do not read more than MAX_BUFFER_SECTORS sectors at once and create a mem overflow! + if (!isMEM2Buffer(buffer)) + { + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_READ_SECTORS, "ii:d", sector, read_secs, mem2_ptr, read_size); + if(ret < 0) + return ret; + + memcpy(buf, mem2_ptr, read_size); + } + else + { + /* Read data */ + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_READ_SECTORS, "ii:d", sector, read_secs, buf, read_size); + if(ret < 0) + return ret; + } + + sector += read_secs; + numSectors -= read_secs; + buf += read_size; + } + + return ret; +} + +s32 USBStorage2_WriteSectors(u32 port, u32 sector, u32 numSectors, const void *buffer) +{ + u8 *buf = (u8 *) buffer; + s32 ret = -1; + + /* Device not opened */ + if (fd < 0) return fd; + + /* Device not opened */ + if (!mem2_ptr) + mem2_ptr = (u8 *) MEM2_alloc(MAX_SECTOR_SIZE * MAX_BUFFER_SECTORS); + + USBStorage2_SetPort(port); + + s32 write_size, write_secs; + + while(numSectors > 0) + { + write_secs = numSectors > MAX_BUFFER_SECTORS ? MAX_BUFFER_SECTORS : numSectors; + write_size = write_secs*hdd_sector_size[port]; + + /* MEM1 buffer */ + if (!isMEM2Buffer(buffer)) + { + // Do not read more than MAX_BUFFER_SECTORS sectors at once and create a mem overflow! + memcpy(mem2_ptr, buf, write_size); + + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_WRITE_SECTORS, "ii:d", sector, write_secs, mem2_ptr, write_size); + if(ret < 0) + return ret; + } + else + { + /* Write data */ + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_WRITE_SECTORS, "ii:d", sector, write_secs, buf, write_size); + if(ret < 0) + return ret; + } + + sector += write_secs; + numSectors -= write_secs; + buf += write_size; + } + + return ret; +} + +static bool __usbstorage_Startup(void) +{ + return USBStorage2_Init(0) >= 0; +} + +static bool __usbstorage_IsInserted(void) +{ + return (USBStorage2_GetCapacity(0, NULL) != 0); +} + +static bool __usbstorage_ReadSectors(u32 sector, u32 numSectors, void *buffer) +{ + return (USBStorage2_ReadSectors(0, sector, numSectors, buffer) >= 0); +} + +static bool __usbstorage_WriteSectors(u32 sector, u32 numSectors, const void *buffer) +{ + return (USBStorage2_WriteSectors(0, sector, numSectors, buffer) >= 0); +} + +static bool __usbstorage_ClearStatus(void) +{ + return true; +} + +static bool __usbstorage_Shutdown(void) +{ + hddInUse[0] = false; + hdd_sector_size[0] = 512; + return true; +} + +const DISC_INTERFACE __io_usbstorage2_port0 = { + DEVICE_TYPE_WII_UMS, FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_USB, + (FN_MEDIUM_STARTUP) &__usbstorage_Startup, + (FN_MEDIUM_ISINSERTED) &__usbstorage_IsInserted, + (FN_MEDIUM_READSECTORS) &__usbstorage_ReadSectors, + (FN_MEDIUM_WRITESECTORS) &__usbstorage_WriteSectors, + (FN_MEDIUM_CLEARSTATUS) &__usbstorage_ClearStatus, + (FN_MEDIUM_SHUTDOWN) &__usbstorage_Shutdown +}; + +static bool __usbstorage_Startup2(void) +{ + return USBStorage2_Init(1) >= 0; +} + +static bool __usbstorage_IsInserted2(void) +{ + return (USBStorage2_GetCapacity(1, NULL) != 0); +} + +static bool __usbstorage_ReadSectors2(u32 sector, u32 numSectors, void *buffer) +{ + return (USBStorage2_ReadSectors(1, sector, numSectors, buffer) >= 0); +} + +static bool __usbstorage_WriteSectors2(u32 sector, u32 numSectors, const void *buffer) +{ + return (USBStorage2_WriteSectors(1, sector, numSectors, buffer) >= 0); +} + +static bool __usbstorage_Shutdown2(void) +{ + hddInUse[1] = false; + hdd_sector_size[1] = 512; + return true; +} + +const DISC_INTERFACE __io_usbstorage2_port1 = { + DEVICE_TYPE_WII_UMS, FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_USB, + (FN_MEDIUM_STARTUP) &__usbstorage_Startup2, + (FN_MEDIUM_ISINSERTED) &__usbstorage_IsInserted2, + (FN_MEDIUM_READSECTORS) &__usbstorage_ReadSectors2, + (FN_MEDIUM_WRITESECTORS) &__usbstorage_WriteSectors2, + (FN_MEDIUM_CLEARSTATUS) &__usbstorage_ClearStatus, + (FN_MEDIUM_SHUTDOWN) &__usbstorage_Shutdown2 +}; diff --git a/source/usbloader/usbstorage2.h b/source/usbloader/usbstorage2.h new file mode 100644 index 0000000..56ce138 --- /dev/null +++ b/source/usbloader/usbstorage2.h @@ -0,0 +1,31 @@ +#ifndef _USBSTORAGE2_H_ +#define _USBSTORAGE2_H_ + +#include "ogc/disc_io.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Prototypes */ + s32 USBStorage2_Init(u32 port); + void USBStorage2_Deinit(); + s32 USBStorage2_GetCapacity(u32 port, u32 *size); + + s32 USBStorage2_ReadSectors(u32 port, u32 sector, u32 numSectors, void *buffer); + s32 USBStorage2_WriteSectors(u32 port, u32 sector, u32 numSectors, const void *buffer); + + s32 USBStorage2_SetPort(u32 port); + s32 USBStorage2_GetPort(); + +#define DEVICE_TYPE_WII_UMS (('W'<<24)|('U'<<16)|('M'<<8)|'S') + + extern const DISC_INTERFACE __io_usbstorage2_port0; + extern const DISC_INTERFACE __io_usbstorage2_port1; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/usbloader/wbfs.cpp b/source/usbloader/wbfs.cpp new file mode 100644 index 0000000..d0500a5 --- /dev/null +++ b/source/usbloader/wbfs.cpp @@ -0,0 +1,250 @@ +#include +#include +#include +#include + +#include "Controls/DeviceHandler.hpp" +#include "usbloader/usbstorage2.h" +#include "wbfs.h" +#include "usbloader/wbfs/wbfs_base.h" +#include "usbloader/wbfs/wbfs_wbfs.h" +#include "usbloader/wbfs/wbfs_fat.h" +#include "usbloader/wbfs/wbfs_ntfs.h" +#include "usbloader/wbfs/wbfs_ext.h" + +#include "usbloader/GameList.h" +#include "menu/menus.h" +#include "gecko.h" + +#define VALID(x) (x >= 0 && x < (int) WbfsList.size() && WbfsList[x] != NULL) + +static std::vector WbfsList; + +wbfs_disc_t* WBFS_OpenDisc(u8 *discid) +{ + if(!discid) return NULL; + + int part = gameList.GetPartitionNumber(discid); + if(!VALID(part)) + return NULL; + + return WbfsList[part]->OpenDisc(discid); +} + +void WBFS_CloseDisc(wbfs_disc_t *disc) +{ + if(!disc) return; + + struct discHdr * header = (struct discHdr *) disc->header; + int part_num = gameList.GetPartitionNumber(header->id); + if(!VALID(part_num)) + return; + + WbfsList[part_num]->CloseDisc(disc); +} + +s32 WBFS_Init(u32 device) +{ + return Wbfs::Init(device); +} + +s32 WBFS_ReInit(u32 device) +{ + WBFS_CloseAll(); + DeviceHandler::Instance()->UnMountAllUSB(); + DeviceHandler::Instance()->MountAllUSB(); + s32 ret = -1; + + if(Settings.MultiplePartitions) + ret = WBFS_OpenAll(); + else + ret = WBFS_OpenPart(Settings.partition); + + return ret; +} + +s32 WBFS_OpenAll() +{ + int ret = -1; + int partCount = DeviceHandler::GetUSBPartitionCount(); + + for(int i = 0; i < partCount; ++i) + { + if(WBFS_OpenPart(i) == 0) + ret = 0; + } + + return ret; +} + +s32 WBFS_OpenPart(int part_num) +{ + PartitionHandle * usbHandle = DeviceHandler::Instance()->GetUSBHandleFromPartition(part_num); + if(!usbHandle || part_num < 0 || part_num >= DeviceHandler::GetUSBPartitionCount()) + return -1; + + // close + WBFS_Close(part_num); + + if(part_num >= (int) WbfsList.size()) + WbfsList.resize(part_num+1); + + int portPart = DeviceHandler::PartitionToPortPartition(part_num); + int usbPort = DeviceHandler::PartitionToUSBPort(part_num); + + gprintf("\tWBFS_OpenPart: filesystem: %s, start sector %u, sector count: %u\n", usbHandle->GetFSName(portPart), usbHandle->GetLBAStart(portPart), usbHandle->GetSecCount(portPart)); + + if (strncmp(usbHandle->GetFSName(portPart), "FAT", 3) == 0) + { + WbfsList[part_num] = new Wbfs_Fat(usbHandle->GetLBAStart(portPart), usbHandle->GetSecCount(portPart), part_num, usbPort); + } + else if (strncmp(usbHandle->GetFSName(portPart), "NTFS", 4) == 0) + { + WbfsList[part_num] = new Wbfs_Ntfs(usbHandle->GetLBAStart(portPart), usbHandle->GetSecCount(portPart), part_num, usbPort); + } + else if (strncmp(usbHandle->GetFSName(portPart), "LINUX", 5) == 0) + { + WbfsList[part_num] = new Wbfs_Ext(usbHandle->GetLBAStart(portPart), usbHandle->GetSecCount(portPart), part_num, usbPort); + } + else if (strncmp(usbHandle->GetFSName(portPart), "WBFS", 4) == 0) + { + WbfsList[part_num] = new Wbfs_Wbfs(usbHandle->GetLBAStart(portPart), usbHandle->GetSecCount(portPart), part_num, usbPort); + } + else + { + return -1; + } + + if (WbfsList[part_num]->Open() != 0) + { + delete WbfsList[part_num]; + WbfsList[part_num] = NULL; + return -1; + } + + return 0; +} + +bool WBFS_Close(int part_num) +{ + if(!VALID(part_num)) + return false; + + delete WbfsList[part_num]; + WbfsList[part_num] = NULL; + + gameList.RemovePartition(part_num); + + return true; +} + +void WBFS_CloseAll() +{ + gameList.clear(); + + for(u32 i = 0; i < WbfsList.size(); ++i) + WBFS_Close(i); +} + +s32 WBFS_Format(u32 lba, u32 size, u32 port) +{ + Wbfs_Wbfs Part(WBFS_MIN_DEVICE, lba, size, port); + + return Part.Format(); +} + +s32 WBFS_GetCount(int part_num, u32 *count) +{ + if(!VALID(part_num)) + return -1; + + int ret = WbfsList[part_num]->GetCount(count); + + return ret; +} + +s32 WBFS_GetHeaders(int part_num, struct discHdr *outbuf, u32 cnt, u32 len) +{ + if(!VALID(part_num)) + return -1; + + return WbfsList[part_num]->GetHeaders(outbuf, cnt, len); +} + +s32 WBFS_CheckGame(u8 *discid) +{ + int part_num = gameList.GetPartitionNumber(discid); + if(!VALID(part_num)) + return 0; + + return WbfsList[part_num]->CheckGame(discid); +} + +s32 WBFS_AddGame(void) +{ + if(!VALID(Settings.partition)) + return -1; + + return WbfsList[Settings.partition]->AddGame(); +} + +s32 WBFS_RemoveGame(u8 *discid) +{ + int part_num = gameList.GetPartitionNumber(discid); + if(!VALID(part_num)) + return -1; + + return WbfsList[part_num]->RemoveGame(discid); +} + +s32 WBFS_GameSize(u8 *discid, f32 *size) +{ + int part_num = gameList.GetPartitionNumber(discid); + if(!VALID(part_num)) + return -1; + + return WbfsList[part_num]->GameSize(discid, size); +} + +s32 WBFS_DiskSpace(f32 *used, f32 *free) +{ + if(!VALID(Settings.partition)) + return -1; + + return WbfsList[Settings.partition]->DiskSpace(used, free); +} + +s32 WBFS_RenameGame(u8 *discid, const void *newname) +{ + int part_num = gameList.GetPartitionNumber(discid); + if(!VALID(part_num)) + return -1; + + return WbfsList[part_num]->RenameGame(discid, newname); +} + +s32 WBFS_ReIDGame(u8 *discid, const void *newID) +{ + int part_num = gameList.GetPartitionNumber(discid); + if(!VALID(part_num)) + return -1; + + return WbfsList[part_num]->ReIDGame(discid, newID); +} + +u64 WBFS_EstimeGameSize(void) +{ + if(!VALID(Settings.partition)) + return 0; + + return WbfsList[Settings.partition]->EstimateGameSize(); +} + +s32 WBFS_GetFragList(u8 *id) +{ + int part_num = gameList.GetPartitionNumber(id); + if(!VALID(part_num)) + return -1; + + return WbfsList[part_num]->GetFragList(id); +} diff --git a/source/usbloader/wbfs.h b/source/usbloader/wbfs.h new file mode 100644 index 0000000..582f2a0 --- /dev/null +++ b/source/usbloader/wbfs.h @@ -0,0 +1,50 @@ +#ifndef _WBFS_H_ +#define _WBFS_H_ + +#include "libs/libwbfs/libwbfs.h" +#include "usbloader/disc.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define PART_FS_WBFS 0 +#define PART_FS_FAT 1 +#define PART_FS_NTFS 2 +#define PART_FS_EXT 3 + + /* Macros */ +#define WBFS_MIN_DEVICE 1 +#define WBFS_MAX_DEVICE 2 + + /* Prototypes */ + s32 WBFS_Init(u32 device); + s32 WBFS_ReInit(u32 device); + s32 WBFS_Format(u32 lba, u32 size, u32 port); + s32 WBFS_GetCount(int part, u32 *count); + s32 WBFS_GetHeaders(int part, struct discHdr *, u32, u32); + s32 WBFS_CheckGame(u8 *gameid); + s32 WBFS_AddGame(void); + s32 WBFS_RemoveGame(u8 *gameid); + s32 WBFS_GameSize(u8 *gameid, f32 *size); + s32 WBFS_DiskSpace(f32 *used, f32 *free); + s32 WBFS_RenameGame(u8 *gameid, const void *newname); + s32 WBFS_ReIDGame(u8 *discid, const void *newID); + u64 WBFS_EstimeGameSize(void); + + s32 WBFS_GetFragList(u8 *id); + + s32 WBFS_OpenAll(); + s32 WBFS_OpenPart(int part_num); + wbfs_disc_t* WBFS_OpenDisc(u8 *discid); + void WBFS_CloseDisc(wbfs_disc_t *disc); + bool WBFS_Close(int part); + void WBFS_CloseAll(); + bool WBFS_Selected(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/usbloader/wbfs/wbfs_base.cpp b/source/usbloader/wbfs/wbfs_base.cpp new file mode 100644 index 0000000..94112d6 --- /dev/null +++ b/source/usbloader/wbfs/wbfs_base.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include + +#include "Controls/DeviceHandler.hpp" +#include "usbloader/sdhc.h" +#include "usbloader/usbstorage2.h" +#include "usbloader/wbfs.h" +#include "utils/tools.h" + +#include "wbfs_rw.h" +#include "wbfs_base.h" + +Wbfs::Wbfs(u32 l, u32 s, u32 part, u32 port) + : hdd(NULL), lba(l), size(s), partition(part), usbport(port) +{ +} + +s32 Wbfs::Init(u32 device) +{ + s32 ret; + + switch (WBFS_DEVICE_USB) + { + case WBFS_DEVICE_USB: + /* Initialize USB storage */ + + if (DeviceHandler::GetUSBPartitionCount() > 0) + { + /* Setup callbacks */ + readCallback = __ReadUSB; + writeCallback = __WriteUSB; + } + else + return -1; + break; + case WBFS_DEVICE_SDHC: + /* Initialize SDHC */ + ret = SDHC_Init(); + + if (ret) + { + /* Setup callbacks */ + readCallback = __ReadSDHC; + writeCallback = __WriteSDHC; + } + else return -1; + break; + } + + return 0; +} + +// Default behavior: can't format +s32 Wbfs::Format() +{ + return -1; +} + +s32 Wbfs::CheckGame(u8 *discid) +{ + wbfs_disc_t *disc = NULL; + + /* Try to open game disc */ + disc = OpenDisc(discid); + if (disc) + { + /* Close disc */ + CloseDisc(disc); + + return 1; + } + + return 0; +} + +s32 Wbfs::GameSize(u8 *discid, f32 *size) +{ + if(!discid) return 0; + + /* Open disc */ + wbfs_disc_t *disc = OpenDisc(discid); + if (!disc) return -2; + + u32 sectors = wbfs_disc_sector_used(disc); + + /* Copy value */ + if(size) + *size = (disc->p->wbfs_sec_sz / GB_SIZE) * sectors; + + /* Close disc */ + CloseDisc(disc); + + return 0; +} diff --git a/source/usbloader/wbfs/wbfs_base.h b/source/usbloader/wbfs/wbfs_base.h new file mode 100644 index 0000000..e7be856 --- /dev/null +++ b/source/usbloader/wbfs/wbfs_base.h @@ -0,0 +1,45 @@ +#ifndef _H +#define _H + +#include "libs/libwbfs/libwbfs.h" +#include "usbloader/frag.h" +#include "usbloader/wbfs.h" + +#define CACHE_SIZE 32 +#define CACHED_SECTORS 64 + +class Wbfs +{ + public: + Wbfs(u32 lba, u32 size, u32 part, u32 usbport); + virtual ~Wbfs() { Close(); }; + static s32 Init(u32); + s32 CheckGame(u8 *); + s32 GameSize(u8 *, f32 *); + bool IsMounted() { return hdd == 0; }; + virtual s32 GetFragList(u8 *id) { return 0; }; + + virtual s32 Open() = 0; + virtual void Close() {}; + virtual wbfs_disc_t* OpenDisc(u8 *discid) = 0; + virtual void CloseDisc(wbfs_disc_t *disc) = 0; + virtual s32 Format(); + virtual s32 GetCount(u32 *) = 0; + virtual s32 GetHeaders(struct discHdr *, u32, u32) = 0; + virtual s32 AddGame(void) = 0; + virtual s32 RemoveGame(u8 *) = 0; + virtual s32 DiskSpace(f32 *, f32 *) = 0; + virtual s32 RenameGame(u8 *, const void *) = 0; + virtual s32 ReIDGame(u8 *discid, const void *newID) = 0; + virtual u64 EstimateGameSize(void) = 0; + virtual u8 GetFSType(void) const { return PART_FS_WBFS; } + const wbfs_t *GetHDDHandle(void) { return hdd; } + protected: + wbfs_t *hdd; + const u32 lba; + const u32 size; + const u32 partition; + const u32 usbport; +}; + +#endif //_H diff --git a/source/usbloader/wbfs/wbfs_ext.h b/source/usbloader/wbfs/wbfs_ext.h new file mode 100644 index 0000000..3d930c9 --- /dev/null +++ b/source/usbloader/wbfs/wbfs_ext.h @@ -0,0 +1,16 @@ +#ifndef _WBFS_EXT_H +#define _WBFS_EXT_H + +#include "wbfs_fat.h" + +class Wbfs_Ext: public Wbfs_Fat +{ + public: + Wbfs_Ext(u32 lba, u32 size, u32 part, u32 port) : + Wbfs_Fat(lba, size, part, port) + { + } + virtual u8 GetFSType(void) { return PART_FS_EXT; } +}; + +#endif //_WBFS_NTFS_H diff --git a/source/usbloader/wbfs/wbfs_fat.cpp b/source/usbloader/wbfs/wbfs_fat.cpp new file mode 100644 index 0000000..df830e5 --- /dev/null +++ b/source/usbloader/wbfs/wbfs_fat.cpp @@ -0,0 +1,860 @@ +// WBFS FAT by oggzee + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Controls/DeviceHandler.hpp" +#include "FileOperations/fileops.h" +#include "settings/CSettings.h" +#include "settings/GameTitles.h" +#include "usbloader/disc.h" +#include "usbloader/usbstorage2.h" +#include "language/gettext.h" +#include "libs/libfat/fatfile_frag.h" +#include "utils/ShowError.h" +#include "wbfs_fat.h" +#include "prompts/ProgressWindow.h" +#include "usbloader/wbfs.h" +#include "usbloader/GameList.h" +#include "utils/tools.h" +#include "wbfs_rw.h" + +#include "gecko.h" + +#define MAX_FAT_PATH 1024 +#define TITLE_LEN 64 + +using namespace std; + +static const char wbfs_fat_dir[] = "/wbfs"; +static const char invalid_path[] = "/\\:|<>?*\"'"; +extern u32 hdd_sector_size[2]; +extern int install_abort_signal; + +inline bool isGameID(const char *id) +{ + for (int i = 0; i < 6; i++) + if (!isalnum((int) id[i])) + return false; + + return true; +} + +Wbfs_Fat::Wbfs_Fat(u32 lba, u32 size, u32 part, u32 port) : + Wbfs(lba, size, part, port), fat_hdr_list(NULL), fat_hdr_count(0) +{ + memset(wbfs_fs_drive, 0, sizeof(wbfs_fs_drive)); +} + +s32 Wbfs_Fat::Open() +{ + Close(); + + if(partition < (u32) DeviceHandler::GetUSBPartitionCount()) + { + PartitionHandle *usbHandle = DeviceHandler::Instance()->GetUSBHandleFromPartition(partition); + int portPart = DeviceHandler::PartitionToPortPartition(partition); + if (lba == usbHandle->GetLBAStart(portPart)) + { + snprintf(wbfs_fs_drive, sizeof(wbfs_fs_drive), "%s:", usbHandle->MountName(portPart)); + return 0; + } + } + + return -1; +} + +void Wbfs_Fat::Close() +{ + if (hdd) + { + wbfs_close(hdd); + hdd = NULL; + } + + memset(wbfs_fs_drive, 0, sizeof(wbfs_fs_drive)); +} + +wbfs_disc_t* Wbfs_Fat::OpenDisc(u8 *discid) +{ + char fname[MAX_FAT_PATH]; + + // wbfs 'partition' file + if (!FindFilename(discid, fname, sizeof(fname))) return NULL; + + if (strcasecmp(strrchr(fname, '.'), ".iso") == 0) + { + // .iso file + // create a fake wbfs_disc + int fd; + fd = open(fname, O_RDONLY); + if (fd == -1) return NULL; + wbfs_disc_t *iso_file = (wbfs_disc_t *) calloc(sizeof(wbfs_disc_t), 1); + if (iso_file == NULL) return NULL; + // mark with a special wbfs_part + wbfs_iso_file.wbfs_sec_sz = hdd_sector_size[usbport]; + iso_file->p = &wbfs_iso_file; + iso_file->header = (wbfs_disc_info_t*) malloc(sizeof(wbfs_disc_info_t)); + if(!iso_file->header) + { + free(iso_file); + return NULL; + } + read(fd, iso_file->header, sizeof(wbfs_disc_info_t)); + iso_file->i = fd; + return iso_file; + } + + wbfs_t *part = OpenPart(fname); + if (!part) return NULL; + + wbfs_disc_t *disc = wbfs_open_disc(part, discid); + if(!disc) + { + ClosePart(part); + return NULL; + } + + return disc; +} + +void Wbfs_Fat::CloseDisc(wbfs_disc_t* disc) +{ + if (!disc) return; + wbfs_t *part = disc->p; + + // is this really a .iso file? + if (part == &wbfs_iso_file) + { + close(disc->i); + free(disc->header); + free(disc); + return; + } + + wbfs_close_disc(disc); + ClosePart(part); + return; +} + +s32 Wbfs_Fat::GetCount(u32 *count) +{ + GetHeadersCount(); + *count = fat_hdr_count; + return 0; +} + +s32 Wbfs_Fat::GetHeaders(struct discHdr *outbuf, u32 cnt, u32 len) +{ + if(cnt*len > fat_hdr_count*sizeof(struct discHdr)) + return -1; + + memcpy(outbuf, fat_hdr_list, cnt*len); + + if(fat_hdr_list) + free(fat_hdr_list); + fat_hdr_list = NULL; + fat_hdr_count = 0; + + return 0; +} + +s32 Wbfs_Fat::AddGame(void) +{ + static struct discHdr header ATTRIBUTE_ALIGN( 32 ); + char path[MAX_FAT_PATH]; + wbfs_t *part = NULL; + s32 ret; + + // read ID from DVD + Disc_ReadHeader(&header); + // path + GetDir(&header, path); + // create wbfs 'partition' file + part = CreatePart(header.id, path); + if (!part) return -1; + /* Add game to device */ + partition_selector_t part_sel = (partition_selector_t) Settings.InstallPartitions; + + ret = wbfs_add_disc(part, __ReadDVD, NULL, ShowProgress, part_sel, 0); + wbfs_trim(part); + ClosePart(part); + + if(install_abort_signal) + RemoveGame(header.id); + if (ret < 0) return ret; + + return 0; +} + +s32 Wbfs_Fat::RemoveGame(u8 *discid) +{ + char fname[MAX_FAT_PATH]; + int loc; + // wbfs 'partition' file + loc = FindFilename(discid, fname, sizeof(fname)); + if (!loc) return -1; + split_create(&split, fname, 0, 0, true); + split_close(&split); + if (loc == 1) return 0; + + // game is in subdir + // remove optional .txt file + DIR *dir = NULL; + struct dirent *dirent = NULL; + char path[MAX_FAT_PATH]; + char name[MAX_FAT_PATH]; + strncpy(path, fname, sizeof(path)); + char *p = strrchr(path, '/'); + if (p) *p = 0; + dir = opendir(path); + if (!dir) return 0; + while ((dirent = readdir(dir)) != 0) + { + snprintf(name, sizeof(name), dirent->d_name); + if (name[0] == '.') continue; + if (name[6] != '_') continue; + if (strncasecmp(name, (char*) discid, 6) != 0) continue; + p = strrchr(name, '.'); + if (!p) continue; + if (strcasecmp(p, ".txt") != 0) continue; + snprintf(fname, sizeof(fname), "%s/%s", path, name); + remove(fname); + break; + } + closedir(dir); + // remove game subdir + remove(path); + + return 0; +} + +s32 Wbfs_Fat::DiskSpace(f32 *used, f32 *free) +{ + static f32 used_cached = 0.0; + static f32 free_cached = 0.0; + static int game_count = 0; + + //! Since it's freaken slow, only refresh on new gamecount + if(used_cached == 0.0 || game_count != gameList.GameCount()) + { + game_count = gameList.GameCount(); + } + else + { + *used = used_cached; + *free = free_cached; + return 0; + } + + f32 size; + int ret; + struct statvfs wbfs_fat_vfs; + + *used = used_cached = 0.0; + *free = free_cached = 0.0; + ret = statvfs(wbfs_fs_drive, &wbfs_fat_vfs); + if (ret) return -1; + + /* FS size in GB */ + size = (f32) wbfs_fat_vfs.f_frsize * (f32) wbfs_fat_vfs.f_blocks / GB_SIZE; + *free = free_cached = (f32) wbfs_fat_vfs.f_frsize * (f32) wbfs_fat_vfs.f_bfree / GB_SIZE; + *used = used_cached = size - *free; + + return 0; +} + +s32 Wbfs_Fat::RenameGame(u8 *discid, const void *newname) +{ + wbfs_t *part = OpenPart((char *) discid); + if (!part) return -1; + + s32 ret = wbfs_ren_disc(part, discid, (u8*) newname); + + ClosePart(part); + + return ret; +} + +s32 Wbfs_Fat::ReIDGame(u8 *discid, const void *newID) +{ + wbfs_t *part = OpenPart((char *) discid); + if (!part) return -1; + + s32 ret = wbfs_rID_disc(part, discid, (u8*) newID); + + ClosePart(part); + + if (ret == 0) + { + char fname[100]; + char fnamenew[100]; + s32 cnt = 0x31; + + Filename(discid, fname, sizeof(fname), NULL); + Filename((u8*) newID, fnamenew, sizeof(fnamenew), NULL); + + int stringlength = strlen(fname); + + while (rename(fname, fnamenew) == 0) + { + fname[stringlength] = cnt; + fname[stringlength + 1] = 0; + fnamenew[stringlength] = cnt; + fnamenew[stringlength + 1] = 0; + cnt++; + } + } + + return ret; +} + +u64 Wbfs_Fat::EstimateGameSize() +{ + wbfs_t *part = NULL; + u64 size = (u64) 143432 * 2 * 0x8000ULL; + u32 n_sector = size / hdd_sector_size[usbport]; + + // init a temporary dummy part + // as a placeholder for wbfs_size_disc + wbfs_set_force_mode(1); + part = wbfs_open_partition(nop_rw_sector, nop_rw_sector, NULL, hdd_sector_size[usbport], n_sector, 0, 1); + wbfs_set_force_mode(0); + if (!part) return -1; + + partition_selector_t part_sel = (partition_selector_t) Settings.InstallPartitions; + + u64 estimated_size = wbfs_estimate_disc(part, __ReadDVD, NULL, part_sel); + + wbfs_close(part); + + return estimated_size; +} + +// TITLE [GAMEID] +bool Wbfs_Fat::CheckLayoutB(char *fname, int len, u8* id, char *fname_title) +{ + if (len <= 8) return false; + if (fname[len - 8] != '[' || fname[len - 1] != ']') return false; + if (!isGameID(&fname[len - 7])) return false; + strncpy(fname_title, fname, TITLE_LEN); + // cut at '[' + fname_title[len - 8] = 0; + int n = strlen(fname_title); + if (n == 0) return false; + // cut trailing _ or ' ' + if (fname_title[n - 1] == ' ' || fname_title[n - 1] == '_') + { + fname_title[n - 1] = 0; + } + if (strlen(fname_title) == 0) return false; + if (id) + { + memcpy(id, &fname[len - 7], 6); + id[6] = 0; + } + return true; +} + +void Wbfs_Fat::AddHeader(struct discHdr *discHeader) +{ + //! First allocate before reallocating + if(!fat_hdr_list) + fat_hdr_list = (struct discHdr *) malloc(sizeof(struct discHdr)); + + struct discHdr *tmpList = (struct discHdr *) realloc(fat_hdr_list, (fat_hdr_count+1) * sizeof(struct discHdr)); + if(!tmpList) + return; //out of memory, keep the list until now and stop + + for(int j = 0; j < 6; ++j) + discHeader->id[j] = toupper((int) discHeader->id[j]); + + fat_hdr_list = tmpList; + memcpy(&fat_hdr_list[fat_hdr_count], discHeader, sizeof(struct discHdr)); + GameTitles.SetGameTitle(discHeader->id, discHeader->title); + fat_hdr_count++; +} + +s32 Wbfs_Fat::GetHeadersCount() +{ + char path[MAX_FAT_PATH]; + char fname[MAX_FAT_PATH]; + char fpath[MAX_FAT_PATH]; + char fname_title[TITLE_LEN]; + struct discHdr tmpHdr; + struct stat st; + int is_dir; + int len; + u8 id[8]; + memset(id, 0, sizeof(id)); + const char *title; + DIR *dir_iter; + struct dirent *dirent; + + if(fat_hdr_list) + free(fat_hdr_list); + fat_hdr_list = NULL; + fat_hdr_count = 0; + + strcpy(path, wbfs_fs_drive); + strcat(path, wbfs_fat_dir); + + dir_iter = opendir(path); + if (!dir_iter) return 0; + + while ((dirent = readdir(dir_iter)) != 0) + { + if (dirent->d_name[0] == '.') continue; + + snprintf(fname, sizeof(fname), "%s", dirent->d_name); + + // reset id and title + memset(id, 0, sizeof(id)); + *fname_title = 0; + + const char * fileext = strrchr(fname, '.'); + if(fileext && (strcasecmp(fileext, ".wbfs") == 0 || + strcasecmp(fileext, ".iso") == 0 || strcasecmp(fileext, ".ciso") == 0)) + { + // usb:/wbfs/GAMEID.wbfs + // or usb:/wbfs/GAMEID.iso + // or usb:/wbfs/GAMEID.ciso + int n = fileext - fname; // length withouth .wbfs + memcpy(id, fname, 6); + if (n != 6) + { + // TITLE [GAMEID].wbfs + if (!CheckLayoutB(fname, n, id, fname_title)) continue; + } + snprintf(fpath, sizeof(fpath), "%s/%s", path, fname); + is_dir = 0; + } + else + { + snprintf(fname, sizeof(fname), "%s/%s", path, dirent->d_name); + + if(stat(fname, &st) != 0) + continue; + + is_dir = S_ISDIR( st.st_mode ); + if(!is_dir) continue; + + snprintf(fname, sizeof(fname), "%s", dirent->d_name); + + len = strlen(fname); + if (len < 6) continue; // less than "GAMEID" + + if(len == 6) + { + // usb:/wbfs/GAMEID/GAMEID.wbfs + if(!isGameID(fname)) + continue; + + memcpy(id, fname, 6); + } + else if(len >= 8 ) // GAMEID_Title or Title_[GameID] + { + int lay_a = 0; + int lay_b = 0; + if (CheckLayoutB(fname, len, id, fname_title)) + { + // usb:/wbfs/TITLE[GAMEID]/GAMEID.wbfs + lay_b = 1; + } + else if (fname[6] == '_') + { + // usb:/wbfs/GAMEID_TITLE/GAMEID.wbfs + memcpy(id, fname, 6); + + if(isGameID((char*) id)) + { + lay_a = 1; + snprintf(fname_title, sizeof(fname_title), &fname[7]); + } + } + + if (!lay_a && !lay_b) continue; + } + else // Todo : Add usb:/wbfs/Title/GAMEID.wbfs + continue; + + + // check ahead, make sure it succeeds + snprintf(fpath, sizeof(fpath), "%s/%s/%.6s.wbfs", path, dirent->d_name, (char *) id); + } + + // if we have titles.txt entry use that + title = GameTitles.GetTitle(id); + // if no titles.txt get title from dir or file name + if (strlen(title) == 0 && !Settings.ForceDiscTitles && strlen(fname_title) > 0) + title = fname_title; + + if (strlen(title) > 0) + { + memset(&tmpHdr, 0, sizeof(tmpHdr)); + memcpy(tmpHdr.id, id, 6); + strncpy(tmpHdr.title, title, sizeof(tmpHdr.title)-1); + tmpHdr.magic = 0x5D1C9EA3; + AddHeader(&tmpHdr); + continue; + } + + // Check for existing wbfs/iso/ciso file in the directory + if(is_dir) + { + if (stat(fpath, &st) != 0) + { + // look for direct .iso file + strcpy(strrchr(fpath, '.'), ".iso"); // replace .wbfs with .iso + if (stat(fpath, &st) != 0) + { + // look for direct .ciso file + strcpy(strrchr(fpath, '.'), ".ciso"); // replace .iso with .ciso + if (stat(fpath, &st) != 0) continue; + } + } + } + + fileext = strrchr(fpath, '.'); + // Sanity check + if(!fileext) + continue; + + // else read it from file directly + if (strcasecmp(fileext, ".wbfs") == 0) + { + // wbfs file directly + FILE *fp = fopen(fpath, "rb"); + if (fp != NULL) + { + fseek(fp, 512, SEEK_SET); + fread(&tmpHdr, sizeof(struct discHdr), 1, fp); + fclose(fp); + tmpHdr.is_ciso = 0; + if ((tmpHdr.magic == 0x5D1C9EA3) && (memcmp(tmpHdr.id, id, 6) == 0)) + { + AddHeader(&tmpHdr); + continue; + } + } + // no title found, read it from wbfs file + // but this is a little bit slower + // open 'partition' file + wbfs_t *part = OpenPart(fpath); + if (!part) + continue; + + u32 size; + // Get header + int ret = wbfs_get_disc_info(part, 0, (u8*) &tmpHdr, sizeof(struct discHdr), &size); + ClosePart(part); + if (ret == 0) + { + AddHeader(&tmpHdr); + continue; + } + + } + else if (strcasecmp(fileext, ".iso") == 0) + { + // iso file + FILE *fp = fopen(fpath, "rb"); + if (fp != NULL) + { + fseek(fp, 0, SEEK_SET); + fread(&tmpHdr, sizeof(struct discHdr), 1, fp); + fclose(fp); + tmpHdr.is_ciso = 0; + if ((tmpHdr.magic == 0x5D1C9EA3) && (memcmp(tmpHdr.id, id, 6) == 0)) + { + AddHeader(&tmpHdr); + continue; + } + } + } + else if (strcasecmp(fileext, ".ciso") == 0) + { + // ciso file + FILE *fp = fopen(fpath, "rb"); + if (fp != NULL) + { + fseek(fp, 0x8000, SEEK_SET); + fread(&tmpHdr, sizeof(struct discHdr), 1, fp); + fclose(fp); + tmpHdr.is_ciso = 1; + if ((tmpHdr.magic == 0x5D1C9EA3) && (memcmp(tmpHdr.id, id, 6) == 0)) + { + AddHeader(&tmpHdr); + continue; + } + } + } + } + + closedir(dir_iter); + + return 0; +} + +int Wbfs_Fat::FindFilename(u8 *id, char *fname, int len) +{ + struct stat st; + // look for direct .wbfs file + Filename(id, fname, len, NULL); + if (stat(fname, &st) == 0) return 1; + // look for direct .iso file + strcpy(strrchr(fname, '.'), ".iso"); // replace .wbfs with .iso + if (stat(fname, &st) == 0) return 1; + // look for direct .ciso file + strcpy(strrchr(fname, '.'), ".ciso"); // replace .iso with .ciso + if (stat(fname, &st) == 0) return 1; + + // direct file not found, check subdirs + *fname = 0; + DIR *dir_iter; + struct dirent *dirent; + char gameID[7]; + snprintf(gameID, sizeof(gameID), (char *) id); + char path[MAX_FAT_PATH]; + strcpy(path, wbfs_fs_drive); + strcat(path, wbfs_fat_dir); + + dir_iter = opendir(path); + if (!dir_iter) + return 0; + + while ((dirent = readdir(dir_iter)) != 0) + { + if(strcasestr(dirent->d_name, gameID) == NULL) continue; + + if (dirent->d_name[0] == '.') continue; + int n = strlen(dirent->d_name); + if (n < 6) continue; + + const char *fileext = strrchr(dirent->d_name, '.'); + if(fileext && (strcasecmp(fileext, ".wbfs") == 0 || + strcasecmp(fileext, ".iso") == 0 || strcasecmp(fileext, ".ciso") == 0)) + { + // TITLE [GAMEID].wbfs + char fn_title[TITLE_LEN]; + u8 fn_id[8]; + int n = fileext - dirent->d_name; // length withouth .wbfs + if (!CheckLayoutB(dirent->d_name, n, fn_id, fn_title)) continue; + if (strncasecmp((char*) fn_id, gameID, 6) != 0) continue; + snprintf(fname, len, "%s/%s", path, dirent->d_name); + if (stat(fname, &st) == 0) break; + } + + snprintf(fname, len, "%s/%s", path, dirent->d_name); + + if(stat(fname, &st) != 0) + { + *fname = 0; + continue; + } + + if (S_ISDIR( st.st_mode )) + { + // look for .wbfs file + snprintf(fname, len, "%s/%s/%.6s.wbfs", path, dirent->d_name, gameID); + if (stat(fname, &st) == 0) break; + // look for .iso file + snprintf(fname, len, "%s/%s/%.6s.iso", path, dirent->d_name, gameID); + if (stat(fname, &st) == 0) break; + // look for .ciso file + snprintf(fname, len, "%s/%s/%.6s.ciso", path, dirent->d_name, gameID); + if (stat(fname, &st) == 0) break; + } + + *fname = 0; + } + closedir(dir_iter); + + if (*fname) + return 2; + + return 0; +} + +wbfs_t* Wbfs_Fat::OpenPart(char *fname) +{ + wbfs_t *part = NULL; + int ret; + + // wbfs 'partition' file + ret = split_open(&split, fname); + if (ret) return NULL; + + wbfs_set_force_mode(1); + + part = wbfs_open_partition(split_read_sector, nop_rw_sector, //readonly //split_write_sector, + &split, hdd_sector_size[usbport], split.total_sec, 0, 0); + + wbfs_set_force_mode(0); + + if (!part) + split_close(&split); + + return part; +} + +void Wbfs_Fat::ClosePart(wbfs_t* part) +{ + if (!part) return; + split_info_t *s = (split_info_t*) part->callback_data; + wbfs_close(part); + if (s) split_close(s); +} + +void Wbfs_Fat::Filename(u8 *id, char *fname, int len, char *path) +{ + if (path == NULL) + { + snprintf(fname, len, "%s%s/%.6s.wbfs", wbfs_fs_drive, wbfs_fat_dir, id); + } + else + { + snprintf(fname, len, "%s/%.6s.wbfs", path, id); + } +} + +void Wbfs_Fat::GetDir(struct discHdr *header, char *path) +{ + strcpy(path, wbfs_fs_drive); + strcat(path, wbfs_fat_dir); + if (Settings.InstallToDir) + { + strcat(path, "/"); + int layout = 0; + if (Settings.InstallToDir == 2) layout = 1; + mk_gameid_title(header, path + strlen(path), 0, layout); + } +} + +wbfs_t* Wbfs_Fat::CreatePart(u8 *id, char *path) +{ + char fname[MAX_FAT_PATH]; + wbfs_t *part = NULL; + u64 size = (u64) 143432 * 2 * 0x8000ULL; + u32 n_sector = size / 512; + int ret; + + if(!CreateSubfolder(path)) // game subdir + { + ProgressStop(); + ShowError(tr("Error creating path: %s"), path); + return NULL; + } + + // 1 cluster less than 4gb + u64 OPT_split_size = 4LL * 1024 * 1024 * 1024 - 32 * 1024; + + if(Settings.GameSplit == GAMESPLIT_NONE && DeviceHandler::GetFilesystemType(USB1+Settings.partition) != PART_FS_FAT) + OPT_split_size = (u64) 100LL * 1024 * 1024 * 1024 - 32 * 1024; + + else if(Settings.GameSplit == GAMESPLIT_2GB) + // 1 cluster less than 2gb + OPT_split_size = (u64)2LL * 1024 * 1024 * 1024 - 32 * 1024; + + Filename(id, fname, sizeof(fname), path); + printf("Writing to %s\n", fname); + ret = split_create(&split, fname, OPT_split_size, size, true); + if (ret) return NULL; + + // force create first file + u32 scnt = 0; + int fd = split_get_file(&split, 0, &scnt, 0); + if (fd < 0) + { + printf("ERROR creating file\n"); + sleep(2); + split_close(&split); + return NULL; + } + + wbfs_set_force_mode(1); + + part = wbfs_open_partition(split_read_sector, split_write_sector, &split, hdd_sector_size[usbport], n_sector, 0, 1); + + wbfs_set_force_mode(0); + + if (!part) + split_close(&split); + + return part; +} + +void Wbfs_Fat::mk_gameid_title(struct discHdr *header, char *name, int re_space, int layout) +{ + int i, len; + char title[100]; + char id[7]; + + snprintf(id, sizeof(id), (char *) header->id); + snprintf(title, sizeof(title), header->title); + CleanTitleCharacters(title); + + if (layout == 0) + { + sprintf(name, "%s_%s", id, title); + } + else + { + sprintf(name, "%s [%s]", title, id); + } + + // replace space with '_' + if (re_space) + { + len = strlen(name); + for (i = 0; i < len; i++) + { + if (name[i] == ' ') name[i] = '_'; + } + } +} + +void Wbfs_Fat::CleanTitleCharacters(char *title) +{ + int i, len; + // trim leading space + len = strlen(title); + while (*title == ' ') + { + memmove(title, title + 1, len); + len--; + } + // trim trailing space - not allowed on windows directories + while (len && title[len - 1] == ' ') + { + title[len - 1] = 0; + len--; + } + // replace silly chars with '_' + for (i = 0; i < len; i++) + { + if (strchr(invalid_path, title[i]) || iscntrl((int) title[i])) + { + title[i] = '_'; + } + } +} + +s32 Wbfs_Fat::GetFragList(u8 *id) +{ + char fname[1024]; + + int ret = FindFilename(id, fname, sizeof(fname)); + if (!ret) return -1; + + return get_frag_list_for_file(fname, id, GetFSType(), lba, hdd_sector_size[usbport]); +} diff --git a/source/usbloader/wbfs/wbfs_fat.h b/source/usbloader/wbfs/wbfs_fat.h new file mode 100644 index 0000000..6abe2e8 --- /dev/null +++ b/source/usbloader/wbfs/wbfs_fat.h @@ -0,0 +1,61 @@ +#ifndef _WBFS_FAT_H +#define _WBFS_FAT_H + +#include + +#include "usbloader/splits.h" +#include "usbloader/wbfs.h" +#include "wbfs_base.h" + +class Wbfs_Fat: public Wbfs +{ + public: + Wbfs_Fat(u32 lba, u32 size, u32 part, u32 port); + + virtual s32 Open(); + virtual void Close(); + wbfs_disc_t* OpenDisc(u8 *); + void CloseDisc(wbfs_disc_t *); + + s32 GetCount(u32 *); + s32 GetHeaders(struct discHdr *, u32, u32); + + s32 AddGame(); + s32 RemoveGame(u8 *); + + s32 DiskSpace(f32 *, f32 *); + + s32 RenameGame(u8 *, const void *); + s32 ReIDGame(u8 *, const void *); + + u64 EstimateGameSize(); + + void AddHeader(struct discHdr *discHeader); + + virtual s32 GetFragList(u8 *); + virtual u8 GetFSType(void) { return PART_FS_FAT; } + + static bool CheckLayoutB(char *fname, int len, u8* id, char *fname_title); + static void CleanTitleCharacters(char *title); + protected: + + split_info_t split; + + struct discHdr *fat_hdr_list; + u32 fat_hdr_count; + char wbfs_fs_drive[16]; + + wbfs_t* OpenPart(char *fname); + void ClosePart(wbfs_t* part); + wbfs_t* CreatePart(u8 *id, char *path); + int FindFilename(u8 *id, char *fname, int len); + void Filename(u8 *id, char *fname, int len, char *path); + s32 GetHeadersCount(); + void GetDir(struct discHdr *header, char *path); + + void mk_gameid_title(struct discHdr *header, char *name, int re_space, int layout); + + static s32 nop_rw_sector(void *_fp, u32 lba, u32 count, void* buf) { return 0; } +}; + +#endif //_WBFS_FAT_H diff --git a/source/usbloader/wbfs/wbfs_ntfs.h b/source/usbloader/wbfs/wbfs_ntfs.h new file mode 100644 index 0000000..5c59cf1 --- /dev/null +++ b/source/usbloader/wbfs/wbfs_ntfs.h @@ -0,0 +1,16 @@ +#ifndef _WBFS_NTFS_H +#define _WBFS_NTFS_H + +#include "wbfs_fat.h" + +class Wbfs_Ntfs: public Wbfs_Fat +{ + public: + Wbfs_Ntfs(u32 lba, u32 size, u32 part, u32 port) : + Wbfs_Fat(lba, size, part, port) + { + } + virtual u8 GetFSType(void) { return PART_FS_NTFS; } +}; + +#endif //_WBFS_NTFS_H diff --git a/source/usbloader/wbfs/wbfs_rw.c b/source/usbloader/wbfs/wbfs_rw.c new file mode 100644 index 0000000..60dcfc6 --- /dev/null +++ b/source/usbloader/wbfs/wbfs_rw.c @@ -0,0 +1,218 @@ +#include +#include +#include + +#include "usbloader/sdhc.h" +#include "usbloader/usbstorage2.h" +#include "usbloader/wdvd.h" +#include "wbfs_rw.h" + +/* Constants */ +#define MAX_NB_SECTORS 32 + +rw_sector_callback_t readCallback = NULL; +rw_sector_callback_t writeCallback = NULL; + +s32 __ReadDVD(void *fp, u32 lba, u32 len, void *iobuf) +{ + void *buffer = NULL; + + u64 offset; + u32 mod, size; + s32 ret; + + /* Calculate offset */ + offset = ((u64) lba) << 2; + + /* Calcualte sizes */ + mod = len % 32; + size = len - mod; + + /* Read aligned data */ + if (size) + { + ret = WDVD_UnencryptedRead(iobuf, size, offset); + if (ret < 0) goto out; + } + + /* Read non-aligned data */ + if (mod) + { + /* Allocate memory */ + buffer = memalign(32, 0x20); + if (!buffer) return -1; + + /* Read data */ + ret = WDVD_UnencryptedRead(buffer, 0x20, offset + size); + if (ret < 0) goto out; + + /* Copy data */ + void *ptr = ((u8 *) iobuf) + size; + memcpy(ptr, buffer, mod); + } + + /* Success */ + ret = 0; + + out: + /* Free memory */ + if (buffer) free(buffer); + + return ret; +} + +s32 __ReadUSB(void *fp, u32 lba, u32 count, void *iobuf) +{ + WBFS_PartInfo * info = (WBFS_PartInfo *) fp; + u32 cnt = 0; + s32 ret; + u32 partition_offset = info->partition_lba + (lba-info->partition_lba)*(info->wbfs_sector_size/info->hdd_sector_size); + count *= (info->wbfs_sector_size/info->hdd_sector_size); + + /* Do reads */ + while (cnt < count) + { + u8 *ptr = ((u8 *) iobuf) + (cnt * info->hdd_sector_size); + u32 sectors = (count - cnt); + + /* Read sectors is too big */ + if (sectors > MAX_NB_SECTORS) sectors = MAX_NB_SECTORS; + + /* USB read */ + ret = info->handle->readSectors(partition_offset + cnt, sectors, ptr); + if (!ret) return -1; + + /* Increment counter */ + cnt += sectors; + } + + return 0; +} + +s32 __WriteUSB(void *fp, u32 lba, u32 count, void *iobuf) +{ + WBFS_PartInfo * info = (WBFS_PartInfo *) fp; + u32 cnt = 0; + s32 ret; + u32 partition_offset = info->partition_lba + (lba-info->partition_lba)*(info->wbfs_sector_size/info->hdd_sector_size); + count *= (info->wbfs_sector_size/info->hdd_sector_size); + + /* Do writes */ + while (cnt < count) + { + u8 *ptr = ((u8 *) iobuf) + (cnt * info->hdd_sector_size); + u32 sectors = (count - cnt); + + /* Write sectors is too big */ + if (sectors > MAX_NB_SECTORS) sectors = MAX_NB_SECTORS; + + /* USB write */ + ret = info->handle->writeSectors(partition_offset + cnt, sectors, ptr); + if (!ret) return -1; + + /* Increment counter */ + cnt += sectors; + } + + return 0; +} + +s32 __ReadSDHC(void *fp, u32 lba, u32 count, void *iobuf) +{ + WBFS_PartInfo * info = (WBFS_PartInfo *) fp; + u32 cnt = 0; + s32 ret; + u32 partition_offset = info->partition_lba + (lba-info->partition_lba)*(info->wbfs_sector_size/info->hdd_sector_size); + count *= info->wbfs_sector_size/info->hdd_sector_size; + + /* Do reads */ + while (cnt < count) + { + void *ptr = ((u8 *) iobuf) + (cnt * info->wbfs_sector_size); + u32 sectors = (count - cnt); + + /* Read sectors is too big */ + if (sectors > MAX_NB_SECTORS) sectors = MAX_NB_SECTORS; + + /* SDHC read */ + ret = SDHC_ReadSectors(partition_offset + cnt, sectors, ptr); + if (!ret) return -1; + + /* Increment counter */ + cnt += sectors; + } + + return 0; +} + +s32 __WriteSDHC(void *fp, u32 lba, u32 count, void *iobuf) +{ + WBFS_PartInfo * info = (WBFS_PartInfo *) fp; + u32 cnt = 0; + s32 ret; + u32 partition_offset = info->partition_lba + (lba-info->partition_lba)*(info->wbfs_sector_size/info->hdd_sector_size); + count *= info->wbfs_sector_size/info->hdd_sector_size; + + /* Do writes */ + while (cnt < count) + { + void *ptr = ((u8 *) iobuf) + (cnt * info->wbfs_sector_size); + u32 sectors = (count - cnt); + + /* Write sectors is too big */ + if (sectors > MAX_NB_SECTORS) sectors = MAX_NB_SECTORS; + + /* SDHC write */ + ret = SDHC_WriteSectors(partition_offset + cnt, sectors, ptr); + if (!ret) return -1; + + /* Increment counter */ + cnt += sectors; + } + + return 0; +} + +s32 __ReadDVDPlain(void *iobuf, u32 len, u64 offset) +{ + void *buffer = NULL; + + u32 mod, size; + s32 ret; + + /* Calcualte sizes */ + mod = len % 32; + size = len - mod; + + /* Read aligned data */ + if (size) + { + ret = WDVD_UnencryptedRead(iobuf, size, offset); + if (ret < 0) goto out; + } + + /* Read non-aligned data */ + if (mod) + { + /* Allocate memory */ + buffer = memalign(32, 0x20); + if (!buffer) return -1; + + /* Read data */ + ret = WDVD_UnencryptedRead(buffer, 0x20, offset + size); + if (ret < 0) goto out; + + /* Copy data */ + void *ptr = ((u8 *) iobuf) + size; + memcpy(ptr, buffer, mod); + } + + /* Success */ + ret = 0; + + out: + /* Free memory */ + if (buffer) free(buffer); + + return ret; +} diff --git a/source/usbloader/wbfs/wbfs_rw.h b/source/usbloader/wbfs/wbfs_rw.h new file mode 100644 index 0000000..c84053e --- /dev/null +++ b/source/usbloader/wbfs/wbfs_rw.h @@ -0,0 +1,35 @@ +#ifndef _WBFS_RW_H +#define _WBFS_RW_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include "libs/libwbfs/libwbfs.h" + + typedef struct _WBFS_PartInfo + { + u32 wbfs_sector_size; + u32 hdd_sector_size; + u32 partition_lba; + u32 partition_num_sec; + const DISC_INTERFACE * handle; + } WBFS_PartInfo; + + extern rw_sector_callback_t readCallback; + extern rw_sector_callback_t writeCallback; + + s32 __ReadDVD(void *fp, u32 lba, u32 len, void *iobuf); + s32 __ReadUSB(void *fp, u32 lba, u32 count, void *iobuf); + s32 __WriteUSB(void *fp, u32 lba, u32 count, void *iobuf); + s32 __ReadSDHC(void *fp, u32 lba, u32 count, void *iobuf); + s32 __WriteSDHC(void *fp, u32 lba, u32 count, void *iobuf); + s32 __ReadDVDPlain(void *iobuf, u32 len, u64 offset); + +#ifdef __cplusplus +} +#endif + +#endif //_WBFS_RW_H diff --git a/source/usbloader/wbfs/wbfs_wbfs.cpp b/source/usbloader/wbfs/wbfs_wbfs.cpp new file mode 100644 index 0000000..55b13e4 --- /dev/null +++ b/source/usbloader/wbfs/wbfs_wbfs.cpp @@ -0,0 +1,230 @@ +#include "wbfs_wbfs.h" +#include "Controls/DeviceHandler.hpp" +#include "prompts/ProgressWindow.h" +#include "settings/CSettings.h" +#include "usbloader/wbfs.h" +#include "usbloader/usbstorage2.h" +#include "utils/tools.h" +#include "wbfs_rw.h" + +#define MAX_WBFS_SECTORSIZE 4096 + +extern u32 hdd_sector_size[2]; + +s32 Wbfs_Wbfs::Open() +{ + wbfs_t *part = NULL; + + PartInfo.wbfs_sector_size = MAX_WBFS_SECTORSIZE; + PartInfo.hdd_sector_size = hdd_sector_size[usbport]; + PartInfo.partition_lba = lba; + PartInfo.partition_num_sec = size; + PartInfo.handle = (usbport == 0) ? DeviceHandler::GetUSB0Interface() : DeviceHandler::GetUSB1Interface(); + + u8 * buffer = (u8 *) malloc(MAX_WBFS_SECTORSIZE); + memset(buffer, 0, MAX_WBFS_SECTORSIZE); + + if(readCallback(&PartInfo, lba, 1, buffer) < 0) + { + free(buffer); + return -1; + } + + wbfs_head_t head; + memcpy(&head, buffer, sizeof(wbfs_head_t)); + free(buffer); + + if (head.magic != wbfs_htonl(WBFS_MAGIC)) + return -1; + + /* Set correct sector values for wbfs read/write */ + PartInfo.wbfs_sector_size = 1 << head.hd_sec_sz_s; + PartInfo.partition_num_sec = head.n_hd_sec; + + /* Open partition */ + part = wbfs_open_partition(readCallback, writeCallback, &PartInfo, + PartInfo.wbfs_sector_size, PartInfo.partition_num_sec, + lba, 0); + if (!part) return -1; + + /* Close current hard disk */ + Close(); + hdd = part; + + return 0; +} + +void Wbfs_Wbfs::Close() +{ + if (hdd) + { + wbfs_close(hdd); + hdd = NULL; + } +} + +wbfs_disc_t* Wbfs_Wbfs::OpenDisc(u8 *discid) +{ + /* No device open */ + if (!hdd) return NULL; + + /* Open disc */ + return wbfs_open_disc(hdd, discid); +} + +void Wbfs_Wbfs::CloseDisc(wbfs_disc_t *disc) +{ + /* No device open */ + if (!hdd || !disc) return; + + /* Close disc */ + wbfs_close_disc(disc); +} + +s32 Wbfs_Wbfs::Format() +{ + WBFS_PartInfo HDD_Inf; + HDD_Inf.wbfs_sector_size = hdd_sector_size[usbport]; + HDD_Inf.hdd_sector_size = hdd_sector_size[usbport]; + HDD_Inf.partition_lba = lba; + HDD_Inf.partition_num_sec = size; + HDD_Inf.handle = (usbport == 0) ? DeviceHandler::GetUSB0Interface() : DeviceHandler::GetUSB1Interface(); + + //! If size is over 500GB in sectors and sector size is 512 + //! set 2048 as hdd sector size + if(size > 1048576000 && hdd_sector_size[usbport] == 512) + { + HDD_Inf.wbfs_sector_size = 2048; + HDD_Inf.partition_num_sec = size/(2048/hdd_sector_size[usbport]); + } + + wbfs_t *partition = NULL; + + /* Reset partition */ + partition = wbfs_open_partition(readCallback, writeCallback, &HDD_Inf, HDD_Inf.wbfs_sector_size, HDD_Inf.partition_num_sec, lba, 1); + if (!partition) return -1; + + /* Free memory */ + wbfs_close(partition); + + return 0; +} + +s32 Wbfs_Wbfs::GetCount(u32 *count) +{ + /* No device open */ + if (!hdd) return -1; + + /* Get list length */ + *count = wbfs_count_discs(hdd); + + return 0; +} + +s32 Wbfs_Wbfs::GetHeaders(struct discHdr *outbuf, u32 cnt, u32 len) +{ + u32 idx, size; + s32 ret; + + /* No device open */ + if (!hdd) return -1; + + for (idx = 0; idx < cnt; idx++) + { + u8 *ptr = ((u8 *) outbuf) + (idx * len); + + /* Get header */ + ret = wbfs_get_disc_info(hdd, idx, ptr, len, &size); + if (ret < 0) return ret; + } + + return 0; +} + +s32 Wbfs_Wbfs::AddGame() +{ + s32 ret; + + /* No device open */ + if (!hdd) return -1; + + partition_selector_t part_sel = (partition_selector_t) Settings.InstallPartitions; + + /* Add game to device */ + ret = wbfs_add_disc(hdd, __ReadDVD, NULL, ShowProgress, part_sel, 0); + if (ret < 0) return ret; + + return 0; +} + +s32 Wbfs_Wbfs::RemoveGame(u8 *discid) +{ + s32 ret; + + /* No device open */ + if (!hdd) return -1; + + /* Remove game from USB device */ + ret = wbfs_rm_disc(hdd, discid); + if (ret < 0) return ret; + + return 0; +} + +s32 Wbfs_Wbfs::DiskSpace(f32 *used, f32 *free) +{ + f32 ssize; + u32 cnt; + + /* No device open */ + if (!hdd) return -1; + + /* Count used blocks */ + cnt = wbfs_count_usedblocks(hdd); + + /* Sector size in GB */ + ssize = hdd->wbfs_sec_sz / GB_SIZE; + + /* Copy values */ + *free = ssize * cnt; + *used = ssize * (hdd->n_wbfs_sec - cnt); + + return 0; +} + +s32 Wbfs_Wbfs::RenameGame(u8 *discid, const void *newname) +{ + s32 ret; + + /* No USB device open */ + if (!hdd) return -1; + ret = wbfs_ren_disc(hdd, discid, (u8*) newname); + if (ret < 0) return ret; + + return 0; +} + +s32 Wbfs_Wbfs::ReIDGame(u8 *discid, const void *newID) +{ + s32 ret; + + /* No USB device open */ + if (!hdd) return -1; + ret = wbfs_rID_disc(hdd, discid, (u8*) newID); + if (ret < 0) return ret; + + return 0; +} + +u64 Wbfs_Wbfs::EstimateGameSize() +{ + partition_selector_t part_sel = (partition_selector_t) Settings.InstallPartitions; + return wbfs_estimate_disc(hdd, __ReadDVD, NULL, part_sel); +} + +s32 Wbfs_Wbfs::GetFragList(u8 *id) +{ + //! Doesn't have to be called ".iso" just something different than .wbfs but with a dot. + //! So that the code doesn't fail. + return get_frag_list_for_file((char *) ".iso", id, GetFSType(), lba, hdd_sector_size[usbport]); +} diff --git a/source/usbloader/wbfs/wbfs_wbfs.h b/source/usbloader/wbfs/wbfs_wbfs.h new file mode 100644 index 0000000..d0ddfeb --- /dev/null +++ b/source/usbloader/wbfs/wbfs_wbfs.h @@ -0,0 +1,40 @@ +#ifndef _WBFS_WBFS_H +#define _WBFS_WBFS_H + +#include "wbfs_base.h" +#include "libs/libwbfs/libwbfs.h" +#include "usbloader/wbfs.h" +#include "wbfs_rw.h" + +class Wbfs_Wbfs: public Wbfs +{ + public: + Wbfs_Wbfs(u32 device, u32 lba, u32 size, u32 port) : + Wbfs(device, lba, size, port) + { + } + + s32 Open(); + virtual void Close(); + wbfs_disc_t* OpenDisc(u8 *); + void CloseDisc(wbfs_disc_t *); + + s32 Format(); + s32 GetCount(u32 *); + s32 GetHeaders(struct discHdr *, u32, u32); + + s32 AddGame(); + s32 RemoveGame(u8 *); + + s32 DiskSpace(f32 *, f32 *); + + s32 RenameGame(u8 *, const void *); + s32 ReIDGame(u8 *, const void *); + + u64 EstimateGameSize(); + s32 GetFragList(u8 *id); + private: + WBFS_PartInfo PartInfo; +}; + +#endif //_WBFS_WBFS_H diff --git a/source/usbloader/wdvd.c b/source/usbloader/wdvd.c new file mode 100644 index 0000000..574fd1d --- /dev/null +++ b/source/usbloader/wdvd.c @@ -0,0 +1,437 @@ +#include +#include +#include +#include +#include "gecko.h" +#include "wbfs.h" + +/* Constants */ +#define IOCTL_DI_READID 0x70 +#define IOCTL_DI_READ 0x71 +#define IOCTL_DI_WAITCVRCLOSE 0x79 +#define IOCTL_DI_GETCOVER 0x88 +#define IOCTL_DI_RESET 0x8A +#define IOCTL_DI_OPENPART 0x8B +#define IOCTL_DI_CLOSEPART 0x8C +#define IOCTL_DI_UNENCREAD 0x8D +#define IOCTL_DI_SEEK 0xAB +#define IOCTL_DI_STOPLASER 0xD2 +#define IOCTL_DI_OFFSET 0xD9 +#define IOCTL_DI_DISC_BCA 0xDA +#define IOCTL_DI_STOPMOTOR 0xE3 +#define IOCTL_DI_SETWBFSMODE 0xF4 +#define IOCTL_DI_GETWBFSMODE 0xF5 // odip +#define IOCTL_DI_DISABLERESET 0xF6 // odip + +/** Hermes IOS222 **/ +#define DI_SETWBFSMODE 0xfe + +#define IOCTL_DI_SETFRAG 0xF9 +#define IOCTL_DI_GETMODE 0xFA + +/* Variables */ +static u32 inbuf[8] ATTRIBUTE_ALIGN(32); +static u32 outbuf[8] ATTRIBUTE_ALIGN(32); + +static const char di_fs[] ATTRIBUTE_ALIGN(32) = "/dev/di"; +static s32 _di_fd = -1; + + +s32 WDVD_Init(void) +{ + /* Open "/dev/di" */ + if (_di_fd < 0) { + _di_fd = IOS_Open(di_fs, 0); + if (_di_fd < 0) + return _di_fd; + } + + return 0; +} + +s32 WDVD_Close(void) +{ + /* Close "/dev/di" */ + if (_di_fd >= 0) { + IOS_Close(_di_fd); + _di_fd = -1; + } + + return 0; +} + +s32 WDVD_GetHandle(void) +{ + /* Return di handle */ + return _di_fd; +} + +s32 WDVD_Reset(void) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Reset drive */ + inbuf[0] = IOCTL_DI_RESET << 24; + inbuf[1] = 1; + + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_RESET, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +s32 WDVD_ReadDiskId(void *id) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Read disc ID */ + inbuf[0] = IOCTL_DI_READID << 24; + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_READID, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + if (ret < 0) + return ret; + + if (ret == 1) { + memcpy(id, outbuf, sizeof(dvddiskid)); + return 0; + } + + return -ret; +} + +s32 WDVD_Seek(u64 offset) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Drive seek */ + inbuf[0] = IOCTL_DI_SEEK << 24; + inbuf[1] = (u32)(offset >> 2); + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_SEEK, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; + +} + +s32 WDVD_Offset(u64 offset) +{ + if (_di_fd < 0) + return _di_fd; + + //u32 *off = (u32 *)((void *)&offset); + union { u64 off64; u32 off32[2]; } off;off.off64 = offset; + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Set offset */ + inbuf[0] = IOCTL_DI_OFFSET << 24; + inbuf[1] = (off.off32[0]) ? 1: 0; + inbuf[2] = (off.off32[1] >> 2); + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_OFFSET, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +s32 WDVD_StopLaser(void) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Stop laser */ + inbuf[0] = IOCTL_DI_STOPLASER << 24; + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_STOPLASER, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +s32 WDVD_StopMotor(void) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Stop motor */ + inbuf[0] = IOCTL_DI_STOPMOTOR << 24; + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_STOPMOTOR, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +s32 WDVD_OpenPartition(u64 offset) +{ + if (_di_fd < 0) + return _di_fd; + + static u8 Tmd_Buffer[0x4A00] ATTRIBUTE_ALIGN(32); + static ioctlv Vectors[5] ATTRIBUTE_ALIGN(32); + s32 ret; + + memset(inbuf, 0, sizeof inbuf); + memset(outbuf, 0, sizeof outbuf); + + inbuf[0] = IOCTL_DI_OPENPART << 24; + inbuf[1] = offset >> 2; + + Vectors[0].data = inbuf; + Vectors[0].len = 0x20; + Vectors[1].data = 0; + Vectors[1].len = 0; + Vectors[2].data = 0; + Vectors[2].len = 0; + Vectors[3].data = Tmd_Buffer; + Vectors[3].len = 0x49e4; + Vectors[4].data = outbuf; + Vectors[4].len = 0x20; + + ret = IOS_Ioctlv(_di_fd, IOCTL_DI_OPENPART, 3, 2, (ioctlv *)Vectors); + + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +s32 WDVD_ClosePartition(void) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Close partition */ + inbuf[0] = IOCTL_DI_CLOSEPART << 24; + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_CLOSEPART, inbuf, sizeof(inbuf), NULL, 0); + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +s32 WDVD_UnencryptedRead(void *buf, u32 len, u64 offset) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Unencrypted read */ + inbuf[0] = IOCTL_DI_UNENCREAD << 24; + inbuf[1] = len; + inbuf[2] = (u32)(offset >> 2); + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_UNENCREAD, inbuf, sizeof(inbuf), buf, len); + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +s32 WDVD_Read(void *buf, u32 len, u64 offset) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Disc read */ + inbuf[0] = IOCTL_DI_READ << 24; + inbuf[1] = len; + inbuf[2] = (u32)(offset >> 2); + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_READ, inbuf, sizeof(inbuf), buf, len); + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +s32 WDVD_WaitForDisc(void) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Wait for disc */ + inbuf[0] = IOCTL_DI_WAITCVRCLOSE << 24; + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_WAITCVRCLOSE, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +s32 WDVD_GetCoverStatus(u32 *status) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Get cover status */ + inbuf[0] = IOCTL_DI_GETCOVER << 24; + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_GETCOVER, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + if (ret < 0) + return ret; + + if (ret == 1) { + /* Copy cover status */ + memcpy(status, outbuf, sizeof(u32)); + + return 0; + } + + return -ret; +} + +s32 WDVD_SetUSBMode(const u8 *id, s32 partition) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Set USB mode */ + inbuf[0] = IOCTL_DI_SETWBFSMODE << 24; + inbuf[1] = (id) ? WBFS_DEVICE_USB : 0; + + /* Copy ID */ + if (id) { + memcpy(&inbuf[2], id, 6); + if(partition >= 0) { + inbuf[5] = partition; + } + } + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_SETWBFSMODE, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + if (ret!=1) { + // Try old cIOS 222 + /* Set USB mode */ + inbuf[0] = DI_SETWBFSMODE << 24; + ret = IOS_Ioctl(_di_fd, DI_SETWBFSMODE, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + } + + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +s32 WDVD_Read_Disc_BCA(void *buf) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Disc read */ + inbuf[0] = IOCTL_DI_DISC_BCA << 24; + //inbuf[1] = 64; + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_DISC_BCA, inbuf, sizeof(inbuf), buf, 64); + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +// frag + +s32 WDVD_SetFragList(int device, void *fraglist, int size) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + memset(outbuf, 0, sizeof(outbuf)); + + /* Set FRAG mode */ + inbuf[0] = IOCTL_DI_SETFRAG << 24; + inbuf[1] = device; + inbuf[2] = (u32)fraglist; + inbuf[3] = size; + + DCFlushRange(fraglist, size); + ret = IOS_Ioctl(_di_fd, IOCTL_DI_SETFRAG, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} + +s32 WDVD_Eject(void) +{ + if (_di_fd < 0) + return _di_fd; + + s32 ret; + + memset(inbuf, 0, sizeof(inbuf)); + + /* Stop motor */ + inbuf[0] = IOCTL_DI_STOPMOTOR << 24; + /* Eject DVD */ + inbuf[1] = 1; + + ret = IOS_Ioctl(_di_fd, IOCTL_DI_STOPMOTOR, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf)); + if (ret < 0) + return ret; + + return (ret == 1) ? 0 : -ret; +} diff --git a/source/usbloader/wdvd.h b/source/usbloader/wdvd.h new file mode 100644 index 0000000..295a997 --- /dev/null +++ b/source/usbloader/wdvd.h @@ -0,0 +1,34 @@ +#ifndef _WDVD_H_ +#define _WDVD_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Prototypes */ +s32 WDVD_Init(void); +s32 WDVD_Close(void); +s32 WDVD_GetHandle(void); +s32 WDVD_Reset(void); +s32 WDVD_ReadDiskId(void *); +s32 WDVD_Seek(u64); +s32 WDVD_Offset(u64); +s32 WDVD_StopLaser(void); +s32 WDVD_StopMotor(void); +s32 WDVD_OpenPartition(u64 offset); +s32 WDVD_ClosePartition(void); +s32 WDVD_UnencryptedRead(void *, u32, u64); +s32 WDVD_Read(void *, u32, u64); +s32 WDVD_WaitForDisc(void); +s32 WDVD_GetCoverStatus(u32 *); +s32 WDVD_SetUSBMode(const u8 *, s32); +s32 WDVD_Eject(void); +s32 WDVD_Read_Disc_BCA(void *); +s32 WDVD_SetFragList(int device, void *fraglist, int size); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/source/utils/Callback.hpp b/source/utils/Callback.hpp new file mode 100644 index 0000000..f4a490c --- /dev/null +++ b/source/utils/Callback.hpp @@ -0,0 +1,62 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * WiiXplorer 2010 + ***************************************************************************/ +#ifndef _CPP_CALLBACK_HPP +#define _CPP_CALLBACK_HPP + +class cCallback +{ + public: + virtual void Execute(void * arg) const =0; +}; + +template +class TCallback : public cCallback +{ + public: + TCallback() : cInst(0), pFunction(0) // constructor + { + } + + typedef void (cInstance::*tFunction)(void * arg); + + virtual void Execute(void * arg) const + { + if (pFunction) + (cInst->*pFunction)(arg); + } + + void SetCallback (cInstance * cInstancePointer, tFunction pFunctionPointer) + { + cInst = cInstancePointer; + pFunction = pFunctionPointer; + } + + private: + cInstance *cInst; + tFunction pFunction; +}; + +#endif diff --git a/source/utils/LanguageCode.c b/source/utils/LanguageCode.c new file mode 100644 index 0000000..415f60f --- /dev/null +++ b/source/utils/LanguageCode.c @@ -0,0 +1,26 @@ +#include + +const char* CONF_GetLanguageString(void) +{ + static int confLang = 0xdead; + + if(confLang == 0xdead) + confLang = CONF_GetLanguage(); + + const char*lang; + switch( confLang ) + { + case CONF_LANG_JAPANESE: lang = "JPN"; break; + default: + case CONF_LANG_ENGLISH: lang = "ENG"; break; + case CONF_LANG_GERMAN: lang = "GER"; break; + case CONF_LANG_FRENCH: lang = "FRA"; break; + case CONF_LANG_SPANISH: lang = "SPA"; break; + case CONF_LANG_ITALIAN: lang = "ITA"; break; + case CONF_LANG_DUTCH: lang = "NED"; break; + case CONF_LANG_SIMP_CHINESE: + case CONF_LANG_TRAD_CHINESE: lang = "CHN"; break; + case CONF_LANG_KOREAN: lang = "KOR"; break; + } + return lang; +} diff --git a/source/utils/LanguageCode.h b/source/utils/LanguageCode.h new file mode 100644 index 0000000..c80008b --- /dev/null +++ b/source/utils/LanguageCode.h @@ -0,0 +1,14 @@ +#ifndef __LANGUAGE_CODE_H_ +#define __LANGUAGE_CODE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +const char* CONF_GetLanguageString(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/utils/MD5.c b/source/utils/MD5.c new file mode 100644 index 0000000..cbc3e68 --- /dev/null +++ b/source/utils/MD5.c @@ -0,0 +1,608 @@ +/* ========================================================================== ** + * + * MD5.c + * + * Copyright: + * Copyright (C) 2003-2005 by Christopher R. Hertel + * + * Email: crh@ubiqx.mn.org + * + * $Id: MD5.c,v 0.6 2005/06/08 18:35:59 crh Exp $ + * + * + * Modifications and additions by dimok + * + * -------------------------------------------------------------------------- ** + * + * Description: + * Implements the MD5 hash algorithm, as described in RFC 1321. + * + * -------------------------------------------------------------------------- ** + * + * License: + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- ** + * + * Notes: + * + * None of this will make any sense unless you're studying RFC 1321 as you + * read the code. + * + * MD5 is described in RFC 1321. + * The MD*4* algorithm is described in RFC 1320 (that's 1321 - 1). + * MD5 is very similar to MD4, but not quite similar enough to justify + * putting the two into a single module. Besides, I wanted to add a few + * extra functions to this one to expand its usability. + * + * There are three primary motivations for this particular implementation. + * 1) Programmer's pride. I wanted to be able to say I'd done it, and I + * wanted to learn from the experience. + * 2) Portability. I wanted an implementation that I knew to be portable + * to a reasonable number of platforms. In particular, the algorithm is + * designed with little-endian platforms in mind, but I wanted an + * endian-agnostic implementation. + * 3) Compactness. While not an overriding goal, I thought it worth-while + * to see if I could reduce the overall size of the result. This is in + * keeping with my hopes that this library will be suitable for use in + * some embedded environments. + * Beyond that, cleanliness and clarity are always worth pursuing. + * + * As mentioned above, the code really only makes sense if you are familiar + * with the MD5 algorithm or are using RFC 1321 as a guide. This code is + * quirky, however, so you'll want to be reading carefully. + * + * Yeah...most of the comments are cut-and-paste from my MD4 implementation. + * + * -------------------------------------------------------------------------- ** + * + * References: + * IETF RFC 1321: The MD5 Message-Digest Algorithm + * Ron Rivest. IETF, April, 1992 + * + * ========================================================================== ** + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "MD5.h" + +/* -------------------------------------------------------------------------- ** + * Static Constants: + * + * K[][] - In round one, the values of k (which are used to index + * particular four-byte sequences in the input) are simply + * sequential. In later rounds, however, they are a bit more + * varied. Rather than calculate the values of k (which may + * or may not be possible--I haven't though about it) the + * values are stored in this array. + * + * S[][] - In each round there is a left rotate operation performed as + * part of the 16 permutations. The number of bits varies in + * a repeating patter. This array keeps track of the patterns + * used in each round. + * + * T[][] - There are four rounds of 16 permutations for a total of 64. + * In each of these 64 permutation operations, a different + * constant value is added to the mix. The constants are + * based on the sine function...read RFC 1321 for more detail. + * In any case, the correct constants are stored in the T[][] + * array. They're divided up into four groups of 16. + */ + +static const uint8_t K[3][16] = { +/* Round 1: skipped (since it is simply sequential). */ +{ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 }, /* R2 */ +{ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 }, /* R3 */ +{ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 } /* R4 */ +}; + +static const uint8_t S[4][4] = { { 7, 12, 17, 22 }, /* Round 1 */ +{ 5, 9, 14, 20 }, /* Round 2 */ +{ 4, 11, 16, 23 }, /* Round 3 */ +{ 6, 10, 15, 21 } /* Round 4 */ +}; + +static const uint32_t T[4][16] = { { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* Round 1 */ +0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, + 0xa679438e, 0x49b40821 }, + +{ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */ +0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, + 0x676f02d9, 0x8d2a4c8a }, + +{ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* Round 3 */ +0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, + 0x1fa27cf8, 0xc4ac5665 }, + +{ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* Round 4 */ +0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, + 0x2ad7d2bb, 0xeb86d391 }, }; + +/* -------------------------------------------------------------------------- ** + * Macros: + * md5F(), md5G(), md5H(), and md5I() are described in RFC 1321. + * All of these operations are bitwise, and so not impacted by endian-ness. + * + * GetLongByte() + * Extract one byte from a (32-bit) longword. A value of 0 for + * indicates the lowest order byte, while 3 indicates the highest order + * byte. + * + */ + +#define md5F( X, Y, Z ) ( ((X) & (Y)) | ((~(X)) & (Z)) ) +#define md5G( X, Y, Z ) ( ((X) & (Z)) | ((Y) & (~(Z))) ) +#define md5H( X, Y, Z ) ( (X) ^ (Y) ^ (Z) ) +#define md5I( X, Y, Z ) ( (Y) ^ ((X) | (~(Z))) ) + +#define GetLongByte( L, idx ) ((unsigned char)(( L >> (((idx) & 0x03) << 3) ) & 0xFF)) + +#define STR2HEX(x) ((x >= 0x30) && (x <= 0x39)) ? x - 0x30 : toupper((int)x)-0x37 + +/* -------------------------------------------------------------------------- ** + * Static Functions: + */ + +static void Permute(uint32_t ABCD[4], const unsigned char block[64]) +/* ------------------------------------------------------------------------ ** + * Permute the ABCD "registers" using the 64-byte as a driver. + * + * Input: ABCD - Pointer to an array of four unsigned longwords. + * block - An array of bytes, 64 bytes in size. + * + * Output: none. + * + * Notes: The MD5 algorithm operates on a set of four longwords stored + * (conceptually) in four "registers". It is easy to imagine a + * simple MD4/5 chip that would operate this way. In any case, + * the mangling of the contents of those registers is driven by + * the input message. The message is chopped and finally padded + * into 64-byte chunks and each chunk is used to manipulate the + * contents of the registers. + * + * The MD5 Algorithm calls for padding the input to ensure that + * it is a multiple of 64 bytes in length. The last 16 bytes + * of the padding space are used to store the message length + * (the length of the original message, before padding, expressed + * in terms of bits). If there is not enough room for 16 bytes + * worth of bitcount (eg., if the original message was 122 bytes + * long) then the block is padded to the end with zeros and + * passed to this function. Then *another* block is filled with + * zeros except for the last 16 bytes which contain the length. + * + * Oh... and the algorithm requires that there be at least one + * padding byte. The first padding byte has a value of 0x80, + * and any others are 0x00. + * + * ------------------------------------------------------------------------ ** + */ +{ + int round; + int i, j; + uint8_t s; + uint32_t a, b, c, d; + uint32_t KeepABCD[4]; + uint32_t X[16]; + + /* Store the current ABCD values for later re-use. + */ + for (i = 0; i < 4; i++) + KeepABCD[i] = ABCD[i]; + + /* Convert the input block into an array of unsigned longs, taking care + * to read the block in Little Endian order (the algorithm assumes this). + * The uint32_t values are then handled in host order. + */ + for (i = 0, j = 0; i < 16; i++) + { + X[i] = (uint32_t) block[j++]; + X[i] |= ((uint32_t) block[j++] << 8); + X[i] |= ((uint32_t) block[j++] << 16); + X[i] |= ((uint32_t) block[j++] << 24); + } + + /* This loop performs the four rounds of permutations. + * The rounds are each very similar. The differences are in three areas: + * - The function (F, G, H, or I) used to perform bitwise permutations + * on the registers, + * - The order in which values from X[] are chosen. + * - Changes to the number of bits by which the registers are rotated. + * This implementation uses a switch statement to deal with some of the + * differences between rounds. Other differences are handled by storing + * values in arrays and using the round number to select the correct set + * of values. + * + * (My implementation appears to be a poor compromise between speed, size, + * and clarity. Ugh. [crh]) + */ + for (round = 0; round < 4; round++) + { + for (i = 0; i < 16; i++) + { + j = (4 - (i % 4)) & 0x3; /* handles the rotation of ABCD. */ + s = S[round][i % 4]; /* is the bit shift for this iteration. */ + + b = ABCD[(j + 1) & 0x3]; /* Copy the b,c,d values per ABCD rotation. */ + c = ABCD[(j + 2) & 0x3]; /* This isn't really necessary, it just looks */ + d = ABCD[(j + 3) & 0x3]; /* clean & will hopefully be optimized away. */ + + /* The actual perumation function. + * This is broken out to minimize the code within the switch(). + */ + switch (round) + { + case 0: + /* round 1 */ + a = md5F( b, c, d ) + X[i]; + break; + case 1: + /* round 2 */ + a = md5G( b, c, d ) + X[K[0][i]]; + break; + case 2: + /* round 3 */ + a = md5H( b, c, d ) + X[K[1][i]]; + break; + default: + /* round 4 */ + a = md5I( b, c, d ) + X[K[2][i]]; + break; + } + a = 0xFFFFFFFF & (ABCD[j] + a + T[round][i]); + ABCD[j] = b + (0xFFFFFFFF & ((a << s) | (a >> (32 - s)))); + } + } + + /* Use the stored original A, B, C, D values to perform + * one last convolution. + */ + for (i = 0; i < 4; i++) + ABCD[i] = 0xFFFFFFFF & (ABCD[i] + KeepABCD[i]); + +} /* Permute */ + +/* -------------------------------------------------------------------------- ** + * Functions: + */ + +auth_md5Ctx *auth_md5InitCtx(auth_md5Ctx *ctx) +/* ------------------------------------------------------------------------ ** + * Initialize an MD5 context. + * + * Input: ctx - A pointer to the MD5 context structure to be initialized. + * Contexts are typically created thusly: + * ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) ); + * + * Output: A pointer to the initialized context (same as ). + * + * Notes: The purpose of the context is to make it possible to generate + * an MD5 Message Digest in stages, rather than having to pass a + * single large block to a single MD5 function. The context + * structure keeps track of various bits of state information. + * + * Once the context is initialized, the blocks of message data + * are passed to the function. Once the + * final bit of data has been handed to the + * context can be closed out by calling , + * which also calculates the final MD5 result. + * + * Don't forget to free an allocated context structure when + * you've finished using it. + * + * See Also: , + * + * ------------------------------------------------------------------------ ** + */ +{ + ctx->len = 0; + ctx->b_used = 0; + + ctx->ABCD[0] = 0x67452301; /* The array ABCD[] contains the four 4-byte */ + ctx->ABCD[1] = 0xefcdab89; /* "registers" that are manipulated to */ + ctx->ABCD[2] = 0x98badcfe; /* produce the MD5 digest. The input acts */ + ctx->ABCD[3] = 0x10325476; /* upon the registers, not the other way */ + /* 'round. The initial values are those */ + /* given in RFC 1321 (pg. 4). Note, however, that RFC 1321 */ + /* provides these values as bytes, not as longwords, and the */ + /* bytes are arranged in little-endian order as if they were */ + /* the bytes of (little endian) 32-bit ints. That's */ + /* confusing as all getout (to me, anyway). The values given */ + /* here are provided as 32-bit values in C language format, */ + /* so they are endian-agnostic. */ + return (ctx); +} /* auth_md5InitCtx */ + +auth_md5Ctx *auth_md5SumCtx(auth_md5Ctx *ctx, const unsigned char *src, const int len) +/* ------------------------------------------------------------------------ ** + * Build an MD5 Message Digest within the given context. + * + * Input: ctx - Pointer to the context in which the MD5 sum is being + * built. + * src - A chunk of source data. This will be used to drive + * the MD5 algorithm. + * len - The number of bytes in . + * + * Output: A pointer to the updated context (same as ). + * + * See Also: , , + * + * ------------------------------------------------------------------------ ** + */ +{ + int i; + + /* Add the new block's length to the total length. + */ + ctx->len += (uint32_t) len; + + /* Copy the new block's data into the context block. + * Call the Permute() function whenever the context block is full. + */ + for (i = 0; i < len; i++) + { + ctx->block[ctx->b_used] = src[i]; + (ctx->b_used)++; + if (64 == ctx->b_used) + { + Permute((uint32_t *)ctx->ABCD, ctx->block); + ctx->b_used = 0; + } + } + + /* Return the updated context. + */ + return (ctx); +} /* auth_md5SumCtx */ + +auth_md5Ctx *auth_md5CloseCtx(auth_md5Ctx *ctx, unsigned char *dst) +/* ------------------------------------------------------------------------ ** + * Close an MD5 Message Digest context and generate the final MD5 sum. + * + * Input: ctx - Pointer to the context in which the MD5 sum is being + * built. + * dst - A pointer to at least 16 bytes of memory, which will + * receive the finished MD5 sum. + * + * Output: A pointer to the closed context (same as ). + * You might use this to free a malloc'd context structure. :) + * + * Notes: The context () is returned in an undefined state. + * It must be re-initialized before re-use. + * + * See Also: , + * + * ------------------------------------------------------------------------ ** + */ +{ + int i; + uint32_t l; + + /* Add the required 0x80 padding initiator byte. + * The auth_md5SumCtx() function always permutes and resets the context + * block when it gets full, so we know that there must be at least one + * free byte in the context block. + */ + ctx->block[ctx->b_used] = 0x80; + (ctx->b_used)++; + + /* Zero out any remaining free bytes in the context block. + */ + for (i = ctx->b_used; i < 64; i++) + ctx->block[i] = 0; + + /* We need 8 bytes to store the length field. + * If we don't have 8, call Permute() and reset the context block. + */ + if (56 < ctx->b_used) + { + Permute((uint32_t *)ctx->ABCD, ctx->block); + for (i = 0; i < 64; i++) + ctx->block[i] = 0; + } + + /* Add the total length and perform the final perumation. + * Note: The 60'th byte is read from the *original* len> value + * and shifted to the correct position. This neatly avoids + * any MAXINT numeric overflow issues. + */ + l = ctx->len << 3; + for (i = 0; i < 4; i++) + ctx->block[56 + i] |= GetLongByte( l, i ); + ctx->block[60] = ((GetLongByte( ctx->len, 3 ) & 0xE0) >> 5); /* See Above! */ + Permute((uint32_t *)ctx->ABCD, ctx->block); + + /* Now copy the result into the output buffer and we're done. + */ + for (i = 0; i < 4; i++) + { + dst[0 + i] = GetLongByte( ctx->ABCD[0], i ); + dst[4 + i] = GetLongByte( ctx->ABCD[1], i ); + dst[8 + i] = GetLongByte( ctx->ABCD[2], i ); + dst[12 + i] = GetLongByte( ctx->ABCD[3], i ); + } + + /* Return the context. + * This is done for compatibility with the other auth_md5*Ctx() functions. + */ + return (ctx); +} /* auth_md5CloseCtx */ + +unsigned char * MD5(unsigned char *dst, const unsigned char *src, const int len) +/* ------------------------------------------------------------------------ ** + * Compute an MD5 message digest. + * + * Input: dst - Destination buffer into which the result will be written. + * Must be 16 bytes, minimum. + * src - Source data block to be MD5'd. + * len - The length, in bytes, of the source block. + * (Note that the length is given in bytes, not bits.) + * + * Output: A pointer to , which will contain the calculated 16-byte + * MD5 message digest. + * + * Notes: This function is a shortcut. It takes a single input block. + * For more drawn-out operations, see . + * + * This function is interface-compatible with the + * function in the MD4 module. + * + * The MD5 algorithm is designed to work on data with an + * arbitrary *bit* length. Most implementations, this one + * included, handle the input data in byte-sized chunks. + * + * The MD5 algorithm does much of its work using four-byte + * words, and so can be tuned for speed based on the endian-ness + * of the host. This implementation is intended to be + * endian-neutral, which may make it a teeny bit slower than + * others. ...maybe. + * + * See Also: + * + * ------------------------------------------------------------------------ ** + */ +{ + auth_md5Ctx ctx[1]; + + (void) auth_md5InitCtx(ctx); /* Open a context. */ + (void) auth_md5SumCtx(ctx, src, len); /* Pass only one block. */ + (void) auth_md5CloseCtx(ctx, dst); /* Close the context. */ + + return (dst); /* Makes life easy. */ +} /* auth_md5Sum */ + +unsigned char * MD5fromFile(unsigned char *dst, const char *src) +/* ------------------------------------------------------------------------ ** + * Compute an MD5 message digest. + * + * Input: dst - Destination buffer into which the result will be written. + * Must be 16 bytes, minimum. + * src - filepath of the file to be checked + * + * Output: A pointer to , which will contain the calculated 16-byte + * MD5 message digest. + * + * Notes: This function is a shortcut. It takes a single input block. + * For more drawn-out operations, see . + * + * This function is interface-compatible with the + * function in the MD4 module. + * + * The MD5 algorithm is designed to work on data with an + * arbitrary *bit* length. Most implementations, this one + * included, handle the input data in byte-sized chunks. + * + * The MD5 algorithm does much of its work using four-byte + * words, and so can be tuned for speed based on the endian-ness + * of the host. This implementation is intended to be + * endian-neutral, which may make it a teeny bit slower than + * others. ...maybe. + * + * See Also: + * + * ------------------------------------------------------------------------ ** + */ +{ + auth_md5Ctx ctx[1]; + + FILE * file; + unsigned int blksize = 0; + unsigned int read = 0; + + file = fopen(src, "rb"); + + if (file == NULL) + { + return NULL; + } + + (void) auth_md5InitCtx(ctx); /* Open a context. */ + + fseek(file, 0, SEEK_END); + unsigned long long filesize = ftell(file); + rewind(file); + + if (filesize < 1048576) //1MB cache for files bigger than 1 MB + blksize = filesize; + else blksize = 1048576; + + unsigned char * buffer = malloc(blksize); + + if (buffer == NULL) + { + //no memory + fclose(file); + return NULL; + } + + do + { + read = fread(buffer, 1, blksize, file); + (void) auth_md5SumCtx(ctx, buffer, read); /* Pass only one block. */ + + } while (read > 0); + + fclose(file); + free(buffer); + + (void) auth_md5CloseCtx(ctx, dst); /* Close the context. */ + + return (dst); /* Makes life easy. */ +} /* auth_md5Sum */ + +const char * MD5ToString(const unsigned char * hash, char * dst) +{ + char hexchar[3]; + short i = 0, n = 0; + + for (i = 0; i < 16; i++) + { + sprintf(hexchar, "%02X", hash[i]); + + dst[n++] = hexchar[0]; + dst[n++] = hexchar[1]; + } + + dst[n] = 0x00; + + return dst; +} + +unsigned char * StringToMD5(const char * hash, unsigned char * dst) +{ + char hexchar[2]; + short i = 0, n = 0; + + for (i = 0; i < 16; i++) + { + hexchar[0] = hash[n++]; + hexchar[1] = hash[n++]; + + dst[i] = STR2HEX( hexchar[0] ); + dst[i] <<= 4; + dst[i] += STR2HEX( hexchar[1] ); + } + + return dst; +} + +/* ========================================================================== */ diff --git a/source/utils/MD5.h b/source/utils/MD5.h new file mode 100644 index 0000000..a7cb9fd --- /dev/null +++ b/source/utils/MD5.h @@ -0,0 +1,241 @@ +#ifndef MD5_H +#define MD5_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* ========================================================================== ** + * + * MD5.h + * + * Copyright: + * Copyright (C) 2003-2005 by Christopher R. Hertel + * + * Email: crh@ubiqx.mn.org + * + * $Id: MD5.h,v 0.6 2005/06/08 18:35:59 crh Exp $ + * + * Modifications and additions by dimok + * + * -------------------------------------------------------------------------- ** + * + * Description: + * Implements the MD5 hash algorithm, as described in RFC 1321. + * + * -------------------------------------------------------------------------- ** + * + * License: + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- ** + * + * Notes: + * + * None of this will make any sense unless you're studying RFC 1321 as you + * read the code. + * + * MD5 is described in RFC 1321. + * The MD*4* algorithm is described in RFC 1320 (that's 1321 - 1). + * MD5 is very similar to MD4, but not quite similar enough to justify + * putting the two into a single module. Besides, I wanted to add a few + * extra functions to this one to expand its usability. + * + * There are three primary motivations for this particular implementation. + * 1) Programmer's pride. I wanted to be able to say I'd done it, and I + * wanted to learn from the experience. + * 2) Portability. I wanted an implementation that I knew to be portable + * to a reasonable number of platforms. In particular, the algorithm is + * designed with little-endian platforms in mind, but I wanted an + * endian-agnostic implementation. + * 3) Compactness. While not an overriding goal, I thought it worth-while + * to see if I could reduce the overall size of the result. This is in + * keeping with my hopes that this library will be suitable for use in + * some embedded environments. + * Beyond that, cleanliness and clarity are always worth pursuing. + * + * As mentioned above, the code really only makes sense if you are familiar + * with the MD5 algorithm or are using RFC 1321 as a guide. This code is + * quirky, however, so you'll want to be reading carefully. + * + * Yeah...most of the comments are cut-and-paste from my MD4 implementation. + * + * -------------------------------------------------------------------------- ** + * + * References: + * IETF RFC 1321: The MD5 Message-Digest Algorithm + * Ron Rivest. IETF, April, 1992 + * + * ========================================================================== ** + */ + /* -------------------------------------------------------------------------- ** + * Typedefs: + */ + + typedef struct + { + unsigned int len; + unsigned int ABCD[4]; + int b_used; + unsigned char block[64]; + } auth_md5Ctx; + + /* -------------------------------------------------------------------------- ** + * Functions: + */ + + auth_md5Ctx *auth_md5InitCtx(auth_md5Ctx *ctx); + /* ------------------------------------------------------------------------ ** + * Initialize an MD5 context. + * + * Input: ctx - A pointer to the MD5 context structure to be initialized. + * Contexts are typically created thusly: + * ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) ); + * + * Output: A pointer to the initialized context (same as ). + * + * Notes: The purpose of the context is to make it possible to generate + * an MD5 Message Digest in stages, rather than having to pass a + * single large block to a single MD5 function. The context + * structure keeps track of various bits of state information. + * + * Once the context is initialized, the blocks of message data + * are passed to the function. Once the + * final bit of data has been handed to the + * context can be closed out by calling , + * which also calculates the final MD5 result. + * + * Don't forget to free an allocated context structure when + * you've finished using it. + * + * See Also: , + * + * ------------------------------------------------------------------------ ** + */ + + auth_md5Ctx *auth_md5SumCtx(auth_md5Ctx *ctx, const unsigned char *src, const int len); + /* ------------------------------------------------------------------------ ** + * Build an MD5 Message Digest within the given context. + * + * Input: ctx - Pointer to the context in which the MD5 sum is being + * built. + * src - A chunk of source data. This will be used to drive + * the MD5 algorithm. + * len - The number of bytes in . + * + * Output: A pointer to the updated context (same as ). + * + * See Also: , , + * + * ------------------------------------------------------------------------ ** + */ + + auth_md5Ctx *auth_md5CloseCtx(auth_md5Ctx *ctx, unsigned char *dst); + /* ------------------------------------------------------------------------ ** + * Close an MD5 Message Digest context and generate the final MD5 sum. + * + * Input: ctx - Pointer to the context in which the MD5 sum is being + * built. + * dst - A pointer to at least 16 bytes of memory, which will + * receive the finished MD5 sum. + * + * Output: A pointer to the closed context (same as ). + * You might use this to free a malloc'd context structure. :) + * + * Notes: The context () is returned in an undefined state. + * It must be re-initialized before re-use. + * + * See Also: , + * + * ------------------------------------------------------------------------ ** + */ + + unsigned char * MD5(unsigned char * hash, const unsigned char *src, const int len); + /* ------------------------------------------------------------------------ ** + * Compute an MD5 message digest. + * + * Input: dst - Destination buffer into which the result will be written. + * Must be 16 bytes, minimum. + * src - Source data block to be MD5'd. + * len - The length, in bytes, of the source block. + * (Note that the length is given in bytes, not bits.) + * + * Output: A pointer to , which will contain the calculated 16-byte + * MD5 message digest. + * + * Notes: This function is a shortcut. It takes a single input block. + * For more drawn-out operations, see . + * + * This function is interface-compatible with the + * function in the MD4 module. + * + * The MD5 algorithm is designed to work on data with an + * arbitrary *bit* length. Most implementations, this one + * included, handle the input data in byte-sized chunks. + * + * The MD5 algorithm does much of its work using four-byte + * words, and so can be tuned for speed based on the endian-ness + * of the host. This implementation is intended to be + * endian-neutral, which may make it a teeny bit slower than + * others. ...maybe. + * + * See Also: + * + * ------------------------------------------------------------------------ ** + */ + + unsigned char * MD5fromFile(unsigned char *dst, const char *src); + /* ------------------------------------------------------------------------ ** + * Compute an MD5 message digest. + * + * Input: dst - Destination buffer into which the result will be written. + * Must be 16 bytes, minimum. + * src - filepath to the file to be MD5'd. + * + * Output: A pointer to , which will contain the calculated 16-byte + * MD5 message digest. + * + * Notes: This function is a shortcut. It takes a single input block. + * For more drawn-out operations, see . + * + * This function is interface-compatible with the + * function in the MD4 module. + * + * The MD5 algorithm is designed to work on data with an + * arbitrary *bit* length. Most implementations, this one + * included, handle the input data in byte-sized chunks. + * + * The MD5 algorithm does much of its work using four-byte + * words, and so can be tuned for speed based on the endian-ness + * of the host. This implementation is intended to be + * endian-neutral, which may make it a teeny bit slower than + * others. ...maybe. + * + * See Also: + * + * ------------------------------------------------------------------------ ** + */ + + const char * MD5ToString(const unsigned char *hash, char *dst); + unsigned char * StringToMD5(const char * hash, unsigned char * dst); + +/* ========================================================================== */ + +#ifdef __cplusplus +} +#endif +#endif /* AUTH_MD5_H */ diff --git a/source/utils/PasswordCheck.cpp b/source/utils/PasswordCheck.cpp new file mode 100644 index 0000000..feed076 --- /dev/null +++ b/source/utils/PasswordCheck.cpp @@ -0,0 +1,21 @@ +#include "prompts/PromptWindows.h" + +int PasswordCheck(const char * password) +{ + if(!password || strcmp(password, "") == 0 || strcmp(password, "not set") == 0) + return 2; + + char entered[100]; + memset(entered, 0, sizeof(entered)); + + int result = OnScreenKeyboard(entered, 20, 0, true); + if (result == 1) + { + if (strcmp(entered, password) == 0) //if password correct + return 1; + else + return -1; + } + + return 0; +} diff --git a/source/utils/PasswordCheck.h b/source/utils/PasswordCheck.h new file mode 100644 index 0000000..9df6cc2 --- /dev/null +++ b/source/utils/PasswordCheck.h @@ -0,0 +1,6 @@ +#ifndef PASSWORD_CHECK_H_ +#define PASSWORD_CHECK_H_ + +int PasswordCheck(const char * password); + +#endif diff --git a/source/utils/ResourceManager.cpp b/source/utils/ResourceManager.cpp new file mode 100644 index 0000000..aeb6f20 --- /dev/null +++ b/source/utils/ResourceManager.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "ResourceManager.h" + +ResourceManager * ResourceManager::instance = NULL; + +ResourceManager * ResourceManager::Instance() +{ + if (instance == NULL) + { + instance = new ResourceManager(); + } + return instance; +} + +void ResourceManager::DestroyInstance() +{ + if (instance != NULL) + { + delete instance; + instance = NULL; + } +} + +ResourceManager::~ResourceManager() +{ + // Delete all images... + std::map::iterator imgitr; + for (imgitr = images.begin(); imgitr != images.end(); imgitr++) + { + if(imgitr->second.data) + free(imgitr->second.data); + } + images.clear(); + imageCount.clear(); +} + +void ResourceManager::AddImageData(const u8 *img, ImageData & Data) +{ + ResourceManager::Instance()->InternalAddImageData(img, Data); +} + +ImageData * ResourceManager::GetImageData(const u8 *img) +{ + return ResourceManager::Instance()->InternalGetImageData(img); +} + +void ResourceManager::Remove(u8 * img) +{ + ResourceManager::Instance()->InternalRemoveImageData(img); +} + +void ResourceManager::InternalAddImageData(const u8 * img, ImageData & Data) +{ + std::map::iterator itr = images.find(img); + if (itr != images.end()) + return; + + images[img] = Data; + imageCount[Data.data] = 1; +} + +ImageData * ResourceManager::InternalGetImageData(const u8 *img) +{ + std::map::iterator itr = images.find(img); + if (itr == images.end()) + return NULL; + + imageCount[itr->second.data]++; + + return &itr->second; +} + +void ResourceManager::InternalRemoveImageData(u8 * img) +{ + std::map::iterator itr = imageCount.find(img); + if (itr != imageCount.end()) + { + itr->second--; + + if (itr->second == 0) // Remove the resource + { + imageCount.erase(itr); + + std::map::iterator iitr; + for (iitr = images.begin(); iitr != images.end(); iitr++) + { + if (iitr->second.data == img) + { + if(iitr->second.data) + free(iitr->second.data); + images.erase(iitr); + break; + } + } + } + } + else if(img) + { + //! This case should actually never accur + free(img); + } +} diff --git a/source/utils/ResourceManager.h b/source/utils/ResourceManager.h new file mode 100644 index 0000000..d98f0ff --- /dev/null +++ b/source/utils/ResourceManager.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _RESOURCE_MANAGER_H +#define _RESOURCE_MANAGER_H + +#include + +#include "GUI/gui.h" + +#include + +typedef struct _ImageData +{ + u8 * data; + int width; + int height; + u8 format; +} ImageData; + +class ResourceManager +{ + public: + static ResourceManager *Instance(); + static void DestroyInstance(); + + static void AddImageData(const u8 *img, ImageData & data); + static ImageData * GetImageData(const u8 *img); + static void Remove(u8 * img); + private: + void InternalAddImageData(const u8 * img, ImageData & Data); + ImageData *InternalGetImageData(const u8 *img); + void InternalRemoveImageData(u8 * img); + + ~ResourceManager(); + + static ResourceManager *instance; + + std::map images; + std::map imageCount; +}; + +#endif //_ResourceManager_H diff --git a/source/utils/ShowError.cpp b/source/utils/ShowError.cpp new file mode 100644 index 0000000..be19b25 --- /dev/null +++ b/source/utils/ShowError.cpp @@ -0,0 +1,21 @@ +#include +#include +#include + +#include "language/gettext.h" +#include "prompts/PromptWindows.h" + +extern "C" void ShowError(const char * format, ...) +{ + char *tmp=0; + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va)>=0) && tmp) + { + WindowPrompt(tr("Error:"), tmp, tr("OK")); + } + va_end(va); + + if(tmp) + free(tmp); +} diff --git a/source/utils/ShowError.h b/source/utils/ShowError.h new file mode 100644 index 0000000..20f64ae --- /dev/null +++ b/source/utils/ShowError.h @@ -0,0 +1,14 @@ +#ifndef SHOWERROR_H_ +#define SHOWERROR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void ShowError(const char * format, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/utils/StringTools.c b/source/utils/StringTools.c new file mode 100644 index 0000000..6cc4b72 --- /dev/null +++ b/source/utils/StringTools.c @@ -0,0 +1,182 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include + +const char * fmt(const char * format, ...) +{ + static char strChar[512]; + strChar[0] = 0; + char * tmp = NULL; + + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + snprintf(strChar, sizeof(strChar), tmp); + free(tmp); + va_end(va); + return (const char *) strChar; + } + va_end(va); + + if(tmp) + free(tmp); + + return NULL; +} + +const wchar_t * wfmt(const char * format, ...) +{ + static wchar_t strWChar[512]; + strWChar[0] = 0; + + if(!format) + return (const wchar_t *) strWChar; + + if(strcmp(format, "") == 0) + return (const wchar_t *) strWChar; + + char * tmp = NULL; + + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + int bt; + int strlength = strlen(tmp); + bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512 ); + free(tmp); + tmp = 0; + + if(bt > 0) + { + strWChar[bt] = 0; + return (const wchar_t *) strWChar; + } + } + va_end(va); + + if(tmp) + free(tmp); + + return (const wchar_t *) strWChar; +} + +bool char2wchar_t(const char * strChar, wchar_t * dest) +{ + if(!strChar || !dest) + return false; + + int bt; + bt = mbstowcs(dest, strChar, strlen(strChar)); + if (bt > 0) { + dest[bt] = 0; + return true; + } + + return false; +} + +int strtokcmp(const char * string, const char * compare, const char * separator) +{ + if(!string || !compare) + return -1; + + char TokCopy[512]; + strcpy(TokCopy, compare); + + char * strTok = strtok(TokCopy, separator); + + while (strTok != NULL) + { + if (strcasecmp(string, strTok) == 0) + { + return 0; + } + strTok = strtok(NULL,separator); + } + + return -1; +} + +const char * FullpathToFilename(const char *path) +{ + if(!path) return path; + + const char * ptr = path; + const char * Filename = ptr; + + while(*ptr != '\0') + { + if(*ptr == '/' && ptr[1] != '\0') + Filename = ptr+1; + + ++ptr; + } + + return Filename; +} + +int replaceString(char *string, const char *replace, const char *replacement) +{ + if(!string || !replace || !replacement) + return -1; + + char *strCpy = strdup(string); + if(!strCpy) + return -1; + + char *ptr; + int replacelen = strlen(replace); + + for(ptr = strCpy; *ptr != 0; string++, ptr++) + { + if(strncasecmp(ptr, replace, replacelen) == 0) + { + const char *ptr2 = replacement; + while(*ptr2 != 0) + { + *string = *ptr2; + string++; + ptr2++; + } + ptr += replacelen; + } + + *string = *ptr; + } + + *string = 0; + + free(strCpy); + + return 0; +} diff --git a/source/utils/StringTools.h b/source/utils/StringTools.h new file mode 100644 index 0000000..31af1c6 --- /dev/null +++ b/source/utils/StringTools.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef __STRING_TOOLS_H +#define __STRING_TOOLS_H + +#ifdef __cplusplus +extern "C" { +#endif + +//! fmt and wfmt can only be used once at a session and the strings needs +//! to be copied afterwards. A second use overwrites the first string. +const char * fmt(const char * format, ...); +const wchar_t * wfmt(const char * format, ...); +bool char2wchar_t(const char * src, wchar_t * dest); +int strtokcmp(const char * string, const char * compare, const char * separator); +const char * FullpathToFilename(const char *path); +int replaceString(char *string, const char *replace, const char *replacement); + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif /* __STRING_TOOLS_H */ + diff --git a/source/utils/ThreadedTask.cpp b/source/utils/ThreadedTask.cpp new file mode 100644 index 0000000..4d7b7e2 --- /dev/null +++ b/source/utils/ThreadedTask.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "ThreadedTask.hpp" + +ThreadedTask * ThreadedTask::instance = NULL; + +ThreadedTask::ThreadedTask() + : ExitRequested(false) +{ + LWP_CreateThread (&Thread, ThreadCallback, this, NULL, 16384, 70); +} + +ThreadedTask::~ThreadedTask() +{ + ExitRequested = true; + Execute(); + LWP_JoinThread(Thread, NULL); +} + +void * ThreadedTask::ThreadCallback(void *arg) +{ + ThreadedTask * myInstance = (ThreadedTask *) arg; + + while(!myInstance->ExitRequested) + { + LWP_SuspendThread(myInstance->Thread); + + while(!myInstance->CallbackList.empty()) + { + if(myInstance->CallbackList[0].first) + myInstance->CallbackList[0].first->Execute(myInstance->ArgList[0]); + + else if(myInstance->CallbackList[0].second) + myInstance->CallbackList[0].second(myInstance->ArgList[0]); + + myInstance->CallbackList.erase(myInstance->CallbackList.begin()); + myInstance->ArgList.erase(myInstance->ArgList.begin()); + } + } + + return NULL; +} diff --git a/source/utils/ThreadedTask.hpp b/source/utils/ThreadedTask.hpp new file mode 100644 index 0000000..4d99f71 --- /dev/null +++ b/source/utils/ThreadedTask.hpp @@ -0,0 +1,65 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef THREADED_TASK_HPP_ +#define THREADED_TASK_HPP_ + +#include +#include +#include "Callback.hpp" + +class ThreadedTask +{ + public: + static ThreadedTask * Instance() { if(!instance) instance = new ThreadedTask(); return instance; }; + static void DestroyInstance() { delete instance; instance = NULL; }; + + //! This callback is used for C-Like callbacks + typedef void (*Callback)(void * arg); + void AddCallback(ThreadedTask::Callback C_Standard, void * arg = 0) + { + CallbackList.push_back(std::pair(0, C_Standard)); + ArgList.push_back(arg); + } + //! This callback is used for C++-Like class callbacks + void AddCallback(cCallback * classCallback, void * arg = 0) + { + CallbackList.push_back(std::pair(classCallback, 0)); + ArgList.push_back(arg); + } + //! Start the threaded task thread and execute one callback after another - FIFO style + void Execute() { LWP_ResumeThread(Thread); }; + private: + ThreadedTask(); + ~ThreadedTask(); + void ThreadLoop(void *arg); + static void * ThreadCallback(void *arg); + + static ThreadedTask *instance; + lwp_t Thread; + bool ExitRequested; + std::vector > CallbackList; + std::vector ArgList; +}; + +#endif diff --git a/source/utils/U8Archive.cpp b/source/utils/U8Archive.cpp new file mode 100644 index 0000000..acfe9b2 --- /dev/null +++ b/source/utils/U8Archive.cpp @@ -0,0 +1,543 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok and giantpune + * + * 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 +#include + +#include "ash.h" +#include "lz77.h" +#include "gecko.h" +#include "U8Archive.h" +#include "uncompress.h" + +#define RU(N, S) ((((N) + (S) - 1) / (S)) * (S)) + +U8Archive::U8Archive(const u8 *stuff, u32 len ) + : fst( NULL ), + name_table( NULL ), + data( NULL ) +{ + if( stuff ) + { + SetData( stuff, len ); + } +} + +void U8Archive::SetData( const u8 *stuff, u32 len ) +{ + fst = NULL; + name_table = NULL; + data = NULL; + if( !stuff || len < 0x40 ) + { + gprintf( "SetData(): !stuff || len < 0x40 %p %08x\n", stuff, len ); + return; + } + stuff = FindU8Tag( stuff, len ); + if( !stuff ) + { + gprintf( "U8 tag not found\n" ); + return; + } + const U8Header * binHdr = (const U8Header *)stuff; + + const u8* fst_buffer = stuff + binHdr->rootNodeOffset; + fst = (FstEntry *)fst_buffer; + u32 name_table_offset = fst->filelen * 0xC; + name_table = (char *)( fst_buffer + name_table_offset ); + data = (u8*)stuff; +} + +const u8 *U8Archive::FindU8Tag( const u8* stuff, u32 len ) +{ + if( !stuff || len < 0x20 ) + { + return NULL; + } + if( *(u32*)( stuff ) == 0x55AA382D ) + { + return stuff; + } + if( len > 0x620 && *(u32*)( stuff + 0x600 ) == 0x55AA382D ) + { + return stuff + 0x600; + } + if( len > 0x660 && *(u32*)( stuff + 0x640 ) == 0x55AA382D ) + { + return stuff + 0x640; + } + return NULL; +} + +u8 *U8Archive::GetFile( const std::string &path, u32 *size ) const +{ + return GetFile( path.c_str(), size ); +} + +u8 *U8Archive::GetFile( const char *path, u32 *size ) const +{ + if( !path || !fst || !name_table ) + { + return NULL; + } + + s32 entryNo = EntryFromPath( path ); + if( entryNo < 1 ) + { + //gprintf( "U8: entry wasn\'t found in the archive \"%s\"\n", path ); + return NULL; + } + if( fst[ entryNo ].filetype ) + { + gprintf( "U8: \"%s\" is a folder\n", path ); + return NULL; + } + if( size ) + { + *size = fst[ entryNo ].filelen; + } + return data + fst[ entryNo ].fileoffset; +} + +u8 *U8Archive::GetFile( u32 fstIdx, u32 *size ) const +{ + if( !fst || !name_table ) + { + return NULL; + } + + if( fstIdx >= fst[0].filelen || fst[ fstIdx ].filetype ) + { + gprintf( "%i is a folder\n", fstIdx ); + return NULL; + } + + if( size ) + { + *size = fst[ fstIdx ].filelen; + } + return data + fst[ fstIdx ].fileoffset; +} + +u8* U8Archive::GetFileAllocated( const std::string &path, u32 *size ) const +{ + return GetFileAllocated( path.c_str(), size ); +} + +u8 *U8Archive::DecompressCopy( const u8 * stuff, u32 len, u32 *size ) const +{ + // check for IMD5 header and skip it + if( len > 0x40 && *(u32*)stuff == 0x494d4435 )// IMD5 + { + stuff += 0x20; + len -= 0x20; + } + + u8* ret = NULL; + // determine if it needs to be decompressed + if( IsAshCompressed( stuff, len ) ) + { + //u32 len2 = len; + // ASH0 + ret = DecompressAsh( stuff, len ); + if( !ret ) + { + gprintf( "out of memory\n" ); + return NULL; + } + } + else if( (len > 8) && *(u32*)( stuff ) == 0x59617a30 )// Yaz0 + { + // Yaz0 with a magic word + Yaz0_Header *header = (Yaz0_Header *) stuff; + // set decompress length + len = header->decompressed_size; + // allocate memory + ret = (u8*) memalign(32, ALIGN32(len)); + if(!ret) + { + gprintf("out of memory\n"); + return NULL; + } + // function can not fail at this point + uncompressYaz0(stuff, ret, len); + } + else if( isLZ77compressed( stuff ) ) + { + // LZ77 with no magic word + if( decompressLZ77content( stuff, len, &ret, &len ) ) + { + return NULL; + } + } + else if( *(u32*)( stuff ) == 0x4C5A3737 )// LZ77 + { + // LZ77 with a magic word + if( decompressLZ77content( stuff + 4, len - 4, &ret, &len ) ) + { + return NULL; + } + } + else + { + // just copy the data out of the archive + ret = (u8*)memalign( 32, ALIGN32( len ) ); + if( !ret ) + { + gprintf( "out of memory\n" ); + return NULL; + } + memcpy( ret, stuff, len ); + } + if( size ) + { + *size = len; + } + + // flush the cache so if there are any textures in this data, it will be ready for the GX + DCFlushRange( ret, len ); + return ret; +} + +u8* U8Archive::GetFileAllocated( const char *path, u32 *size ) const +{ + u32 len; + const u8 *stuff = GetFile( path, &len ); + if( !stuff ) + { + return NULL; + } + + return DecompressCopy( stuff, len, size ); +} + +u8* U8Archive::GetFileAllocated( u32 fstIdx, u32 *size ) const +{ + u32 len; + const u8 *stuff = GetFile( fstIdx, &len ); + if( !stuff ) + { + return NULL; + } + + return DecompressCopy( stuff, len, size ); +} + + +u32 U8Archive::FileDescriptor( const char *path ) const +{ + int ret = EntryFromPath( path ); + if( ret < 1 ) + { + return 0; + } + return ret; +} + +u8* U8Archive::GetFileFromFd( u32 fd, u32 *size )const +{ + if( !fst || !name_table || fd >= fst[ 0 ].filelen ) + { + return NULL; + } + if( fst[ fd ].filetype ) + { + gprintf( "U8: \"%s\" is a folder\n", FstName( &fst[ fd ] ) ); + return NULL; + } + if( size ) + { + *size = fst[ fd ].filelen; + } + return data + fst[ fd ].fileoffset; +} + +char *U8Archive::FstName( const FstEntry *entry ) const +{ + if( entry == &fst[ 0 ] ) + { + return NULL; + } + + return (char*)name_table + ( *((u32 *)entry) & 0x00ffffff ); +} + +int U8Archive::strcasecmp_slash( const char *s1, const char *s2 ) +{ + while( toupper( *s1 ) == toupper( *s2++ ) ) + { + if( *s1++ == 0 || *s1 == '/' ) + { + return 0; + } + } + + return( *(const unsigned char*)s1 - *(const unsigned char *)( s2 - 1 ) ); +} + +int U8Archive::strlen_slash( const char *s ) +{ + int ret = 0; + while( *s && *s++ != '/' ) + { + ret++; + } + + return ret; +} + +u32 U8Archive::NextEntryInFolder( u32 current, u32 directory ) const +{ + u32 next = ( fst[ current ].filetype ? fst[ current ].filelen : current + 1 ); + if( next < fst[ directory ].filelen ) + return next; + + return 0; +} + +s32 U8Archive::EntryFromPath( const char *path, int d ) const +{ + //gprintf( "EntryFromPath( \"%s\", %d )\n", path, d ); + while( *path == '/' ) + { + path++; + } + + if( !fst[ d ].filetype ) + { + gprintf("ERROR!! %s is not a directory\n", FstName( &fst[ d ] ) ); + return -1; + } + + u32 next = d + 1; + + FstEntry *entry = &fst[ next ]; + + while( next ) + { + //does this entry match. + //strlen_slash is used because if looking for "dvd:/gameboy/" it would return a false positive if it hit "dvd:/gameboy advance/" first + if( !strcasecmp_slash( path, FstName( entry ) ) && ( strlen( FstName( entry ) ) == (u32)strlen_slash( path ) ) ) + { + char *slash = strchr( path, '/' ); + if( slash && *( slash + 1 ) ) + { + //we are looking for a file somewhere in this folder + return EntryFromPath( slash + 1, next ); + } + //this is the actual entry we were looking for + return next; + } + + //find the next entry in this folder + next = NextEntryInFolder( next, d ); + entry = &fst[ next ]; + } + + //no entry with the given path was found + return -1; +} + +U8NandArchive::U8NandArchive( const char* nandPath ) + : U8Archive( NULL, 0 ), + fd( -1 ), + dataOffset( 0 ) +{ + if( nandPath ) + { + SetFile( nandPath ); + } +} + +U8NandArchive::~U8NandArchive() +{ + if( fd >= 0 ) + { + ISFS_Close( fd ); + } + free( fst ); +} + +bool U8NandArchive::SetFile( const char* nandPath ) +{ + if(fst) + free(fst); + if(name_table) + free(name_table); + CloseFile(); + + // open file + if( (fd = ISFS_Open( nandPath, ISFS_OPEN_READ ) ) < 0 ) + { + gprintf( "U8NandArchive: ISFS_Open( \"%s\" ) failed\n", nandPath ); + return false; + } + + // get file size + fstats stats __attribute__(( aligned( 32 ) )); + int ret = ISFS_GetFileStats( fd, &stats ); + if( ret < 0 ) + { + CloseFile(); + gprintf( "U8NandArchive: ISFS_GetFileStats( \"%s\" ) failed\n", nandPath ); + return false; + } + + // buffer for reading the header and stuff + u8* buffer = (u8*)memalign( 32, 0x800 ); + if( !buffer ) + { + CloseFile(); + gprintf( "U8NandArchive: enomem\n" ); + return false; + } + + // read a chunk big enough that it should contain the U8 header if there is going to be one + if( (ret = ISFS_Read( fd, buffer, 0x800 )) != 0x800 ) + { + free( buffer ); + CloseFile(); + gprintf( "U8NandArchive: ISFS_Read( 0x800 ) = %i\n", ret ); + return false; + } + + // find the start of the U8 data + U8Header* tagStart = (U8Header*)FindU8Tag( buffer, ret ); + if( !tagStart ) + { + free( buffer ); + CloseFile(); + gprintf( "U8NandArchive: didn't see a U8 tag\n" ); + return false; + } + + // remember where in the file the U8 starts + dataOffset = ( (u8*)tagStart - buffer ); + + // allocate memory and read the fst + if( !(fst = (FstEntry *)memalign( 32, RU( tagStart->dataOffset - dataOffset, 32 ) ) ) + || ( ISFS_Seek( fd, dataOffset + tagStart->rootNodeOffset, SEEK_SET ) != (s32)( dataOffset + tagStart->rootNodeOffset ) ) + || ( ISFS_Read( fd, fst, tagStart->dataOffset - dataOffset ) != (s32)( tagStart->dataOffset - dataOffset ) ) + || ( fst->filelen * 0xC > tagStart->dataOffset ) ) + { + dataOffset = 0; + free( buffer ); + if( fst ) + free( fst ); + CloseFile(); + gprintf( "U8NandArchive: error reading fst\n" ); + } + + // set name table pointer + u32 name_table_offset = fst->filelen * 0xC; + name_table = ((char *)fst) + name_table_offset; + + free( buffer ); + return true; +} + +u8* U8NandArchive::GetFileAllocated( const char *path, u32 *size ) const +{ + //gprintf( "U8NandArchive::GetFileAllocated( %s )\n" ); + if( !path || !fst ) + { + return NULL; + } + + // find file + int f = EntryFromPath( path, 0 ); + if( f < 1 || f >= (int)fst[ 0 ].filelen ) + { + gprintf( "U8: \"%s\" wasn't found in the archive.\n", path ); + return NULL; + } + if( fst[ f ].filetype ) + { + gprintf( "U8: \"%s\" is a folder\n", path ); + return NULL; + } + + // create a buffer + u8* ret = (u8*)memalign( 32, RU( fst[ f ].filelen, 32 ) ); + if( !ret ) + { + gprintf( "U8: out of memory\n" ); + return NULL; + } + + // seek and read + if( ISFS_Seek( fd, dataOffset + fst[ f ].fileoffset, SEEK_SET ) != (s32)( dataOffset + fst[ f ].fileoffset ) + || ISFS_Read( fd, ret, fst[ f ].filelen ) != (s32)fst[ f ].filelen ) + { + free( ret ); + gprintf( "U8: error reading data from nand\n" ); + gprintf( "fd: %i fst[ fd ].filelen: %08x\n", fd, fst[ f ].filelen ); + return NULL; + } + + u32 len = fst[ f ].filelen; + u8* ret2; + // determine if it needs to be decompressed + if( IsAshCompressed( ret, len ) ) + { + // ASH0 + ret2 = DecompressAsh( ret, len ); + if( !ret2 ) + { + free( ret ); + gprintf( "out of memory\n" ); + return NULL; + } + free( ret ); + } + else if( isLZ77compressed( ret ) ) + { + // LZ77 with no magic word + if( decompressLZ77content( ret, len, &ret2, &len ) ) + { + free( ret ); + return NULL; + } + free( ret ); + } + else if( *(u32*)( ret ) == 0x4C5A3737 )// LZ77 + { + // LZ77 with a magic word + if( decompressLZ77content( ret + 4, len - 4, &ret2, &len ) ) + { + free( ret ); + return NULL; + } + free( ret ); + } + else + { + // already got what we are after + ret2 = ret; + } + + if( size ) + { + *size = len; + } + + // flush the cache so if there are any textures in this data, it will be ready for the GX + DCFlushRange( ret2, len ); + return ret2; +} + diff --git a/source/utils/U8Archive.h b/source/utils/U8Archive.h new file mode 100644 index 0000000..4f0c697 --- /dev/null +++ b/source/utils/U8Archive.h @@ -0,0 +1,128 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok and giantpune + * + * 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 U8ARCHIVE_H +#define U8ARCHIVE_H + +#include +#include +#include "tools.h" + +class U8Archive +{ +public: + U8Archive( const u8 *stuff, u32 len ); + + // set the data used for this archive + virtual void SetData( const u8 *stuff, u32 len ); + + // returns a pointer to a file within the archive + virtual u8* GetFile( const char *path, u32 *size = NULL ) const; + virtual u8* GetFile( const std::string &path, u32 *size = NULL ) const; + virtual u8* GetFile( u32 fstIdx, u32 *size = NULL ) const; + + // gets a file and copies it into a newly memalign()'d buffer + //! if the data looks ASH or LZ77 compressed, it is decompressed + virtual u8* GetFileAllocated( const char *path, u32 *size = NULL ) const; + virtual u8* GetFileAllocated( const std::string &path, u32 *size = NULL ) const; + virtual u8* GetFileAllocated( u32 fstIdx, u32 *size = NULL ) const; + + virtual u32 FileDescriptor( const char *path ) const; + virtual u32 FileDescriptor( const std::string &path ) const{ return FileDescriptor( path.c_str() ); } + virtual u8* GetFileFromFd( u32 fd, u32 *size = NULL )const; + + +protected: + struct U8Header + { + u32 magic; + u32 rootNodeOffset; + u32 headerSize; + u32 dataOffset; + u8 zeroes[16]; + } __attribute__((packed)); + + struct FstEntry + { + u8 filetype; + char name_offset[3]; + u32 fileoffset; + u32 filelen; + } __attribute__((packed)); + + FstEntry *fst; + char *name_table; + u8* data; + + u32 NextEntryInFolder( u32 current, u32 directory ) const ; + s32 EntryFromPath( const char *path, int d = 0 ) const ; + char *FstName( const FstEntry *entry ) const; + u8 *DecompressCopy( const u8 * stuff, u32 len, u32 *size ) const; + + static int strlen_slash( const char *s ); + + static int strcasecmp_slash( const char *s1, const char *s2 ); + + // lightweight toupper - because U8 archives are case-insinsitive + static char toupper( char c ) + { + if( c <= 'z' && c >= 'a' ) + return c - 0x20; + return c; + } + + // looks in some common offsets for a U8 tag + static const u8* FindU8Tag( const u8* stuff, u32 len ); +}; + +// class to access files from an archive that is saved on the nand +// GetFile() will return NULL, use GetfileAllocated() +class U8NandArchive : public U8Archive +{ +public: + U8NandArchive( const char* nandPath ); + ~U8NandArchive(); + + bool SetFile( const char* nandPath ); + + + // not implimented in this subclass... + void SetData( const u8 *stuff, u32 len ){} + u8* GetFile( const char *path, u32 *size = NULL ) const { return NULL; } + u8* GetFile( const std::string &path, u32 *size = NULL ) const { return NULL; } + u8* GetFileFromFd( u32 fd, u32 *size = NULL )const { return NULL; } + + + // gets a file and copies it into a newly memalign()'d buffer + //! if the data looks ASH or LZ77 compressed, it is decompressed + u8* GetFileAllocated( const char *path, u32 *size = NULL ) const; + +private: + s32 fd; + + // where the U8 header starts within the file + u32 dataOffset; + void CloseFile() + { + if( fd >= 0 ) + { + ISFS_Close( fd ); + fd = -1; + } + } +}; + +#endif // U8ARCHIVE_H diff --git a/source/utils/ash.cpp b/source/utils/ash.cpp new file mode 100644 index 0000000..53f099b --- /dev/null +++ b/source/utils/ash.cpp @@ -0,0 +1,455 @@ +/**************************************************************************** + * Copyright (C) 2012 giantpune + * + * 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 "ash.h" +#include "gecko.h" + +#include +#include +//#include +#include +#include + + + +bool IsAshCompressed( const u8 *stuff, u32 len ) +{ + return ( len > 0x10 && + ((*(u32*)( stuff )) & 0xFFFFFF00 ) == 0x41534800 ); +} + +u8* DecompressAsh( const u8 *stuff, u32 &len ) +{ + if( !IsAshCompressed( stuff, len ) ) + { + return NULL; + } + + unsigned int r[32]; + unsigned int count = 0; + unsigned int t; + + r[4] = (u32)stuff; //in + + r[5] = 0x415348; + r[6] = 0x415348; + + r[5] = s32(*(unsigned int *)(r[4]+4)); + r[5] = r[5] & 0x00FFFFFF; + + u32 size = r[5]; + //gprintf("Decompressed size: %d\n", size); + u8* buf1 = (u8*)memalign( 32, size ); + if( !buf1 ) + { + gprintf( "ASH: no memory\n" ); + return NULL; + } + r[3] = (u32)buf1; //out + memset( (void*)buf1, 0, size ); + //printf("r[3] :%08X\n", r[3]); + + //printf("\n\n"); + + r[24] = 0x10; + r[28] = s32(*(unsigned int *)(r[4]+8)); + r[25] = 0; + r[29] = 0; + r[26] = s32(*(unsigned int *)(r[4]+0xC)); + r[30] = s32(*(unsigned int *)(r[4]+r[28])); + r[28] = r[28] + 4; + //r[8] = 0x8108<<16; + //HACK, pointer to RAM + u8* workingBuffer = (u8*)memalign( 32, 0x100000 ); + if( !workingBuffer ) + { + gprintf( "ASH: no memory 2\n" ); + free( buf1 ); + return NULL; + } + r[8] = (u32)workingBuffer; + memset( (void*)workingBuffer, 0, 0x100000 ); + //printf("r[8] :%08X\n", r[8]); + + r[8] = r[8]; + r[9] = r[8] + 0x07FE; + r[10] = r[9] + 0x07FE; + r[11] = r[10] + 0x1FFE; + r[31] = r[11] + 0x1FFE; + r[23] = 0x200; + r[22] = 0x200; + r[27] = 0; + +loc_81332124: + + if( r[25] != 0x1F ) + goto loc_81332140; + + r[0] = r[26] >> 31; + r[26]= s32(*(unsigned int *)(r[4] + r[24])); + r[25]= 0; + r[24]= r[24] + 4; + goto loc_8133214C; + +loc_81332140: + + r[0] = r[26] >> 31; + r[25]= r[25] + 1; + r[26]= r[26] << 1; + +loc_8133214C: + + if( r[0] == 0 ) + goto loc_81332174; + + r[0] = r[23] | 0x8000; + *(unsigned short *)(r[31]) = s16(r[0]); + r[0] = r[23] | 0x4000; + *(unsigned short *)(r[31]+2) = s16(r[0]); + + r[31] = r[31] + 4; + r[27] = r[27] + 2; + r[23] = r[23] + 1; + r[22] = r[22] + 1; + + goto loc_81332124; + +loc_81332174: + + r[12] = 9; + r[21] = r[25] + r[12]; + t = r[21]; + if( r[21] > 0x20 ) + goto loc_813321AC; + + r[21] = (~(r[12] - 0x20))+1; + r[6] = r[26] >> r[21]; + if( t == 0x20 ) + goto loc_8133219C; + + r[26] = r[26] << r[12]; + r[25] = r[25] + r[12]; + goto loc_813321D0; + +loc_8133219C: + + r[26]= s32(*(unsigned int *)(r[4] + r[24])); + r[25]= 0; + r[24]= r[24] + 4; + goto loc_813321D0; + +loc_813321AC: + + r[0] = (~(r[12] - 0x20))+1; + r[6] = r[26] >> r[0]; + r[26]= s32(*(unsigned int *)(r[4] + r[24])); + r[0] = (~(r[21] - 0x40))+1; + r[24]= r[24] + 4; + r[0] = r[26] >> r[0]; + r[6] = r[6] | r[0]; + r[25] = r[21] - 0x20; + r[26] = r[26] << r[25]; + +loc_813321D0: + + r[12]= s16(*(unsigned short *)(r[31] - 2)); + r[31] -= 2; + r[27]= r[27] - 1; + r[0] = r[12] & 0x8000; + r[12]= (r[12] & 0x1FFF) << 1; + if( r[0] == 0 ) + goto loc_813321F8; + + *(unsigned short *)(r[9]+r[12]) = s16(r[6]); + r[6] = (r[12] & 0x3FFF)>>1; // extrwi %r6, %r12, 14,17 + if( r[27] != 0 ) + goto loc_813321D0; + + goto loc_81332204; + +loc_813321F8: + + *(unsigned short *)(r[8]+r[12]) = s16(r[6]); + r[23] = r[22]; + goto loc_81332124; + +loc_81332204: + + r[23] = 0x800; + r[22] = 0x800; + +loc_8133220C: + + if( r[29] != 0x1F ) + goto loc_81332228; + + r[0] = r[30] >> 31; + r[30]= s32(*(unsigned int *)(r[4] + r[28])); + r[29]= 0; + r[28]= r[28] + 4; + goto loc_81332234; + +loc_81332228: + + r[0] = r[30] >> 31; + r[29]= r[29] + 1; + r[30]= r[30] << 1; + +loc_81332234: + + if( r[0] == 0 ) + goto loc_8133225C; + + r[0] = r[23] | 0x8000; + *(unsigned short *)(r[31]) = s16(r[0]); + r[0] = r[23] | 0x4000; + *(unsigned short *)(r[31]+2) = s16(r[0]); + + r[31] = r[31] + 4; + r[27] = r[27] + 2; + r[23] = r[23] + 1; + r[22] = r[22] + 1; + + goto loc_8133220C; + +loc_8133225C: + + r[12] = 0xB; + r[21] = r[29] + r[12]; + t = r[21]; + if( r[21] > 0x20 ) + goto loc_81332294; + + r[21] = (~(r[12] - 0x20))+1; + r[7] = r[30] >> r[21]; + if( t == 0x20 ) + goto loc_81332284; + + r[30] = r[30] << r[12]; + r[29] = r[29] + r[12]; + goto loc_813322B8; + +loc_81332284: + + r[30]= s32(*(unsigned int *)(r[4] + r[28])); + r[29]= 0; + r[28]= r[28] + 4; + goto loc_813322B8; + +loc_81332294: + + r[0] = (~(r[12] - 0x20))+1; + r[7] = r[30] >> r[0]; + r[30]= s32(*(unsigned int *)(r[4] + r[28])); + r[0] = (~(r[21] - 0x40))+1; + r[28]= r[28] + 4; + r[0] = r[30] >> r[0]; + r[7] = r[7] | r[0]; + r[29]= r[21] - 0x20; + r[30]= r[30] << r[29]; + +loc_813322B8: + + r[12]= s16(*(unsigned short *)(r[31] - 2)); + r[31] -= 2; + r[27]= r[27] - 1; + r[0] = r[12] & 0x8000; + r[12]= (r[12] & 0x1FFF) << 1; + if( r[0] == 0 ) + goto loc_813322E0; + + *(unsigned short *)(r[11]+r[12]) = s16(r[7]); + r[7] = (r[12] & 0x3FFF)>>1; // extrwi %r7, %r12, 14,17 + if( r[27] != 0 ) + goto loc_813322B8; + + goto loc_813322EC; + +loc_813322E0: + + *(unsigned short *)(r[10]+r[12]) = s16(r[7]); + r[23] = r[22]; + goto loc_8133220C; + +loc_813322EC: + + r[0] = r[5]; + +loc_813322F0: + + r[12]= r[6]; + +loc_813322F4: + + if( r[12] < 0x200 ) + goto loc_8133233C; + + if( r[25] != 0x1F ) + goto loc_81332318; + + r[31] = r[26] >> 31; + r[26] = s32(*(unsigned int *)(r[4] + r[24])); + r[24] = r[24] + 4; + r[25] = 0; + goto loc_81332324; + +loc_81332318: + + r[31] = r[26] >> 31; + r[25] = r[25] + 1; + r[26] = r[26] << 1; + +loc_81332324: + + r[27] = r[12] << 1; + if( r[31] != 0 ) + goto loc_81332334; + + r[12] = s16(*(unsigned short *)(r[8] + r[27])); + goto loc_813322F4; + +loc_81332334: + + r[12] = s16(*(unsigned short *)(r[9] + r[27])); + goto loc_813322F4; + +loc_8133233C: + + if( r[12] >= 0x100 ) + goto loc_8133235C; + + *(unsigned char *)(r[3]) = r[12]; + r[3] = r[3] + 1; + r[5] = r[5] - 1; + if( r[5] != 0 ) + goto loc_813322F0; + + goto loc_81332434; + +loc_8133235C: + + r[23] = r[7]; + +loc_81332360: + + if( r[23] < 0x800 ) + goto loc_813323A8; + + if( r[29] != 0x1F ) + goto loc_81332384; + + r[31] = r[30] >> 31; + r[30] = s32(*(unsigned int *)(r[4] + r[28])); + r[28] = r[28] + 4; + r[29] = 0; + goto loc_81332390; + +loc_81332384: + + r[31] = r[30] >> 31; + r[29] = r[29] + 1; + r[30] = r[30] << 1; + +loc_81332390: + + r[27] = r[23] << 1; + if( r[31] != 0 ) + goto loc_813323A0; + + r[23] = s16(*(unsigned short *)(r[10] + r[27])); + goto loc_81332360; + +loc_813323A0: + + r[23] = s16(*(unsigned short *)(r[11] + r[27])); + goto loc_81332360; + +loc_813323A8: + + r[12] = r[12] - 0xFD; + r[23] = ~r[23] + r[3] + 1; + r[5] = ~r[12] + r[5] + 1; + r[31] = r[12] >> 3; + + if( r[31] == 0 ) + goto loc_81332414; + + count = r[31]; + +loc_813323C0: + + r[31] = *(unsigned char *)(r[23] - 1); + *(unsigned char *)(r[3]) = r[31]; + + r[31] = *(unsigned char *)(r[23]); + *(unsigned char *)(r[3]+1) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 1); + *(unsigned char *)(r[3]+2) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 2); + *(unsigned char *)(r[3]+3) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 3); + *(unsigned char *)(r[3]+4) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 4); + *(unsigned char *)(r[3]+5) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 5); + *(unsigned char *)(r[3]+6) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 6); + *(unsigned char *)(r[3]+7) = r[31]; + + r[23] = r[23] + 8; + r[3] = r[3] + 8; + + if( --count ) + goto loc_813323C0; + + r[12] = r[12] & 7; + if( r[12] == 0 ) + goto loc_8133242C; + +loc_81332414: + + count = r[12]; + +loc_81332418: + + r[31] = *(unsigned char *)(r[23] - 1); + r[23] = r[23] + 1; + *(unsigned char *)(r[3]) = r[31]; + r[3] = r[3] + 1; + + if( --count ) + goto loc_81332418; + +loc_8133242C: + + if( r[5] != 0 ) + goto loc_813322F0; + +loc_81332434: + + r[3] = r[0]; + len = r[3]; + + //gprintf("Decompressed %d bytes\n", r[3]); + free( workingBuffer ); + return buf1; +} diff --git a/source/utils/ash.h b/source/utils/ash.h new file mode 100644 index 0000000..43614c6 --- /dev/null +++ b/source/utils/ash.h @@ -0,0 +1,30 @@ +/**************************************************************************** + * Copyright (C) 2012 giantpune + * + * 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 ASH_H +#define ASH_H + +#include + +// check if data is ash compressed +bool IsAshCompressed( const u8 *stuff, u32 len ); + +// decompress ash compressed data +//! len is the size of the compressed data, and is set to the size of the decompressed data +//! this allocates memory with memalign, free it when you are done with it + +u8* DecompressAsh( const u8 *stuff, u32 &len ); +#endif // ASH_H diff --git a/source/utils/encrypt.c b/source/utils/encrypt.c new file mode 100644 index 0000000..53cadbe --- /dev/null +++ b/source/utils/encrypt.c @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by dude, Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include + +//! No need for high security crap. It's a simple encrypter/decrypter +//! with a constant sid. +const char * sid = "USBLoaderGX"; + +void EncryptString(const char *src, char *dst) +{ + unsigned int i; + char tmp[3]; + dst[0] = 0; + + for (i = 0; i < strlen(src); i++) + { + sprintf(tmp, "%02x", src[i] ^ sid[i%10]); + strcat(dst, tmp); + } +} + +void DecryptString(const char *src, char *dst) +{ + unsigned int i; + for (i = 0; i < strlen(src); i += 2) + { + char c = (src[i] >= 'a' ? (src[i] - 'a') + 10 : (src[i] - '0')) << 4; + c += (src[i+1] >= 'a' ? (src[i+1] - 'a') + 10 : (src[i+1] - '0')); + dst[i>>1] = c ^ sid[(i>>1)%10]; + } + dst[strlen(src)>>1] = 0; +} + diff --git a/source/utils/encrypt.h b/source/utils/encrypt.h new file mode 100644 index 0000000..6c8139d --- /dev/null +++ b/source/utils/encrypt.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by dude + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef __ENCRYPT_H +#define __ENCRYPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +void EncryptString(const char *src, char *dst); +void DecryptString(const char *src, char *dst); + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif /* __ENCRYPT_H */ + diff --git a/source/utils/gx_addons.c b/source/utils/gx_addons.c new file mode 100644 index 0000000..ce7402a --- /dev/null +++ b/source/utils/gx_addons.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 + +void GX_Project(f32 mx, f32 my, f32 mz, Mtx mv, const f32 *projection, + const f32 *viewport, f32 *sx, f32 *sy, f32 *sz) +{ + float x, y, z, w; + + guVector vec = (guVector) { mx, my, mz }; + guVector vecRes; + guVecMultiply(mv, &vec, &vecRes); + + if(projection[0] == GX_PERSPECTIVE) + { + x = (vecRes.x * projection[1]) + (vecRes.z * projection[2]); + y = (vecRes.y * projection[3]) + (vecRes.z * projection[4]); + z = (vecRes.z * projection[5]) + projection[6]; + w = -1.0f / vecRes.z; + } + else + { + x = (vecRes.x * projection[1]) + projection[2]; + y = (vecRes.y * projection[3]) + projection[4]; + z = (vecRes.z * projection[5]) + projection[6]; + w = 1.0f; + } + + *sx = viewport[0] + (w * x * viewport[2] + viewport[2]) * 0.5f; + *sy = viewport[1] - (w * y * viewport[3] - viewport[3]) * 0.5f; + *sz = viewport[5] + (w * z * (viewport[5] - viewport[4])); +} + +void GX_GetProjectionv( f32* ptr, Mtx44 p, u8 type) +{ + ptr[0] = (f32)type; + ptr[1] = p[0][0]; + ptr[3] = p[1][1]; + ptr[5] = p[2][2]; + ptr[6] = p[2][3]; + + if(type == GX_PERSPECTIVE) + { + ptr[2] = p[0][2]; + ptr[4] = p[1][2]; + } + else + { + ptr[2] = p[0][3]; + ptr[4] = p[1][3]; + } +} + +void GX_GetViewportv( f32* ptr, GXRModeObj *vmode ) +{ + ptr[0] = 0.0f; + ptr[1] = 0.0f; + ptr[2] = vmode->fbWidth; + ptr[3] = vmode->efbHeight; + ptr[4] = 0.0f; + ptr[5] = 1.0f; +} diff --git a/source/utils/gx_addons.h b/source/utils/gx_addons.h new file mode 100644 index 0000000..89afbf3 --- /dev/null +++ b/source/utils/gx_addons.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * 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 GX_ADDONS_H_ +#define GX_ADDONS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void GX_Project(f32 mx, f32 my, f32 mz, Mtx mv, const f32 *projection, + const f32 *viewport, f32 *sx, f32 *sy, f32 *sz); +void GX_GetProjectionv( f32* ptr, Mtx44 p, u8 type); +void GX_GetViewportv( f32* ptr, GXRModeObj *vmode ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/utils/lz77.c b/source/utils/lz77.c new file mode 100755 index 0000000..cf2846f --- /dev/null +++ b/source/utils/lz77.c @@ -0,0 +1,199 @@ +/******************************************************************************* + * lz77.c + * + * Copyright (c) 2009 The Lemon Man + * Copyright (c) 2009 Nicksasa + * Copyright (c) 2009 WiiPower + * + * Distributed under the terms of the GNU General Public License (v2) + * See http://www.gnu.org/licenses/gpl-2.0.txt for more info. + * + * Description: + * ----------- + * + ******************************************************************************/ + +#include +#include +#include +#include +#include + +#include "lz77.h" +#include "tools.h" + +static inline u32 packBytes(int a, int b, int c, int d) +{ + return (d << 24) | (c << 16) | (b << 8) | (a); +} + +s32 __decompressLZ77_11( const u8 *in, u32 inputLen, u8 **output, u32 *outputLen) +{ + int x, y; + + u8 *out = NULL; + + u32 compressedPos = 0x4; + u32 decompressedPos = 0x0; + u32 decompressedSize = 0; + + decompressedSize = packBytes(in[0], in[1], in[2], in[3]) >> 8; + + if (!decompressedSize) + { + decompressedSize = packBytes(in[4], in[5], in[6], in[7]); + compressedPos += 0x4; + } + + out = memalign(32, ALIGN32(decompressedSize)); + if (out == NULL) + return -1; + + while (compressedPos < inputLen && decompressedPos < decompressedSize) + { + u8 byteFlag = in[compressedPos]; + compressedPos++; + + for (x = 7; x >= 0; x--) + { + if ((byteFlag & (1 << x)) > 0) + { + u8 first = in[compressedPos]; + u8 second = in[compressedPos + 1]; + + u32 pos, copyLen; + + if (first < 0x20) + { + u8 third = in[compressedPos + 2]; + + if (first >= 0x10) + { + u32 fourth = in[compressedPos + 3]; + + pos = (u32)(((third & 0xF) << 8) | fourth) + 1; + copyLen = (u32)((second << 4) | ((first & 0xF) << 12) | (third >> 4)) + 273; + + compressedPos += 4; + } else + { + pos = (u32)(((second & 0xF) << 8) | third) + 1; + copyLen = (u32)(((first & 0xF) << 4) | (second >> 4)) + 17; + + compressedPos += 3; + } + } else + { + pos = (u32)(((first & 0xF) << 8) | second) + 1; + copyLen = (u32)(first >> 4) + 1; + + compressedPos += 2; + } + + for (y = 0; y < (int) copyLen; y++) + { + out[decompressedPos + y] = out[decompressedPos - pos + y]; + } + + decompressedPos += copyLen; + } else + { + out[decompressedPos] = in[compressedPos]; + + decompressedPos++; + compressedPos++; + } + + if (compressedPos >= inputLen || decompressedPos >= decompressedSize) + break; + } + } + *output = out; + *outputLen = decompressedSize; + return 0; +} + +s32 __decompressLZ77_10( const u8 *in, u32 inputLen, u8 **output, u32 *outputLen) +{ + int x, y; + + u8 *out = NULL; + + u32 compressedPos = 0; + u32 decompressedSize = 0x4; + u32 decompressedPos = 0; + + decompressedSize = packBytes(in[0], in[1], in[2], in[3]) >> 8; + + out = memalign(32, ALIGN32(decompressedSize)); + if (out == NULL) + return -1; + + compressedPos += 0x4; + + while (decompressedPos < decompressedSize) + { + u8 flag = *(u8*)(in + compressedPos); + compressedPos += 1; + + for (x = 0; x < 8; x++) + { + if (flag & 0x80) + { + u8 first = in[compressedPos]; + u8 second = in[compressedPos + 1]; + + u16 pos = (u16)((((first << 8) + second) & 0xFFF) + 1); + u8 copyLen = (u8)(3 + ((first >> 4) & 0xF)); + + for (y = 0; y < copyLen; y++) + { + out[decompressedPos + y] = out[decompressedPos - pos + (y % pos)]; + } + + compressedPos += 2; + decompressedPos += copyLen; + } else + { + out[decompressedPos] = in[compressedPos]; + compressedPos += 1; + decompressedPos += 1; + } + + flag <<= 1; + + if (decompressedPos >= decompressedSize) + break; + } + } + + *output = out; + *outputLen = decompressedSize; + return 0; +} + +int isLZ77compressed( const u8 *buffer) +{ + if ((buffer[0] == LZ77_0x10_FLAG) || (buffer[0] == LZ77_0x11_FLAG)) + return 1; + + return 0; +} + +int decompressLZ77content(const u8 *buffer, u32 length, u8 **output, u32 *outputLen) +{ + int ret; + switch (buffer[0]) + { + case LZ77_0x10_FLAG: + ret = __decompressLZ77_10(buffer, length, output, outputLen); + break; + case LZ77_0x11_FLAG: + ret = __decompressLZ77_11(buffer, length, output, outputLen); + break; + default: + ret = -1; + break; + } + return ret; +} diff --git a/source/utils/lz77.h b/source/utils/lz77.h new file mode 100755 index 0000000..185ca54 --- /dev/null +++ b/source/utils/lz77.h @@ -0,0 +1,33 @@ +/******************************************************************************* + * lz77.h + * + * Copyright (c) 2009 The Lemon Man + * Copyright (c) 2009 Nicksasa + * Copyright (c) 2009 WiiPower + * + * Distributed under the terms of the GNU General Public License (v2) + * See http://www.gnu.org/licenses/gpl-2.0.txt for more info. + * + * Description: + * ----------- + * + ******************************************************************************/ +#ifndef _LZ77_MODULE +#define _LZ77_MODULE + +#define LZ77_0x10_FLAG 0x10 +#define LZ77_0x11_FLAG 0x11 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int isLZ77compressed( const u8 *buffer); +int decompressLZ77content( const u8 *buffer, u32 length, u8 **output, u32 *outputLen); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/source/utils/minizip/miniunz.c b/source/utils/minizip/miniunz.c new file mode 100644 index 0000000..09370be --- /dev/null +++ b/source/utils/minizip/miniunz.c @@ -0,0 +1,299 @@ +/* + miniunz.c + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + */ + +#include +#include +#include +#include +#include +#include +# include +# include + +#include "miniunz.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +static int mymkdir(const char* dirname) +{ + int ret = 0; + ret = mkdir(dirname, 0775); + return ret; +} + +int makedir(char *newdir) +{ + char *buffer; + char *p; + int len = (int) strlen(newdir); + + if (len <= 0) return 0; + + buffer = (char*) malloc(len + 1); + strcpy(buffer, newdir); + + if (buffer[len - 1] == '/') + { + buffer[len - 1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + free(buffer); + return 1; + } + + p = buffer + 1; + while (1) + { + char hold; + + while (*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + // printf("couldn't create directory %s\n",buffer); + free(buffer); + return 0; + } + if (hold == 0) break; + *p++ = hold; + } + free(buffer); + return 1; +} + +static char *fullfilename(const char *basedir, char *filename) +{ + char *file = (char *) malloc(strlen(basedir) + strlen(filename) + 1); + if (basedir == NULL) + { + strcpy(file, filename); + } + else + { + if (basedir[strlen(basedir) - 1] == '/') + { + sprintf(file, "%s%s", basedir, filename); + } + else + { + sprintf(file, "%s/%s", basedir, filename); + } + } + return file; +} + +static int do_extract_currentfile(unzFile uf, const int* popt_extract_without_path, int* popt_overwrite, + const char* password, const char *basedir) +{ + char filename_inzip[256]; + char* filename_withoutpath; + char* filename_withpath; + char* p; + int err = UNZ_OK; + FILE *fout = NULL; + void* buf; + uInt size_buf; + + unz_file_info file_info; + err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + + if (err != UNZ_OK) + { + // printf("error %d with zipfile in unzGetCurrentFileInfo\n",err); + return err; + } + + size_buf = WRITEBUFFERSIZE; + buf = (void*) malloc(size_buf); + if (buf == NULL) + { + // printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + + p = filename_withoutpath = filename_inzip; + filename_withpath = fullfilename(basedir, filename_inzip); + while ((*p) != '\0') + { + if (((*p) == '/') || ((*p) == '\\')) filename_withoutpath = p + 1; + p++; + } + + if ((*filename_withoutpath) == '\0') + { + if ((*popt_extract_without_path) == 0) + { + + // Fix the path, this will fail if the directoryname is the same as the first filename in the zip + char *path = (char *) malloc(strlen(filename_withpath)); + strcpy(path, filename_withpath); + char *ptr = strstr(path, filename_withoutpath); + *ptr = '\0'; + + // printf("creating directory: %s\n",path); + mymkdir(path); + + free(path); + } + } + else + { + char* write_filename; + int skip = 0; + + if ((*popt_extract_without_path) == 0) + write_filename = filename_withpath; + else write_filename = filename_withoutpath; + + err = unzOpenCurrentFilePassword(uf, password); + if (err != UNZ_OK) + { + // printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err); + } + + if (((*popt_overwrite) == 0) && (err == UNZ_OK)) + { + char rep = 0; + FILE* ftestexist; + ftestexist = fopen(write_filename, "rb"); + if (ftestexist != NULL) + { + fclose(ftestexist); + do + { + char answer[128]; + int ret; + + // printf("The file %s exists. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename); + ret = scanf("%1s", answer); + if (ret != 1) + { + exit(EXIT_FAILURE); + } + rep = answer[0]; + if ((rep >= 'a') && (rep <= 'z')) rep -= 0x20; + } while ((rep != 'Y') && (rep != 'N') && (rep != 'A')); + } + + if (rep == 'N') skip = 1; + + if (rep == 'A') *popt_overwrite = 1; + } + + if ((skip == 0) && (err == UNZ_OK)) + { + fout = fopen(write_filename, "wb"); + + /* some zipfile don't contain directory alone before file */ + if ((fout == NULL) && ((*popt_extract_without_path) == 0) && (filename_withoutpath + != (char*) filename_inzip)) + { + char c = *(filename_withoutpath - 1); + *(filename_withoutpath - 1) = '\0'; + + // Fix the path, this will fail if the directoryname is the same as the first filename in the zip + char *path = (char *) malloc(strlen(write_filename)); + strcpy(path, write_filename); + char *ptr = strstr(path, filename_withoutpath); + *ptr = '\0'; + makedir(path); + free(path); + + *(filename_withoutpath - 1) = c; + fout = fopen(write_filename, "wb"); + } + + if (fout == NULL) + { + // printf("error opening %s\n",write_filename); + } + } + + if (fout != NULL) + { + // printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf, buf, size_buf); + if (err < 0) + { + // printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err > 0) if (fwrite(buf, err, 1, fout) != 1) + { + // printf("error in writing extracted file\n"); + err = UNZ_ERRNO; + break; + } + } while (err > 0); + if (fout) fclose(fout); + + } + + if (err == UNZ_OK) + { + err = unzCloseCurrentFile(uf); + if (err != UNZ_OK) + { + // printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else unzCloseCurrentFile(uf); /* don't lose the error */ + } + free(filename_withpath); + free(buf); + return err; +} + +int extractZip(unzFile uf, int opt_extract_without_path, int opt_overwrite, const char* password, const char *basedir) +{ + uLong i; + unz_global_info gi; + int err; + + err = unzGetGlobalInfo(uf, &gi); + if (err != UNZ_OK) + // printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i = 0; i < gi.number_entry; i++) + { + if (do_extract_currentfile(uf, &opt_extract_without_path, &opt_overwrite, password, basedir) != UNZ_OK) break; + + if ((i + 1) < gi.number_entry) + { + err = unzGoToNextFile(uf); + if (err != UNZ_OK) + { + // printf("error %d with zipfile in unzGoToNextFile\n",err); + break; + } + } + } + + return 0; +} + +int extractZipOnefile(unzFile uf, const char* filename, int opt_extract_without_path, int opt_overwrite, + const char* password) +{ + if (unzLocateFile(uf, filename, CASESENSITIVITY) != UNZ_OK) + { + // printf("file %s not found in the zipfile\n",filename); + return 2; + } + + if (do_extract_currentfile(uf, &opt_extract_without_path, &opt_overwrite, password, NULL) == UNZ_OK) + return 0; + else return 1; +} diff --git a/source/utils/minizip/miniunz.h b/source/utils/minizip/miniunz.h new file mode 100644 index 0000000..3120617 --- /dev/null +++ b/source/utils/minizip/miniunz.h @@ -0,0 +1,21 @@ +#ifndef _miniunz_H +#define _miniunz_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + + int extractZip(unzFile uf, int opt_extract_without_path, int opt_overwrite, const char* password, + const char *basedir); + int extractZipOnefile(unzFile uf, const char* filename, int opt_extract_without_path, int opt_overwrite, + const char* password); + int makedir(char *newdir); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/utils/rockout.cpp b/source/utils/rockout.cpp new file mode 100644 index 0000000..a28714e --- /dev/null +++ b/source/utils/rockout.cpp @@ -0,0 +1,36 @@ +#include "GUI/gui.h" +#include "themes/CTheme.h" +#include "usbloader/GameList.h" +#include "settings/GameTitles.h" +#include "menu/menus.h" + +void rockout(struct discHdr *header) +{ + static bool rockoutSet = false; + + HaltGui(); + + if (!rockoutSet && header && + header->id[0] != 'W' && header->id[0] != 'G' && // Exclude Wiiware and GameCube games + ( strcasestr(GameTitles.GetTitle(header), "guitar") + || strcasestr(GameTitles.GetTitle(header), "band") + || strcasestr(GameTitles.GetTitle(header), "rock"))) + { + pointer[0]->SetImage("rplayer1_point.png"); + pointer[1]->SetImage("rplayer2_point.png"); + pointer[2]->SetImage("rplayer3_point.png"); + pointer[3]->SetImage("rplayer4_point.png"); + + rockoutSet = true; + } + else if(rockoutSet) + { + pointer[0]->SetImage("player1_point.png"); + pointer[1]->SetImage("player2_point.png"); + pointer[2]->SetImage("player3_point.png"); + pointer[3]->SetImage("player4_point.png"); + + rockoutSet = false; + } + ResumeGui(); +} diff --git a/source/utils/rockout.h b/source/utils/rockout.h new file mode 100644 index 0000000..3e99551 --- /dev/null +++ b/source/utils/rockout.h @@ -0,0 +1,6 @@ +#ifndef ROCKOUT_H_ +#define ROCKOUT_H_ + +void rockout(struct discHdr *header); + +#endif diff --git a/source/utils/timer.c b/source/utils/timer.c new file mode 100644 index 0000000..57dfb33 --- /dev/null +++ b/source/utils/timer.c @@ -0,0 +1,119 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include "timer.h" + +bool TimePassed(int limit) +{ + static time_t starttime = 0; + time_t timer = time(NULL); + + if (starttime == 0) + starttime = timer; + + if(difftime(timer, starttime) >= limit) + { + starttime = 0; + return true; + } + + return false; +} + +#define PERIOD_4 (4 * 365 + 1) +#define PERIOD_100 (PERIOD_4 * 25 - 1) +#define PERIOD_400 (PERIOD_100 * 4 + 1) +void ConvertNTFSDate(u64 ulNTFSDate, TimeStruct * ptm) +{ + unsigned year, mon, day, hour, min, sec; + u64 v64 = ulNTFSDate; + u8 ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + unsigned temp; + u32 v; + v64 /= 10000000; + sec = (unsigned)(v64 % 60); + v64 /= 60; + min = (unsigned)(v64 % 60); + v64 /= 60; + hour = (unsigned)(v64 % 24)+1; + v64 /= 24; + + v = (u32)v64; + + year = (unsigned)(1601 + v / PERIOD_400 * 400); + v %= PERIOD_400; + + temp = (unsigned)(v / PERIOD_100); + if (temp == 4) + temp = 3; + year += temp * 100; + v -= temp * PERIOD_100; + + temp = v / PERIOD_4; + if (temp == 25) + temp = 24; + year += temp * 4; + v -= temp * PERIOD_4; + + temp = v / 365; + if (temp == 4) + temp = 3; + year += temp; + v -= temp * 365; + + if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) + ms[1] = 29; + for (mon = 1; mon <= 12; mon++) + { + unsigned s = ms[mon - 1]; + if (v < s) + break; + v -= s; + } + day = (unsigned)v + 1; + + ptm->tm_mday = (u32)day; + ptm->tm_mon = (u32)mon; + ptm->tm_year = (u32)year; + + ptm->tm_hour = (u32)hour; + ptm->tm_min = (u32)min; + ptm->tm_sec = (u32)sec; +} + +void ConvertDosDate(u64 ulDosDate, TimeStruct * ptm) +{ + u32 uDate; + uDate = (u32)(ulDosDate>>16); + ptm->tm_mday = (u32)(uDate&0x1f) ; + ptm->tm_mon = (u32)((((uDate)&0x1E0)/0x20)) ; + ptm->tm_year = (u32)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (u32) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (u32) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (u32) (2*(ulDosDate&0x1f)) ; +} diff --git a/source/utils/timer.h b/source/utils/timer.h new file mode 100644 index 0000000..f250f63 --- /dev/null +++ b/source/utils/timer.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef __TIMER_H +#define __TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct _TimeStruct +{ + u32 tm_sec; /* seconds after the minute - [0,59] */ + u32 tm_min; /* minutes after the hour - [0,59] */ + u32 tm_hour; /* hours since midnight - [0,23] */ + u32 tm_mday; /* day of the month - [1,31] */ + u32 tm_mon; /* months since January - [0,11] */ + u32 tm_year; /* years - [1980..2044] */ +} TimeStruct; + +bool TimePassed(int limit); +void ConvertDosDate(u64 ulDosDate, TimeStruct * ptm); +void ConvertNTFSDate(u64 ulNTFSDate, TimeStruct * ptm); + + +#ifdef __cplusplus +} + +class Timer +{ + public: + Timer() { starttick = gettime(); } + ~Timer() { } + float elapsed() { return (float) (gettime()-starttick)/(1000.0f*TB_TIMER_CLOCK); } + u32 elapsed_millisecs() { return (u32) ((gettime()-starttick)/TB_TIMER_CLOCK); } + void reset() { starttick = gettime(); } + protected: + u64 starttick; +}; + +#endif //__cplusplus + +#endif //__TIMER_H diff --git a/source/utils/tools.h b/source/utils/tools.h new file mode 100644 index 0000000..b633b43 --- /dev/null +++ b/source/utils/tools.h @@ -0,0 +1,22 @@ +#ifndef TOOLS_H_ +#define TOOLS_H_ + + /* Constants */ +#define KB_SIZE 1024.0f +#define MB_SIZE 1048576.0f +#define GB_SIZE 1073741824.0f + +#define round_up(x,n) (-(-(x) & -(n))) + +#define ABS(x) ( (x) >= (0) ? (x) : (-(x)) ) +#define LIMIT(x, min, max) \ + ({ \ + typeof( x ) _x = x; \ + typeof( min ) _min = min; \ + typeof( max ) _max = max; \ + ( ( ( _x ) < ( _min ) ) ? ( _min ) : ( ( _x ) > ( _max ) ) ? ( _max) : ( _x ) ); \ + }) +#define ALIGN(x) (((x) + 3) & ~3) +#define ALIGN32(x) (((x) + 31) & ~31) + +#endif diff --git a/source/utils/uncompress.c b/source/utils/uncompress.c new file mode 100644 index 0000000..154a08c --- /dev/null +++ b/source/utils/uncompress.c @@ -0,0 +1,144 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include + +#include "uncompress.h" +#include "lz77.h" + +u8 * uncompressLZ77(const u8 *inBuf, u32 inLength, u32 * size) +{ + if(!inBuf) + return NULL; + + u8 *buffer = NULL; + if (*((const u32 *)inBuf) != 0x4C5A3737 /*"LZ77"*/) + return NULL; + + decompressLZ77content( (u8*)inBuf + 4, inLength - 4, &buffer, size); + + return buffer; +} + +//Thanks to _demo_ for this function +//src points to the yaz0 source data (to the "real" source data, not at the header!) +//dst points to a buffer uncompressedSize bytes large (you get uncompressedSize from +//the second 4 bytes in the Yaz0 header). +void uncompressYaz0(const u8* srcBuf, u8* dst, int uncompressedSize) +{ + if(!srcBuf || !dst) + return; + + const u8 * src = srcBuf; + + if(*((u32*)src) == 'Yaz0') + { + src += sizeof(Yaz0_Header); + } + + int srcPlace = 0, dstPlace = 0; //current read/write positions + + u32 validBitCount = 0; //number of valid bits left in "code" byte + u8 currCodeByte = 0; + + while(dstPlace < uncompressedSize) + { + //read new "code" byte if the current one is used up + if(validBitCount == 0) + { + currCodeByte = src[srcPlace]; + ++srcPlace; + validBitCount = 8; + } + + if((currCodeByte & 0x80) != 0) + { + //straight copy + dst[dstPlace] = src[srcPlace]; + dstPlace++; + srcPlace++; + } + else + { + //RLE part + u8 byte1 = src[srcPlace]; + u8 byte2 = src[srcPlace + 1]; + srcPlace += 2; + + u32 dist = ((byte1 & 0xF) << 8) | byte2; + u32 copySource = dstPlace - (dist + 1); + + u32 numBytes = byte1 >> 4; + if(numBytes == 0) + { + numBytes = src[srcPlace] + 0x12; + srcPlace++; + } + else + numBytes += 2; + + //copy run + u32 i = 0; + for(i = 0; i < numBytes; ++i) + { + dst[dstPlace] = dst[copySource]; + copySource++; + dstPlace++; + } + } + + //use next bit from "code" byte + currCodeByte <<= 1; + validBitCount-=1; + } +} + + +u32 CheckIMD5Type(const u8 * buffer, int length) +{ + if(*((u32 *) buffer) != 'IMD5') + { + return *((u32 *) buffer); + } + + const u8 * file = buffer+32; + + if(*((u32 *) file) != 'LZ77') + { + return *((u32 *) file); + } + + u32 uncSize = 0; + u8 * uncompressed_data = uncompressLZ77(file, length-32, &uncSize); + if(!uncompressed_data) + return 0; + + u32 * magic = (u32 *) uncompressed_data; + u32 Type = magic[0]; + free(uncompressed_data); + + return Type; +} diff --git a/source/utils/uncompress.h b/source/utils/uncompress.h new file mode 100644 index 0000000..a65b4b5 --- /dev/null +++ b/source/utils/uncompress.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef __UNCOMPRESS_H +#define __UNCOMPRESS_H + +#include + +#define le16(i) ((((u16) ((i) & 0xFF)) << 8) | ((u16) (((i) & 0xFF00) >> 8))) +#define le32(i) ((((u32)le16((i) & 0xFFFF)) << 16) | ((u32)le16(((i) & 0xFFFF0000) >> 16))) +#define le64(i) ((((u64)le32((i) & 0xFFFFFFFFLL)) << 32) | ((u64)le32(((i) & 0xFFFFFFFF00000000LL) >> 32))) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + u32 magic; //Yaz0 + u32 decompressed_size; + u8 zeros[8]; +} Yaz0_Header; + +u8 * uncompressLZ77(const u8 *inBuf, u32 inLength, u32 * uncSize); +void uncompressYaz0(const u8* srcBuf, u8* dst, int uncompressedSize); +u32 CheckIMD5Type(const u8 * buffer, int length); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/utils/wifi_gecko.c b/source/utils/wifi_gecko.c new file mode 100644 index 0000000..d3c978d --- /dev/null +++ b/source/utils/wifi_gecko.c @@ -0,0 +1,113 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#include +#include +#include +#include +#include +#include + +#define DESTINATION_IP "192.168.1.255" +#define DESTINATION_PORT 4405 + +static int connection = -1; + +void WifiGecko_Close() +{ + if(connection >= 0) + net_close(connection); + + connection = -1; +} + +int WifiGecko_Connect() +{ + if(connection >= 0) + return connection; + + connection = net_socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (connection < 0) + return connection; + + struct sockaddr_in connect_addr; + memset(&connect_addr, 0, sizeof(connect_addr)); + connect_addr.sin_family = AF_INET; + connect_addr.sin_port = htons(DESTINATION_PORT); + inet_aton(DESTINATION_IP, &connect_addr.sin_addr); + + if(net_connect(connection, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) < 0) + { + WifiGecko_Close(); + return -1; + } + + return connection; +} + +int WifiGecko_Send(const char * data, int datasize) +{ + if(WifiGecko_Connect() < 0) + return connection; + + int ret = 0, done = 0, blocksize = 1024; + + while (done < datasize) + { + if(blocksize > datasize-done) + blocksize = datasize-done; + + ret = net_send(connection, data+done, blocksize, 0); + if (ret < 0) + { + WifiGecko_Close(); + return ret; + } + else if(ret == 0) + { + break; + } + + done += ret; + usleep (1000); + } + + return ret; +} + +void wifi_printf(const char * format, ...) +{ + char * tmp = NULL; + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + WifiGecko_Send(tmp, strlen(tmp)); + } + va_end(va); + + if(tmp) + free(tmp); +} diff --git a/source/utils/wifi_gecko.h b/source/utils/wifi_gecko.h new file mode 100644 index 0000000..ef97e47 --- /dev/null +++ b/source/utils/wifi_gecko.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + * for WiiXplorer 2010 + ***************************************************************************/ +#ifndef WIFI_GECKO_H_ +#define WIFI_GECKO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int WifiGecko_Connect(); +void WifiGecko_Close(); +int WifiGecko_Send(const char * data, int datasize); +void wifi_printf(const char * format, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/video.cpp b/source/video.cpp new file mode 100644 index 0000000..1565007 --- /dev/null +++ b/source/video.cpp @@ -0,0 +1,520 @@ +/**************************************************************************** + * libwiigui Template + * Tantric 2009 + * + * video.cpp + * Video routines + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GUI/gui.h" +#include "ImageOperations/TextureConverter.h" +#include "ImageOperations/ImageWrite.h" +#include "settings/CSettings.h" +#include "input.h" +#include "sys.h" +#include "gecko.h" + +#define GP_FIFO_SIZE (256 * 1024 * 3) +static u32 *xfb[2] = { NULL, NULL }; // Double buffered +static int whichfb = 0; // Switch +static unsigned char *gp_fifo = NULL; +Mtx44 FSProjection2D; +Mtx FSModelView2D; +GXRModeObj *vmode; // Menu video mode +int screenheight = 480; +int screenwidth = 640; +u32 frameCount = 0; + +/**************************************************************************** + * ResetVideo_Menu + * + * Reset the video/rendering mode for the menu + ****************************************************************************/ +static void ResetVideo_Menu() +{ + f32 yscale; + u32 xfbHeight; + + VIDEO_Configure(vmode); + VIDEO_Flush(); + VIDEO_WaitVSync(); + if (vmode->viTVMode & VI_NON_INTERLACE) + VIDEO_WaitVSync(); + else while (VIDEO_GetNextField()) + VIDEO_WaitVSync(); + + // clears the bg to color and clears the z buffer + GXColor background = { 0, 0, 0, 255 }; + GX_SetCopyClear(background, 0x00ffffff); + + yscale = GX_GetYScaleFactor(vmode->efbHeight, vmode->xfbHeight); + xfbHeight = GX_SetDispCopyYScale(yscale); + GX_SetScissor(0, 0, vmode->fbWidth, vmode->efbHeight); + GX_SetDispCopySrc(0, 0, vmode->fbWidth, vmode->efbHeight); + GX_SetDispCopyDst(vmode->fbWidth, xfbHeight); + GX_SetCopyFilter(vmode->aa, vmode->sample_pattern, GX_TRUE, vmode->vfilter); + GX_SetFieldMode(vmode->field_rendering, ((vmode->viHeight == 2 * vmode->xfbHeight) ? GX_ENABLE : GX_DISABLE)); + + if (vmode->aa) + GX_SetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_LINEAR); + else + GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR); + + // setup the vertex descriptor + // tells the flipper to expect direct data + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_InvalidateTexAll(); + + GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + + for(u32 i = 0; i < 8; i++) + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0+i, GX_TEX_ST, GX_F32, 0); + + GX_SetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE); + + GX_SetNumChans(1); + GX_SetNumTexGens(1); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + + guMtxIdentity(FSModelView2D); + guMtxTransApply(FSModelView2D, FSModelView2D, 0.0F, 0.0F, -9900.0F); + + guOrtho(FSProjection2D, 0, screenheight-1, 0, screenwidth-1, 0, 10000); + + GX_SetViewport(0.0f, 0.0f, vmode->fbWidth, vmode->efbHeight, 0.0f, 1.0f); + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); + GX_SetColorUpdate(GX_TRUE); + GX_SetAlphaUpdate(GX_TRUE); +} + +/**************************************************************************** + * InitVideo + * + * This function MUST be called at startup. + * - also sets up menu video mode + ***************************************************************************/ + +void InitVideo() +{ + VIDEO_Init(); + + // If WiiU - Force 16:9 aspect ratio based on WiiU settings + if(isWiiU() && Settings.widescreen) + { + write32(0xd8006a0, 0x30000004), mask32(0xd8006a8, 0, 2); + } + + vmode = VIDEO_GetPreferredMode(NULL); // get default video mode + + vmode->viWidth = Settings.widescreen ? 708 : 694; + + if (Settings.PAL50) + { + vmode->viXOrigin = (VI_MAX_WIDTH_PAL - vmode->viWidth) / 2; + } + else + { + vmode->viXOrigin = (VI_MAX_WIDTH_NTSC - vmode->viWidth) / 2; + } + + VIDEO_Configure(vmode); + + screenheight = 480; + screenwidth = vmode->fbWidth; + + // Allocate the video buffers + xfb[0] = (u32 *) MEM_K0_TO_K1 ( SYS_AllocateFramebuffer ( vmode ) ); + xfb[1] = (u32 *) MEM_K0_TO_K1 ( SYS_AllocateFramebuffer ( vmode ) ); + + // Clear framebuffers etc. + VIDEO_ClearFrameBuffer(vmode, xfb[0], COLOR_BLACK); + VIDEO_ClearFrameBuffer(vmode, xfb[1], COLOR_BLACK); + VIDEO_SetNextFramebuffer(xfb[0]); + + VIDEO_Flush(); + VIDEO_WaitVSync(); + if (vmode->viTVMode & VI_NON_INTERLACE) + VIDEO_WaitVSync(); + + // Initialize GX + GXColor background = { 0, 0, 0, 0xff }; + gp_fifo = (u8 *) memalign(32, GP_FIFO_SIZE); + memset (gp_fifo, 0, GP_FIFO_SIZE); + GX_Init (gp_fifo, GP_FIFO_SIZE); + GX_SetCopyClear (background, 0x00ffffff); + GX_SetDispCopyGamma (GX_GM_1_0); + GX_SetCullMode (GX_CULL_NONE); + + ResetVideo_Menu(); + + VIDEO_SetBlack(FALSE); + // Finally, the video is up and ready for use :) +} +/**************************************************************************** + * AdjustOverscan + ***************************************************************************/ +void AdjustOverscan(int x, int y) +{ + guOrtho(FSProjection2D, y, screenheight-1 - y, x, screenwidth-1 - x, 0, 10000); +} + +/**************************************************************************** + * StopGX + * + * Stops GX (when exiting) + ***************************************************************************/ +void StopGX() +{ + GX_AbortFrame(); + GX_Flush(); + + VIDEO_SetBlack(TRUE); + VIDEO_Flush(); + VIDEO_WaitVSync(); + if (vmode->viTVMode & VI_NON_INTERLACE) + VIDEO_WaitVSync(); +} + +/**************************************************************************** + * Menu_Render + * + * Renders everything current sent to GX, and flushes video + ***************************************************************************/ +void Menu_Render() +{ + whichfb ^= 1; // flip framebuffer + GX_CopyDisp(xfb[whichfb], GX_TRUE); + GX_DrawDone(); + VIDEO_SetNextFramebuffer(xfb[whichfb]); + VIDEO_Flush(); + VIDEO_WaitVSync(); + frameCount++; +} + +/**************************************************************************** + * Menu_DrawImg + * + * Draws the specified image on screen using GX + ***************************************************************************/ +void Menu_DrawImg(f32 xpos, f32 ypos, f32 zpos, f32 width, f32 height, u8 data[], f32 degrees, f32 scaleX, f32 scaleY, + u8 alpha, int XX1, int YY1, int XX2, int YY2, int XX3, int YY3, int XX4, int YY4) +{ + if (data == NULL) return; + + GX_LoadProjectionMtx(FSProjection2D, GX_ORTHOGRAPHIC); + + GXTexObj texObj; + + GX_InitTexObj(&texObj, data, width, height, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); + GX_LoadTexObj(&texObj, GX_TEXMAP0); + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_InvalidateTexAll(); + + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + Mtx m, m1, m2, mv; + width *= 0.5f; + height *= 0.5f; + guMtxIdentity(m1); + guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0f); + guVector axis = (guVector) {0 , 0, 1}; + guMtxRotAxisDeg (m2, &axis, degrees); + guMtxConcat(m1, m2, m); + + guMtxTransApply(m, m, xpos + width + 0.5f, ypos + height + 0.5f, zpos); + guMtxConcat(FSModelView2D, m, mv); + GX_LoadPosMtxImm(mv, GX_PNMTX0); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position3f32(-width + XX1, -height + YY1, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(0, 0); + + GX_Position3f32(width + XX2, -height + YY2, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(1, 0); + + GX_Position3f32(width + XX3, height + YY3, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(1, 1); + + GX_Position3f32(-width + XX4, height + YY4, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(0, 1); + + GX_End(); +} + +/**************************************************************************** + * Menu_DrawRectangle + * + * Draws a rectangle at the specified coordinates using GX + ***************************************************************************/ +void Menu_DrawRectangle(f32 x, f32 y, f32 width, f32 height, GXColor color, u8 filled) +{ + GX_LoadProjectionMtx(FSProjection2D, GX_ORTHOGRAPHIC); + GX_LoadPosMtxImm(FSModelView2D, GX_PNMTX0); + + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); + + u8 fmt; + long n; + int i; + f32 x2 = x + width; + f32 y2 = y + height; + guVector v[] = { { x, y, 0.0f }, { x2, y, 0.0f }, { x2, y2, 0.0f }, { x, y2, 0.0f }, { x, y, 0.0f } }; + + if (!filled) + { + fmt = GX_LINESTRIP; + n = 5; + } + else + { + fmt = GX_TRIANGLEFAN; + n = 4; + } + + GX_Begin(fmt, GX_VTXFMT0, n); + for (i = 0; i < n; i++) + { + GX_Position3f32(v[i].x, v[i].y, v[i].z); + GX_Color4u8(color.r, color.g, color.b, color.a); + } + GX_End(); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); +} + +void Menu_DrawDiskCover(f32 xpos, f32 ypos, f32 zpos, u16 width, u16 height, u16 distance, u8 data[], f32 deg_alpha, + f32 deg_beta, f32 scaleX, f32 scaleY, u8 alpha, bool shadow) +{ + if (data == NULL) return; + + GX_LoadProjectionMtx(FSProjection2D, GX_ORTHOGRAPHIC); + + GXTexObj texObj; + + GX_InitTexObj(&texObj, data, width, height, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); + GX_LoadTexObj(&texObj, GX_TEXMAP0); + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_InvalidateTexAll(); + + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + f32 cos_beta = cos(DegToRad( deg_beta )); + f32 s_offset_y = (zpos + (cos_beta * distance)) * tan(DegToRad( 5 )); + f32 s_offset_x = (cos_beta < 0 ? -cos_beta : cos_beta) * s_offset_y; + f32 s_offset_z = (s_offset_y < 0 ? 0 : s_offset_y) * 2; + + Mtx m, m1, m2, m3, m4, mv; + width *= .5; + height *= .5; + guMtxIdentity(m4); + guMtxTransApply(m4, m4, 0, 0, distance); + + guMtxIdentity(m1); + guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0); + guVector axis2 = (guVector) {0 , 1, 0}; + guMtxRotAxisDeg ( m2, &axis2, deg_beta ); + guVector axis = (guVector) {0 , 0, 1}; + guMtxRotAxisDeg ( m3, &axis, deg_alpha ); + guMtxConcat(m3, m4, m3); // move distance then rotate z-axis + guMtxConcat(m2, m3, m2); // rotate y-axis + guMtxConcat(m1, m2, m); // scale + + if (shadow) + guMtxTransApply(m, m, xpos + width + 0.5 + s_offset_x, ypos + height + 0.5 + s_offset_y, zpos - s_offset_z); + else + guMtxTransApply(m, m, xpos + width + 0.5, ypos + height + 0.5, zpos); + + guMtxConcat(FSModelView2D, m, mv); + GX_LoadPosMtxImm(mv, GX_PNMTX0); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + if (shadow) + { + GX_Position3f32(-width, -height, 0); + GX_Color4u8(0, 0, 0, alpha); + GX_TexCoord2f32(0, 0); + + GX_Position3f32(width, -height, 0); + GX_Color4u8(0, 0, 0, alpha); + GX_TexCoord2f32(1, 0); + + GX_Position3f32(width, height, 0); + GX_Color4u8(0, 0, 0, alpha); + GX_TexCoord2f32(1, 1); + + GX_Position3f32(-width, height, 0); + GX_Color4u8(0, 0, 0, alpha); + GX_TexCoord2f32(0, 1); + } + else + { + GX_Position3f32(-width, -height, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(0, 0); + + GX_Position3f32(width, -height, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(1, 0); + + GX_Position3f32(width, height, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(1, 1); + + GX_Position3f32(-width, height, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(0, 1); + } + + GX_End(); +} + +void Menu_DrawTPLImg(f32 xpos, f32 ypos, f32 zpos, f32 width, f32 height, GXTexObj *texObj, f32 degrees, f32 scaleX, + f32 scaleY, u8 alpha, int XX1, int YY1, int XX2, int YY2, int XX3, int YY3, int XX4, int YY4) +{ + GX_LoadProjectionMtx(FSProjection2D, GX_ORTHOGRAPHIC); + + GX_LoadTexObj(texObj, GX_TEXMAP0); + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_InvalidateTexAll(); + + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + Mtx m, m1, m2, mv; + width *= .5; + height *= .5; + guMtxIdentity(m1); + guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0); + guVector axis = (guVector) {0 , 0, 1}; + guMtxRotAxisDeg ( m2, &axis, degrees ); + guMtxConcat(m1, m2, m); + + guMtxTransApply(m, m, xpos + width + 0.5, ypos + height + 0.5, zpos); + guMtxConcat(FSModelView2D, m, mv); + GX_LoadPosMtxImm(mv, GX_PNMTX0); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position3f32(-width + XX1, -height + YY1, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(0, 0); + + GX_Position3f32(width + XX2, -height + YY2, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(1, 0); + + GX_Position3f32(width + XX3, height + YY3, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(1, 1); + + GX_Position3f32(-width + XX4, height + YY4, 0); + GX_Color4u8(0xFF, 0xFF, 0xFF, alpha); + GX_TexCoord2f32(0, 1); + + GX_End(); +} +/**************************************************************************** + * TakeScreenshot + * + * Copies the current screen into a file "path" + ***************************************************************************/ +s32 TakeScreenshot(const char *path) +{ + gprintf("\nTakeScreenshot(%s)", path); + int size = (2 * vmode->fbWidth * vmode->xfbHeight + 31) & ~31; + + u8 * buffer = (u8 *) memalign(32, size); + if(!buffer) + return -1; + + memcpy(buffer, xfb[whichfb], size); + + gdImagePtr gdImg = 0; + YCbYCrToGD(buffer, vmode->fbWidth, vmode->xfbHeight, &gdImg); + + free(buffer); + + if(gdImg == 0) + return -1; + + if(Settings.widescreen) + { + gdImagePtr dst = gdImageCreateTrueColor(768, screenheight); + if(dst == 0) + { + gdImageDestroy(gdImg); + return -1; + } + gdImageCopyResampled(dst, gdImg, 0, 0, 0, 0, 768, screenheight, screenwidth, screenheight); + gdImageDestroy(gdImg); + gdImg = dst; + } + + WriteGDImage(path,gdImg, IMAGE_PNG, 0); + gdImageDestroy(gdImg); + + return 1; +} + +/**************************************************************************** + * Restore GX to 2D mode drawing + ***************************************************************************/ +void ReSetup_GX(void) +{ + // channel control + GX_SetNumChans(1); + GX_SetChanCtrl(GX_COLOR0A0,GX_DISABLE,GX_SRC_REG,GX_SRC_VTX,GX_LIGHTNULL,GX_DF_NONE,GX_AF_NONE); + + // texture gen. + GX_SetNumTexGens(1); + GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + // texture environment + GX_SetNumTevStages(1); + GX_SetNumIndStages(0); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GX_SetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0); + GX_SetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_1_4); + GX_SetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_1); + GX_SetTevDirect(GX_TEVSTAGE0); + // swap table + GX_SetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA); + // alpha compare and blend mode + GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET); +} diff --git a/source/video.h b/source/video.h new file mode 100644 index 0000000..918ec4b --- /dev/null +++ b/source/video.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * libwiigui Template + * Tantric 2009 + * + * video.h + * Video routines + ***************************************************************************/ + +#ifndef _VIDEO_H_ +#define _VIDEO_H_ + +#include + +void InitVideo(); +void StopGX(); +void Menu_Render(); +void Menu_DrawImg(f32 xpos, f32 ypos, f32 zpos, f32 width, f32 height, u8 data[], f32 degrees, f32 scaleX, f32 scaleY, + u8 alphaF, int XX1, int YY1, int XX2, int YY2, int XX3, int YY3, int XX4, int YY4); +void Menu_DrawTPLImg(f32 xpos, f32 ypos, f32 zpos, f32 width, f32 height, GXTexObj *texObj, f32 degrees, f32 scaleX, + f32 scaleY, u8 alpha, int XX1, int YY1, int XX2, int YY2, int XX3, int YY3, int XX4, int YY4); +void Menu_DrawRectangle(f32 x, f32 y, f32 width, f32 height, GXColor color, u8 filled); +s32 TakeScreenshot(const char *path); +void VIDEO_SetWidescreen(bool widescreen); +void AdjustOverscan(int x, int y); +void ReSetup_GX(void); + +extern GXRModeObj *vmode; +extern Mtx44 FSProjection2D; +extern Mtx FSModelView2D; +extern int screenheight; +extern int screenwidth; +extern u32 frameCount; + +#endif diff --git a/source/wad/nandtitle.cpp b/source/wad/nandtitle.cpp new file mode 100644 index 0000000..491bf7b --- /dev/null +++ b/source/wad/nandtitle.cpp @@ -0,0 +1,701 @@ +#include +#include +#include "nandtitle.h" +#include "FileOperations/fileops.h" +#include "prompts/ProgressWindow.h" +#include "language/gettext.h" +#include "usbloader/playlog.h" +#include "utils/tools.h" +#include "gecko.h" + +NandTitle NandTitles; + +static u8 tmd_buf[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN( 32 ); + +NandTitle::NandTitle() +{ + currentIndex = 0; + currentType = 0; +} + +NandTitle::~NandTitle() +{ + titleIds.clear(); + NameList.clear(); +} + +s32 NandTitle::Get() +{ + s32 ret; + u64 *list = NULL; + u32 numTitles = 0; + + titleIds.clear(); + NameList.clear(); + + ret = ES_GetNumTitles(&numTitles); + if (ret < 0) return WII_EINTERNAL; + + list = (u64*) memalign(32, numTitles * sizeof(u64)); + if (!list) + { + return -1; + } + + ret = ES_GetTitles(list, numTitles); + if (ret < 0) + { + free(list); + return WII_EINTERNAL; + } + + for (u32 i = 0; i < numTitles; i++) + { + titleIds.push_back(list[i]); + } + + free(list); + + int language = CONF_GetLanguage(); + ISFS_Initialize(); + + wchar_t name[IMET_MAX_NAME_LEN]; + + for (u32 i = 0; i < titleIds.size(); i++) + { + bool r = GetName(titleIds.at(i), language, name); + if (r) + { + wString wsname(name); + NameList[titleIds.at(i)] = wsname.toUTF8(); + } + } + + ISFS_Deinitialize(); + return 1; +} + +tmd* NandTitle::GetTMD(u64 tid) +{ + signed_blob *s_tmd = (signed_blob *) tmd_buf; + u32 tmd_size; + + if (ES_GetStoredTMDSize(tid, &tmd_size) < 0) + { + return NULL; + } + + s32 ret = ES_GetStoredTMD(tid, s_tmd, tmd_size); + if (ret < 0) + { + return NULL; + } + + tmd *t = (tmd*) SIGNATURE_PAYLOAD(s_tmd); + + return t; +} + +bool NandTitle::GetName(u64 tid, int language, wchar_t* name) +{ + if (TITLE_UPPER( tid ) != 0x10001 && TITLE_UPPER( tid ) != 0x10002 && TITLE_UPPER( tid ) != 0x10004) return false; + //gprintf("GetName( %016llx ): ", tid ); + char app[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32); + IMET *imet = (IMET*) memalign(32, sizeof(IMET)); + + tmd* titleTmd = GetTMD(tid); + if (!titleTmd) + { + //gprintf("no TMD\n"); + free(imet); + return false; + } + + u16 i; + bool ok = false; + for (i = 0; i < titleTmd->num_contents; i++) + { + if (!titleTmd->contents[i].index) + { + ok = true; + break; + } + } + if (!ok) + { + free(imet); + return false; + } + + snprintf(app, sizeof(app), "/title/%08x/%08x/content/%08x.app", (unsigned int)TITLE_UPPER( tid ), (unsigned int)TITLE_LOWER( tid ), + (unsigned int)titleTmd->contents[i].cid); + //gprintf("%s\n", app ); + + if (language > CONF_LANG_KOREAN) language = CONF_LANG_ENGLISH; + + s32 fd = ISFS_Open(app, ISFS_OPEN_READ); + if (fd < 0) + { + //gprintf("fd: %d\n", fd ); + free(imet); + return false; + } + + if (ISFS_Seek(fd, IMET_OFFSET, SEEK_SET) != IMET_OFFSET) + { + ISFS_Close(fd); + free(imet); + return false; + } + + if (ISFS_Read(fd, imet, sizeof(IMET)) != sizeof(IMET)) + { + ISFS_Close(fd); + free(imet); + return false; + } + + ISFS_Close(fd); + + if (imet->sig != IMET_SIGNATURE) + { + free(imet); + return false; + } + + if (imet->name_japanese[language * IMET_MAX_NAME_LEN] == 0) + { + // channel name is not available in system language + if (imet->name_english[0] != 0) + { + language = CONF_LANG_ENGLISH; + } + else + { + // channel name is also not available on english, get ascii name + for (int i = 0; i < 4; i++) + { + name[i] = (TITLE_LOWER( tid ) >> (24 - i * 8)) & 0xFF; + } + name[4] = 0; + free(imet); + return true; + } + } + + // retrieve channel name in system language or on english + for (int i = 0; i < IMET_MAX_NAME_LEN; i++) + { + name[i] = imet->name_japanese[i + (language * IMET_MAX_NAME_LEN)]; + } + + free(imet); + + return true; +} + +bool NandTitle::Exists(u64 tid) +{ + char app[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32); + tmd* titleTmd = GetTMD(tid); + if (!titleTmd) return false; + + u16 i; + bool ok = false; + for (i = 0; i < titleTmd->num_contents; i++) + { + if (!titleTmd->contents[i].index) + { + ok = true; + break; + } + } + if (!ok) return false; + + snprintf(app, sizeof(app), "/title/%08x/%08x/content/%08x.app", (unsigned int)TITLE_UPPER( tid ), (unsigned int)TITLE_LOWER( tid ), + (unsigned int)titleTmd->contents[i].cid); + s32 fd = ISFS_Open(app, ISFS_OPEN_READ); + if (fd >= 0) ISFS_Close(fd); + + //gprintf(" fd: %d\n", fd ); + return fd >= 0 || fd == -102; //102 means it exists, but we dont have permission to open it + +} + +bool NandTitle::ExistsFromIndex(u32 i) +{ + if (i >= titleIds.size()) return false; + + return Exists(titleIds.at(i)); +} + +u64 NandTitle::At(u32 i) +{ + if (i >= titleIds.size()) return 0; + + return titleIds.at(i); +} + +int NandTitle::IndexOf(u64 tid) +{ + for (u32 i = 0; i < titleIds.size(); i++) + { + if (titleIds.at(i) == tid) return i; + } + + return WII_EINSTALL; +} + +const char* NandTitle::NameOf(u64 tid) +{ + map::iterator itr = NameList.find(tid); + if (itr != NameList.end()) return itr->second.c_str(); + + return NULL; +} + +const char* NandTitle::NameFromIndex(u32 i) +{ + if (i >= titleIds.size()) return NULL; + + map::iterator itr = NameList.find(titleIds.at(i)); + if (itr != NameList.end()) return itr->second.c_str(); + + return NULL; +} + +u16 NandTitle::VersionOf(u64 tid) +{ + for (u32 i = 0; i < titleIds.size(); i++) + { + if (titleIds.at(i) == tid) + { + tmd* Tmd = GetTMD(tid); + if (!Tmd) break; + + return Tmd->title_version; + } + } + return 0; + +} + +u16 NandTitle::VersionFromIndex(u32 i) +{ + if (i >= titleIds.size()) return 0; + + tmd* Tmd = GetTMD(titleIds.at(i)); + if (!Tmd) return 0; + + return Tmd->title_version; +} + +u32 NandTitle::CountType(u32 type) +{ + u32 ret = 0; + for (u32 i = 0; i < titleIds.size(); i++) + { + if (TITLE_UPPER( titleIds.at( i ) ) == type) + { + ret++; + } + } + return ret; +} + +u32 NandTitle::SetType(u32 upper) +{ + currentType = upper; + currentIndex = 0; + + return CountType(upper); +} + +u64 NandTitle::Next() +{ + u64 ret = 0; + //gprintf("Next( %08x, %u )\n", currentType, currentIndex ); + u32 i; + for (i = currentIndex; i < titleIds.size(); i++) + { + if (currentType) + { + if (currentType == TITLE_UPPER( titleIds.at( i ) )) + { + ret = titleIds.at(i); + break; + } + } + else + { + ret = titleIds.at(i); + break; + } + } + currentIndex = i + 1; + + return ret; +} + +void NandTitle::ResetCounter() +{ + currentIndex = 0; +} + +void NandTitle::AsciiTID(u64 tid, char* out) +{ + //gprintf("AsciiTID( %016llx ): "); + out[0] = ascii(TITLE_3( tid )); + out[1] = ascii(TITLE_2( tid )); + out[2] = ascii(TITLE_1( tid )); + out[3] = ascii((u8) (tid)); + out[4] = 0; + //gprintf("%s\n", out ); +} + +void NandTitle::AsciiFromIndex(u32 i, char* out) +{ + if (i >= titleIds.size()) + { + out[0] = 0; + return; + } + + AsciiTID(titleIds.at(i), out); +} + +s32 NandTitle::GetTicketViews(u64 tid, tikview **outbuf, u32 *outlen) +{ + tikview *views = NULL; + + u32 nb_views; + s32 ret; + + /* Get number of ticket views */ + ret = ES_GetNumTicketViews(tid, &nb_views); + if (ret < 0) return ret; + + /* Allocate memory */ + views = (tikview *) memalign(32, sizeof(tikview) * nb_views); + if (!views) return -1; + + /* Get ticket views */ + ret = ES_GetTicketViews(tid, views, nb_views); + if (ret < 0) goto err; + + /* Set values */ + *outbuf = views; + *outlen = nb_views; + + return 0; + + err: + /* Free memory */ + if (views) free(views); + + return ret; +} + +u64 NandTitle::FindU64(const char *s) +{ + u64 tid = strtoull(s, NULL, 16); + + for (u32 i = 0; i < titleIds.size(); i++) + { + if(titleIds[i] == tid) + return titleIds[i]; + } + + return 0; +} + +u64 NandTitle::FindU32(const char *s) +{ + u32 tid = (u32) strtoull(s, NULL, 16); + if(!tid) + return 0; + + for (u32 i = 0; i < titleIds.size(); i++) + { + if (TITLE_LOWER(titleIds[i]) == tid) + return titleIds[i]; + } + return 0; +} + +int NandTitle::LoadFileFromNand(const char *filepath, u8 **outbuffer, u32 *outfilesize) +{ + if(!filepath) + return -1; + + fstats *stats = (fstats *) memalign(32, ALIGN32(sizeof(fstats))); + if(!stats) + return IPC_ENOMEM; + + int fd = ISFS_Open(filepath, ISFS_OPEN_READ); + if(fd < 0) + { + free(stats); + return fd; + } + + int ret = ISFS_GetFileStats(fd, stats); + if (ret < 0) + { + free(stats); + ISFS_Close(fd); + return ret; + } + + u32 filesize = stats->file_length; + + free(stats); + + u8 *buffer = (u8 *) memalign(32, ALIGN32(filesize)); + if(!buffer) + { + ISFS_Close(fd); + return IPC_ENOMEM; + } + + ret = ISFS_Read(fd, buffer, filesize); + + ISFS_Close(fd); + + if (ret < 0) + { + free(buffer); + return ret; + } + + *outbuffer = buffer; + *outfilesize = filesize; + + return 0; +} + +typedef struct _ReplaceStruct +{ + const char * replace; + char orig; +} ReplaceStruct; + +//! More replacements can be added if needed +static const ReplaceStruct Replacements[] = +{ + { ">", '>' }, + { "<", '<' }, + { "&st;", '*' }, + { "&cl;", ':' }, + { "&qt;", '\"' }, + { "&qm;", '?' }, + { "&vb;", '|' }, + { NULL, '\0' } +}; + +static void ConvertInvalidCharacters(std::string &filepath) +{ + size_t startPos; + size_t pos; + + for(int i = 0; Replacements[i].replace != 0; ++i) + { + //! Skip the first ':' because it is the device delimiter + if(Replacements[i].orig == ':') + startPos = filepath.find(Replacements[i].orig)+1; + else + startPos = 0; + + while((pos = filepath.find(Replacements[i].orig, startPos)) != std::string::npos) + { + filepath.erase(pos, 1); + filepath.insert(pos, Replacements[i].replace); + } + } +} + +int NandTitle::ExtractFile(const char *nandPath, const char *filepath) +{ + if(!nandPath || !filepath) + return -1; + + char *strDup = strdup(filepath); + if(!strDup) + return -666; + + char *ptr = strrchr(strDup, '/'); + if(!ptr) + { + free(strDup); + return -333; + } + else + { + *ptr = 0; + CreateSubfolder(strDup); + free(strDup); + } + + const char *filename = strrchr(filepath, '/')+1; + int done = 0; + int fd = -1; + int blocksize = 32*1024; + u8 *buffer = (u8 *) memalign(32, ALIGN32(blocksize)); + if(!buffer) + return -666; + + fstats *stats = (fstats *) memalign(32, ALIGN32(sizeof(fstats))); + if(!stats) + { + free(buffer); + return -666; + } + + do + { + fd = ISFS_Open(nandPath, ISFS_OPEN_READ); + if(fd < 0) + break; + + int ret = ISFS_GetFileStats(fd, stats); + if (ret < 0) + break; + + int filesize = stats->file_length; + + FILE *pFile = fopen(filepath, "wb"); + if(!pFile) + break; + + while(done < filesize) + { + if(ProgressCanceled()) + break; + + if(filesize-done < blocksize) + blocksize = filesize-done; + + ShowProgress(filename, done, filesize); + + ret = ISFS_Read(fd, buffer, blocksize); + if(ret < 0) + { + done = ret; + break; + } + + fwrite(buffer, 1, ret, pFile); + + done += ret; + } + + // Show last size information + ShowProgress(filename, done, filesize); + + fclose(pFile); + + } while(0); + + free(buffer); + free(stats); + + if(fd >= 0) + ISFS_Close(fd); + + if(ProgressCanceled()) + return PROGRESS_CANCELED; + + return done; + +} + +int NandTitle::InternalExtractDir(char *nandPath, std::string &filepath) +{ + int ret = -1; + + u32 list_len = 0; + ret = ISFS_ReadDir(nandPath, NULL, &list_len); + if(ret < 0) + return ret; + + char * name_list = (char *) memalign(32, ALIGN32(list_len * ISFS_MAXPATH)); + if(!name_list) + return -666; + + ret = ISFS_ReadDir(nandPath, name_list, &list_len); + if(ret < 0) + { + free(name_list); + return ret; + } + + char *entry = name_list; + + for(u32 i = 0; i < list_len; ++i) + { + if(ProgressCanceled()) + break; + + u32 dummy; + int posNandPath = strlen(nandPath); + int posFilePath = filepath.size(); + + if(posFilePath > 0 && filepath[posFilePath-1] != '/') + filepath += '/'; + filepath += entry; + + if(posNandPath > 0 && nandPath[posNandPath-1] != '/') + strcat(nandPath, "/"); + strcat(nandPath, entry); + + if(ISFS_ReadDir(nandPath, NULL, &dummy) < 0) + { + std::string filepathCpy = filepath; + ConvertInvalidCharacters(filepathCpy); + + int res = ExtractFile(nandPath, filepathCpy.c_str()); + if(res < 0) { + gprintf("ExtractFile: Error %i occured on file extract: %s\n", res, nandPath); + ret = -2; + } + } + else + { + int res = InternalExtractDir(nandPath, filepath); + if(res < 0) { + gprintf("InternalExtractDir: Error %i occured in: %s\n", res, nandPath); + ret = -3; + } + } + + nandPath[posNandPath] = 0; + filepath.erase(posFilePath); + entry += strlen(entry) + 1; + } + + free(name_list); + + if(ProgressCanceled()) + return PROGRESS_CANCELED; + + return ret; +} + +int NandTitle::ExtractDir(const char *nandPath, const char *filepath) +{ + if(!filepath || !nandPath) + return -1; + + std::string internFilePath = filepath; + char *internNandPath = (char *) memalign(32, ISFS_MAXPATH); + if(!internNandPath) + return -666; + + snprintf(internNandPath, ISFS_MAXPATH, nandPath); + + int ret = InternalExtractDir(internNandPath, internFilePath); + + free(internNandPath); + + return ret; +} diff --git a/source/wad/nandtitle.h b/source/wad/nandtitle.h new file mode 100644 index 0000000..0fca928 --- /dev/null +++ b/source/wad/nandtitle.h @@ -0,0 +1,117 @@ +#ifndef NANDTITLE_H +#define NANDTITLE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wstring.hpp" +using namespace std; + +#define TITLE_ID(x,y) (((u64)(x) << 32) | (y)) +#define TITLE_UPPER(x) ((u32)((x) >> 32)) +#define TITLE_LOWER(x) ((u32)(x)) + +#define TITLE_1(x) ((u8)((x) >> 8)) +#define TITLE_2(x) ((u8)((x) >> 16)) +#define TITLE_3(x) ((u8)((x) >> 24)) +#define TITLE_4(x) ((u8)((x) >> 32)) +#define TITLE_5(x) ((u8)((x) >> 40)) +#define TITLE_6(x) ((u8)((x) >> 48)) +#define TITLE_7(x) ((u8)((x) >> 56)) + +#define IMET_MAX_NAME_LEN 0x2a + +#define IMET_OFFSET 0x40 +#define IMET_SIGNATURE 0x494d4554 +#define DOWNLOADED_CHANNELS 0x00010001 +#define SYSTEM_CHANNELS 0x00010002 +#define RF_NEWS_CHANNEL 0x48414741 +#define RF_FORECAST_CHANNEL 0x48414641 + +typedef struct +{ + u8 zeroes1[0x40]; + u32 sig; // "IMET" + u32 unk1; + u32 unk2; + u32 filesizes[3]; + u32 unk3; + u16 name_japanese[IMET_MAX_NAME_LEN]; + u16 name_english[IMET_MAX_NAME_LEN]; + u16 name_german[IMET_MAX_NAME_LEN]; + u16 name_french[IMET_MAX_NAME_LEN]; + u16 name_spanish[IMET_MAX_NAME_LEN]; + u16 name_italian[IMET_MAX_NAME_LEN]; + u16 name_dutch[IMET_MAX_NAME_LEN]; + u16 name_simp_chinese[IMET_MAX_NAME_LEN]; + u16 name_trad_chinese[IMET_MAX_NAME_LEN]; + u16 name_korean[IMET_MAX_NAME_LEN]; + u8 zeroes2[0x24c]; + u8 md5[0x10]; +} IMET; + +class NandTitle +{ + public: + NandTitle(); + ~NandTitle(); + + s32 Get(); + u64 At(u32 i); + int IndexOf(u64 tid); + u32 Count() + { + return titleIds.size(); + } + + const char* NameOf(u64 tid); + const char* NameFromIndex(u32 i); + + u16 VersionOf(u64 tid); + u16 VersionFromIndex(u32 i); + + u32 CountType(u32 type); + + u32 SetType(u32 upper); + u64 Next(); + void ResetCounter(); + + void AsciiTID(u64 tid, char* out); + void AsciiFromIndex(u32 i, char* out); + + bool Exists(u64 tid); + bool ExistsFromIndex(u32 i); + + u64 FindU64(const char *s); + u64 FindU32(const char *s); + + s32 GetTicketViews(u64 tid, tikview **outbuf, u32 *outlen); + + u64 operator[](u32 i) { return At(i); } + + bool GetName(u64 tid, int language, wchar_t* name); + + tmd* GetTMD(u64 tid); + + static int LoadFileFromNand(const char *filepath, u8 **outbuffer, u32 *outfilesize); + static int ExtractFile(const char *nandPath, const char *filepath); + static int ExtractDir(const char *wiipath, const char *filepath); + private: + static int InternalExtractDir(char *nandPath, std::string &filepath); + + std::vector titleIds; + std::map NameList; + + u32 currentIndex; + u32 currentType; +}; + +extern NandTitle NandTitles; + +#endif // NANDTITLE_H diff --git a/source/wad/wad.cpp b/source/wad/wad.cpp new file mode 100644 index 0000000..f725a1c --- /dev/null +++ b/source/wad/wad.cpp @@ -0,0 +1,532 @@ +/**************************************************************************** + * Copyright (C) 2013 Cyan + * Copyright (C) 2011 Dimok + * + * 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 +#include "prompts/ProgressWindow.h" +#include "FileOperations/fileops.h" +#include "language/gettext.h" +#include "utils/ShowError.h" +#include "utils/tools.h" +#include "wad.h" + +extern "C" +{ + void aes_set_key(u8 *key); + void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len); + void _decrypt_title_key(u8 *tik, u8 *title_key); +} + +typedef struct map_entry +{ + char name[8]; + u8 hash[20]; +} __attribute__((packed)) map_entry_t; + +typedef struct uid_entry { + u64 title_id; + u32 uid; +} __attribute__((packed)) uid_entry_t; + +Wad::Wad(const char *wadpath, bool prompt) + : pFile(0), header(0), + p_tik(0), p_tmd(0), + content_map(0), content_map_size(0), + content_start(0) +{ + showPrompt = prompt; + Open(wadpath); +} + +Wad::~Wad() +{ + Close(); +} + +void Wad::Close(void) +{ + if(pFile) + fclose(pFile); + if(header) + free(header); + if(p_tik) + free(p_tik); + if(p_tmd) + free(p_tmd); + if(content_map) + free(content_map); + + pFile = 0; + header = 0; + p_tik = 0; + p_tmd = 0; + content_map = 0; + content_map_size = 0; +} + +bool Wad::Open(const char *wadpath) +{ + if(!wadpath) + return false; + + // Close if another file is opened already + Close(); + + // Open file + pFile = fopen(wadpath, "rb"); + if(!pFile) + { + if(showPrompt) + ShowError(tr("Can't open file: %s"), wadpath); + return false; + } + + // Read wad header + header = (wadHeader *) malloc(sizeof(wadHeader)); + if(!header) + { + if(showPrompt) + ShowError(tr("Not enough memory.")); + return false; + } + + if(fread(header, 1, sizeof(wadHeader), pFile) != sizeof(wadHeader)) + { + if(showPrompt) + ShowError(tr("Failed to read wad header.")); + return false; + } + + // Check for sanity + if(header->header_len != sizeof(wadHeader)) + { + if(showPrompt) + ShowError(tr("Invalid wad file.")); + return false; + } + + u32 offset = round_up( header->header_len, 64 ); + offset += round_up( header->certs_len, 64 ); + if (header->crl_len) + offset += round_up( header->crl_len, 64 ); + + // Read title ticket + p_tik = (u8 *) malloc(header->tik_len); + if(!p_tik) + { + if(showPrompt) + ShowError(tr("Not enough memory.")); + return false; + } + + fseek(pFile, offset, SEEK_SET); + + if(fread(p_tik, 1, header->tik_len, pFile) != header->tik_len) + { + if(showPrompt) + ShowError(tr("Failed to read ticket.")); + return false; + } + + offset += round_up( header->tik_len, 64 ); + + // Read title tmd + p_tmd = (u8 *) malloc(header->tmd_len); + if(!p_tik) + { + if(showPrompt) + ShowError(tr("Not enough memory.")); + return false; + } + + fseek(pFile, offset, SEEK_SET); + + if(fread(p_tmd, 1, header->tmd_len, pFile) != header->tmd_len) + { + if(showPrompt) + ShowError(tr("Failed to read tmd file.")); + return false; + } + + offset += round_up( header->tmd_len, 64 ); + + // Prepare offset for install + content_start = offset; + + return true; +} + +bool Wad::UnInstall(const char *installpath) +{ + if(!installpath || !pFile || !header || !p_tmd || !p_tik) + return false; + + char filepath[1024]; + tmd *tmd_data = (tmd *) SIGNATURE_PAYLOAD((signed_blob *) p_tmd); + + // trim ending slash + while(installpath[strlen(installpath)-1] == '/') + { + char *pathPtr = strrchr(installpath, '/'); + if(pathPtr) *pathPtr = 0; + } + + int result = true; + + // Remove ticket + snprintf(filepath, sizeof(filepath), "%s/ticket/%08x/%08x.tik", installpath, (unsigned int)(tmd_data->title_id >> 32), (unsigned int) tmd_data->title_id); + if(!RemoveFile(filepath)) + result = false; + + // Remove contents / data + snprintf(filepath, sizeof(filepath), "%s/title/%08x/%08x/", installpath, (unsigned int) (tmd_data->title_id >> 32), (unsigned int) tmd_data->title_id); + if(!RemoveDirectory(filepath)) + result = false; + + return result; +} + +bool Wad::Install(const char *installpath) +{ + if(!installpath || !pFile || !header || !p_tmd || !p_tik) + return false; + + char filepath[1024]; + u8 title_key[16]; + tmd *tmd_data = (tmd *) SIGNATURE_PAYLOAD((signed_blob *) p_tmd); + + // Create necessary folders if not existing + snprintf(filepath, sizeof(filepath), "%s/ticket/%08x/", installpath, (unsigned int) (tmd_data->title_id >> 32)); + CreateSubfolder(filepath); + + snprintf(filepath, sizeof(filepath), "%s/title/%08x/%08x/content/", installpath, (unsigned int) (tmd_data->title_id >> 32), (unsigned int) tmd_data->title_id); + CreateSubfolder(filepath); + + snprintf(filepath, sizeof(filepath), "%s/title/%08x/%08x/data/", installpath, (unsigned int) (tmd_data->title_id >> 32), (unsigned int) tmd_data->title_id); + CreateSubfolder(filepath); + + // Write ticket file + snprintf(filepath, sizeof(filepath), "%s/ticket/%08x/%08x.tik", installpath, (unsigned int) (tmd_data->title_id >> 32), (unsigned int) tmd_data->title_id); + if(!WriteFile(filepath, p_tik, header->tik_len)) + return false; + + // Write tmd file + snprintf(filepath, sizeof(filepath), "%s/title/%08x/%08x/content/title.tmd", installpath, (unsigned int) (tmd_data->title_id >> 32), (unsigned int) tmd_data->title_id); + if(!WriteFile(filepath, p_tmd, header->tmd_len)) + return false; + + // Get title key and prepare decryption + _decrypt_title_key(p_tik, title_key); + aes_set_key(title_key); + + // Start progress + ProgressCancelEnable(true); + StartProgress(0, 0, 0, true, true); + + // Install contents + bool result = InstallContents(installpath); + + // Stop progress + ProgressStop(); + ProgressCancelEnable(false); + + if(!result) + return false; + + // Update /sys/uid.sys + if(!SetTitleUID(installpath, tmd_data->title_id)) + return false; + + return true; +} + +bool Wad::WriteFile(const char *filepath, u8 *buffer, u32 len) +{ + FILE *f = fopen(filepath, "wb"); + if(!f) + { + if(showPrompt) + ShowError(tr("Can't create file: %s"), filepath); + return false; + } + + u32 write = fwrite(buffer, 1, len, f); + fclose(f); + + if(write != len && showPrompt) + ShowError(tr("Write error on file: %s"), filepath); + + return (write == len); +} + +bool Wad::InstallContents(const char *installpath) +{ + const u32 blocksize = 50 * 1024; + u16 cnt; + u32 totalDone = 0; + u32 totalSize = 0; + u32 offset = content_start; + char filepath[1024]; + char progressTxt[80]; + u8 iv[16]; + bool userCanceled = false; + + // tmd + tmd *tmd_data = (tmd *) SIGNATURE_PAYLOAD((signed_blob *) p_tmd); + + // Get total size for progress bar + for (cnt = 0; cnt < tmd_data->num_contents; cnt++) + { + if(tmd_data->contents[cnt].type == 0x8001) { + // shared content + int result = CheckContentMap(installpath, &tmd_data->contents[cnt], filepath); + if(result == 1) // exists already, skip file + continue; + } + totalSize += round_up( tmd_data->contents[cnt].size, 64 ); + } + + for (cnt = 0; cnt < tmd_data->num_contents; cnt++) + { + if(ProgressCanceled()) + break; + + if(cnt > 0) + offset += round_up( tmd_data->contents[cnt-1].size, 64); + + u32 done = 0, len; + tmd_content *content = &tmd_data->contents[cnt]; + + // Encrypted content size + len = round_up( content->size, 64 ); + + // Prepare iv for decryption + memset(iv, 0, sizeof(iv)); + memcpy(iv, &cnt, 2); + + // Install content + if(content->type == 0x8001) { + // shared content + int result = CheckContentMap(installpath, content, filepath); + if(result == 1) // exists already, skip file + continue; + + else if(result < 0) // failure + return false; + // else it does not exist...install it + } + else { + // private content + snprintf(filepath, sizeof(filepath), "%s/title/%08x/%08x/content/%08x.app", installpath, (unsigned int) (tmd_data->title_id >> 32), (unsigned int) tmd_data->title_id, (unsigned int) content->cid); + } + + // Create file + FILE *fp = fopen(filepath, "wb"); + if(!fp) + { + if(showPrompt) + ShowError(tr("Can't create file: %s"), filepath); + return false; + } + + u8 * inbuf = (u8 *) malloc(blocksize); + u8 * outbuf = (u8 *) malloc(blocksize); + if(!inbuf || !outbuf) + { + if(showPrompt) + ShowError(tr("Not enough memory.")); + if(inbuf) free(inbuf); + if(outbuf) free(outbuf); + fclose(fp); + return false; + } + + snprintf(progressTxt, sizeof(progressTxt), "%s %08x.app", tr("Installing content"), (unsigned int) content->cid); + + // Go to position + fseek(pFile, offset, SEEK_SET); + + // Install content data + while (done < len) + { + if(ProgressCanceled()) + { + userCanceled = true; + break; + } + + ShowProgress(tr("Installing title..."), progressTxt, 0, totalDone + done, totalSize, true, true); + + // Encrypted data length + u32 size = (len - done); + if (size > blocksize) + size = blocksize; + + // Decryted data length + u32 dec_size = (content->size - done); // Content size not round up to 64 + if (dec_size > blocksize) + dec_size = blocksize; + + // Read data + if(fread(inbuf, 1, size, pFile) != size) + break; + + // Decrypt data + aes_decrypt(iv, inbuf, outbuf, size); + + // Write data + if(fwrite(outbuf, 1, dec_size, fp) != dec_size) + break; + + // Set new iv for next read chunk + memcpy(iv, inbuf + blocksize - 16, 16); + + // Increase variables + done += size; + } + + // done + free(inbuf); + free(outbuf); + fclose(fp); + + // update progress variable + totalDone += len; + + // Check if the user canceled the install manually + if(userCanceled) + return false; + + // Check if the read/write process stopped before finishing + if(done < len) + { + if(showPrompt) + ShowError(tr("File read/write error.")); + return false; + } + } + + return true; +} + +int Wad::CheckContentMap(const char *installpath, tmd_content *content, char *filepath) +{ + if(!content_map) + { + // Get and keep content map in memory + snprintf(filepath, 1024, "%s/shared1/content.map", installpath); + if(LoadFileToMem(filepath, &content_map, &content_map_size) < 0 || content_map_size < sizeof(map_entry_t)) + { + if(showPrompt) + ShowError(tr("Can't read file: %s"), filepath); + return -1; + } + + content_map_size /= sizeof(map_entry_t); + } + + map_entry_t *map = (map_entry_t *) content_map; + + for(u32 n = 0; n < content_map_size; n++) + { + if(memcmp(map[n].hash, content->hash, 20) == 0) + return 1; // content exists already + } + + // Content does not exists, append it. + u32 next_entry = content_map_size; + u8 *tmp = (u8 *) realloc(content_map, (next_entry + 1) * sizeof(map_entry_t)); + if(!tmp) + { + if(showPrompt) + ShowError(tr("Not enough memory.")); + return -1; + } + + content_map = tmp; + content_map_size++; + + map = (map_entry_t *) content_map; + sprintf(map[next_entry].name, "%08x", (unsigned int)next_entry); + memcpy(map[next_entry].hash, content->hash, 20); + + // write new content.map + snprintf(filepath, 1024, "%s/shared1/content.map", installpath); + if(!WriteFile(filepath, content_map, content_map_size * sizeof(map_entry_t))) + return -1; + + snprintf(filepath, 1024, "%s/shared1/%08x.app", installpath, (unsigned int)next_entry); + + return 0; +} + +bool Wad::SetTitleUID(const char *installpath, const u64 &tid) +{ + char filepath[1024]; + u8 *uid_sys = NULL; + u32 uid_sys_size = 0; + + // Read in uid.sys file + snprintf(filepath, sizeof(filepath), "%s/sys/uid.sys", installpath); + + if(LoadFileToMem(filepath, &uid_sys, &uid_sys_size) < 0 || uid_sys_size < sizeof(uid_entry_t)) + { + if(showPrompt) + ShowError(tr("Can't read file: %s"), filepath); + if(uid_sys) free(uid_sys); + return false; + } + + uid_sys_size /= sizeof(uid_entry_t); + uid_entry_t *map = (uid_entry_t *) uid_sys; + + for(u32 i = 0; i < uid_sys_size; ++i) + { + if(map[i].title_id == tid) + { + // title entry exists already + free(uid_sys); + return true; + } + } + + // title entry does not exists, append it + u32 next_entry = uid_sys_size; + u8 *tmp = (u8 *) realloc(uid_sys, (next_entry + 1) * sizeof(uid_entry_t)); + if(!tmp) + { + if(showPrompt) + ShowError(tr("Not enough memory.")); + free(uid_sys); + return -1; + } + + uid_sys = tmp; + uid_sys_size++; + + map = (uid_entry_t *) uid_sys; + map[next_entry].title_id = tid; + map[next_entry].uid = map[next_entry-1].uid + 1; + + // write new uid.sys + bool result = WriteFile(filepath, uid_sys, uid_sys_size * sizeof(uid_entry_t)); + + free(uid_sys); + + return result; +} diff --git a/source/wad/wad.h b/source/wad/wad.h new file mode 100644 index 0000000..dab2300 --- /dev/null +++ b/source/wad/wad.h @@ -0,0 +1,64 @@ +/**************************************************************************** + * Copyright (C) 2011 Dimok + * + * 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 _WAD_H_ +#define _WAD_H_ + +#include + +/* 'WAD Header' structure */ +typedef struct +{ + /* Header length */ + u32 header_len; + /* WAD type */ + u16 type; + u16 padding; + /* Data length */ + u32 certs_len; + u32 crl_len; + u32 tik_len; + u32 tmd_len; + u32 data_len; + u32 footer_len; +} ATTRIBUTE_PACKED wadHeader; + +class Wad +{ +public: + Wad(const char *wadpath = 0, bool prompt = true); + virtual ~Wad(); + bool Open(const char *wadpath); + void Close(void); + bool Install(const char *installpath); + bool UnInstall(const char *installpath); + void SetPrompt(bool choice) { showPrompt = choice; }; +private: + bool InstallContents(const char *installpath); + int CheckContentMap(const char *installpath, tmd_content *content, char *filepath); + bool WriteFile(const char *filepath, u8 *buffer, u32 len); + bool SetTitleUID(const char *intallpath, const u64 &tid); + + FILE *pFile; + wadHeader *header; + u8 *p_tik, *p_tmd; + u8 *content_map; + u32 content_map_size; + u32 content_start; + bool showPrompt; +}; + +#endif diff --git a/source/wpad.c b/source/wpad.c new file mode 100644 index 0000000..98ec343 --- /dev/null +++ b/source/wpad.c @@ -0,0 +1,91 @@ +#include +#include +#include + +#include "sys.h" +#include "wpad.h" + +/* Constants */ +#define MAX_WIIMOTES 4 + +extern u8 shutdown; + +void __Wpad_PowerCallback(s32 chan) +{ + /* Poweroff console */ + shutdown = 1; +} + +s32 Wpad_Init(void) +{ + s32 ret; + + /* Initialize Wiimote subsystem */ + ret = WPAD_Init(); + if (ret < 0) return ret; + + /* Set POWER button callback */ + WPAD_SetPowerButtonCallback(__Wpad_PowerCallback); + + return ret; +} + +void Wpad_Disconnect(void) +{ + u32 cnt; + + /* Disconnect Wiimotes */ + for (cnt = 0; cnt < MAX_WIIMOTES; cnt++) + WPAD_Disconnect(cnt); + + /* Shutdown Wiimote subsystem */ + WPAD_Shutdown(); +} + +bool IsWpadConnected() +{ + int i = 0; + u32 test = 0; + int notconnected = 0; + for (i = 0; i < 4; i++) + { + if (WPAD_Probe(i, &test) == WPAD_ERR_NO_CONTROLLER) + { + notconnected++; + } + } + if (notconnected < 4) + return true; + else return false; +} + +u32 ButtonsHold(void) +{ + + int i; + u32 buttons = 0; + WPAD_ScanPads(); + PAD_ScanPads(); + + for (i = 3; i >= 0; i--) + { + buttons |= PAD_ButtonsHeld(i); + buttons |= WPAD_ButtonsHeld(i); + } + return buttons; +} + +u32 ButtonsPressed(void) +{ + int i; + u32 buttons = 0; + WPAD_ScanPads(); + PAD_ScanPads(); + + for (i = 3; i >= 0; i--) + { + buttons |= PAD_ButtonsDown(i); + buttons |= WPAD_ButtonsDown(i); + } + return buttons; +} diff --git a/source/wpad.h b/source/wpad.h new file mode 100644 index 0000000..d92fe30 --- /dev/null +++ b/source/wpad.h @@ -0,0 +1,22 @@ +#ifndef _WPAD_H_ +#define _WPAD_H_ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Prototypes */ + s32 Wpad_Init(void); + void Wpad_Disconnect(void); + u32 ButtonsPressed(void); + u32 ButtonsHold(void); + bool IsWpadConnected(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/wstring.cpp b/source/wstring.cpp new file mode 100644 index 0000000..907768c --- /dev/null +++ b/source/wstring.cpp @@ -0,0 +1,167 @@ +#include +#include "wstring.hpp" + +using namespace std; + +wString::wString(const wchar_t *s) : + std::basic_string, std::allocator >(s) +{ +} + +wString::wString(const basic_string , allocator > &ws) : + basic_string , allocator > (ws) +{ +} + +wString::wString(const string &s) +{ + std::string::size_type size; + + size = s.size(); + resize(size); + for (std::string::size_type i = 0; i < size; ++i) + (*this)[i] = (unsigned char) s[i]; +} + +wString &wString::operator=(const string & s) +{ + std::string::size_type size; + + size = s.size(); + this->resize(size); + for (std::string::size_type i = 0; i < size; ++i) + (*this)[i] = (unsigned char) s[i]; + return *this; +} + +void wString::fromUTF8(const char *s) +{ + size_t len = utf8Len(s); + + clear(); + if (len == 0) return; + reserve(len); + for (int i = 0; s[i] != 0;) + { + if ((s[i] & 0xF8) == 0xF0) + { + push_back(((wchar_t) (s[i] & 0x07) << 18) | ((wchar_t) (s[i + 1] & 0x3F) << 12) | ((wchar_t) (s[i + 2] + & 0x3F) << 6) | (wchar_t) (s[i + 3] & 0x3F)); + i += 4; + } + else if ((s[i] & 0xF0) == 0xE0) + { + push_back(((wchar_t) (s[i] & 0x0F) << 12) | ((wchar_t) (s[i + 1] & 0x3F) << 6) + | (wchar_t) (s[i + 2] & 0x3F)); + i += 3; + } + else if ((s[i] & 0xE0) == 0xC0) + { + push_back(((wchar_t) (s[i] & 0x1F) << 6) | (wchar_t) (s[i + 1] & 0x3F)); + i += 2; + } + else + { + push_back((wchar_t) s[i]); + ++i; + } + } +} + +string wString::toUTF8(void) const +{ + string s; + size_t len = 0; + wchar_t wc; + + for (size_t i = 0; i < size(); ++i) + { + wc = operator[](i); + if (wc < 0x80) + ++len; + else if (wc < 0x800) + len += 2; + else if (wc < 0x10000) + len += 3; + else len += 4; + } + s.reserve(len); + for (size_t i = 0; i < size(); ++i) + { + wc = operator[](i); + if (wc < 0x80) + s.push_back((char) wc); + else if (wc < 0x800) + { + s.push_back((char) ((wc >> 6) | 0xC0)); + s.push_back((char) ((wc & 0x3F) | 0x80)); + } + else if (wc < 0x10000) + { + s.push_back((char) ((wc >> 12) | 0xE0)); + s.push_back((char) (((wc >> 6) & 0x3F) | 0x80)); + s.push_back((char) ((wc & 0x3F) | 0x80)); + } + else + { + s.push_back((char) (((wc >> 18) & 0x07) | 0xF0)); + s.push_back((char) (((wc >> 12) & 0x3F) | 0x80)); + s.push_back((char) (((wc >> 6) & 0x3F) | 0x80)); + s.push_back((char) ((wc & 0x3F) | 0x80)); + } + } + return s; +} + +size_t utf8Len(const char *s) +{ + size_t len = 0; + + for (int i = 0; s[i] != 0;) + { + if ((s[i] & 0xF8) == 0xF0) + { + if (((s[i + 1] & 0xC0) != 0x80) || ((s[i + 2] & 0xC0) != 0x80) || ((s[i + 3] & 0xC0) != 0x80)) return 0; + ++len; + i += 4; + } + else if ((s[i] & 0xF0) == 0xE0) + { + if (((s[i + 1] & 0xC0) != 0x80) || ((s[i + 2] & 0xC0) != 0x80)) return 0; + ++len; + i += 3; + } + else if ((s[i] & 0xE0) == 0xC0) + { + if (((s[i + 1] & 0xC0) != 0x80)) return 0; + ++len; + i += 2; + } + else if ((s[i] & 0x80) == 0x00) + { + ++len; + ++i; + } + else return 0; + } + return len; +} + +const wchar_t *wcscasestr(const wchar_t *s1, const wchar_t *s2) +{ + if(*s2 == 0) + return (wchar_t *)s1; + + int s1_len = wcslen(s1); + int s2_len = wcslen(s2); + + if(s1_len < s2_len) + return 0; + + const wchar_t *end = &s1[s1_len-s2_len]; + for(const wchar_t *s = s1; s <= end; s++) + if(wcsncasecmp(s, s2, s2_len)==0) + return s; + + return 0; +} diff --git a/source/wstring.hpp b/source/wstring.hpp new file mode 100644 index 0000000..f18dc7c --- /dev/null +++ b/source/wstring.hpp @@ -0,0 +1,28 @@ +/**************************************************************************** + * wstring Class + * by Hibernatus + ***************************************************************************/ +#ifndef __WSTRING_HPP +#define __WSTRING_HPP + +#include + +class wString: public std::basic_string, std::allocator > +{ + public: + wString(void) + { + } + wString(const wchar_t *s); + wString(const std::basic_string, std::allocator > &ws); + wString(const std::string &s); + wString &operator=(const std::string &s); + void fromUTF8(const char *s); + std::string toUTF8(void) const; +}; + +size_t utf8Len(const char *s); + +const wchar_t *wcscasestr(const wchar_t *s1, const wchar_t *s2); + +#endif // !defined(__WSTRING_HPP) diff --git a/source/xml/GameTDB.cpp b/source/xml/GameTDB.cpp new file mode 100644 index 0000000..b94a6f4 --- /dev/null +++ b/source/xml/GameTDB.cpp @@ -0,0 +1,1256 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include +#include "GameTDB.hpp" + +#define NAME_OFFSET_DB "wiitdb_offsets.bin" +#define MAXREADSIZE 1024*1024 // Cache size only for parsing the offsets: 1MB + +typedef struct _ReplaceStruct +{ + const char * orig; + char replace; + short size; +} ReplaceStruct; + +//! More replacements can be added if needed +static const ReplaceStruct Replacements[] = +{ + { ">", '>', 4 }, + { "<", '<', 4 }, + { """, '\"', 6 }, + { "'", '\'', 6 }, + { "&", '&', 5 }, + { NULL, '\0', 0 } +}; + +GameTDB::GameTDB() + : file(0), LangCode("EN"), GameNodeCache(0) +{ +} + +GameTDB::GameTDB(const char * filepath) + : file(0), LangCode("EN"), GameNodeCache(0) +{ + OpenFile(filepath); +} + +GameTDB::~GameTDB() +{ + CloseFile(); +} + +bool GameTDB::OpenFile(const char * filepath) +{ + if(!filepath) + return false; + + file = fopen(filepath, "rb"); + if(file) + { + int pos; + string OffsetsPath = filepath; + if((pos = OffsetsPath.find_last_of('/')) != (int) string::npos) + OffsetsPath[pos] = '\0'; + else + OffsetsPath.clear(); //! Relative path + + LoadGameOffsets(OffsetsPath.c_str()); + } + + return (file != NULL); +} + +void GameTDB::CloseFile() +{ + OffsetMap.clear(); + vector().swap(OffsetMap); + + if(GameNodeCache) + delete [] GameNodeCache; + GameNodeCache = NULL; + + if(file) + fclose(file); + file = NULL; +} + +bool GameTDB::LoadGameOffsets(const char * path) +{ + if(!path) + return false; + + string OffsetDBPath = path; + if(strlen(path) > 0 && path[strlen(path)-1] != '/') + OffsetDBPath += '/'; + OffsetDBPath += NAME_OFFSET_DB; + + FILE * fp = fopen(OffsetDBPath.c_str(), "rb"); + if(!fp) + { + bool result = ParseFile(); + if(result) + SaveGameOffsets(OffsetDBPath.c_str()); + + return result; + } + + unsigned long long ExistingVersion = GetGameTDBVersion(); + unsigned long long Version = 0; + unsigned int NodeCount = 0; + + fread(&Version, 1, sizeof(Version), fp); + + if(ExistingVersion != Version) + { + fclose(fp); + bool result = ParseFile(); + if(result) + SaveGameOffsets(OffsetDBPath.c_str()); + + return result; + } + + fread(&NodeCount, 1, sizeof(NodeCount), fp); + + if(NodeCount == 0) + { + fclose(fp); + bool result = ParseFile(); + if(result) + SaveGameOffsets(OffsetDBPath.c_str()); + + return result; + } + + OffsetMap.resize(NodeCount); + + if((int) fread(&OffsetMap[0], 1, NodeCount*sizeof(GameOffsets), fp) < 0) + { + fclose(fp); + bool result = ParseFile(); + if(result) + SaveGameOffsets(OffsetDBPath.c_str()); + + return result; + } + + fclose(fp); + + return true; +} + +bool GameTDB::SaveGameOffsets(const char * path) +{ + if(OffsetMap.size() == 0 || !path) + return false; + + FILE * fp = fopen(path, "wb"); + if(!fp) + return false; + + unsigned long long ExistingVersion = GetGameTDBVersion(); + unsigned int NodeCount = OffsetMap.size(); + + if(fwrite(&ExistingVersion, 1, sizeof(ExistingVersion), fp) != sizeof(ExistingVersion)) + { + fclose(fp); + return false; + } + + if(fwrite(&NodeCount, 1, sizeof(NodeCount), fp) != sizeof(NodeCount)) + { + fclose(fp); + return false; + } + + if(fwrite(&OffsetMap[0], 1, NodeCount*sizeof(GameOffsets), fp) != NodeCount*sizeof(GameOffsets)) + { + fclose(fp); + return false; + } + + fclose(fp); + + return true; +} + +unsigned long long GameTDB::GetGameTDBVersion() +{ + if(!file) + return 0; + + char TmpText[1024]; + + if(GetData(TmpText, 0, sizeof(TmpText)) < 0) + return 0; + + char * VersionText = GetNodeText(TmpText, ""); + if(!VersionText) + return 0; + + return strtoull(VersionText, NULL, 10); +} + +int GameTDB::GetData(char * data, int offset, int size) +{ + if(!file || !data) + return -1; + + fseek(file, offset, SEEK_SET); + + return fread(data, 1, size, file); +} + +char * GameTDB::LoadGameNode(const char * id) +{ + unsigned int read = 0; + + GameOffsets * offset = this->GetGameOffset(id); + if(!offset) + return NULL; + + char * data = new (std::nothrow) char[offset->nodesize+1]; + if(!data) + return NULL; + + if((read = GetData(data, offset->gamenode, offset->nodesize)) != offset->nodesize) + { + delete [] data; + return NULL; + } + + data[read] = '\0'; + + return data; +} + +char * GameTDB::GetGameNode(const char * id) +{ + char * data = NULL; + + if(GameNodeCache != 0 && strncmp(id, GameIDCache, strlen(GameIDCache)) == 0) + { + data = new (std::nothrow) char[strlen(GameNodeCache)+1]; + if(data) + strcpy(data, GameNodeCache); + } + else + { + if(GameNodeCache) + delete [] GameNodeCache; + + GameNodeCache = LoadGameNode(id); + + if(GameNodeCache) + { + snprintf(GameIDCache, sizeof(GameIDCache), id); + data = new (std::nothrow) char[strlen(GameNodeCache)+1]; + if(data) + strcpy(data, GameNodeCache); + } + } + + return data; +} + +GameOffsets * GameTDB::GetGameOffset(const char * gameID) +{ + for(unsigned int i = 0; i < OffsetMap.size(); ++i) + { + if(strncmp(gameID, OffsetMap[i].gameID, strlen(OffsetMap[i].gameID)) == 0) + return &OffsetMap[i]; + } + + return 0; +} + +static inline char * CleanText(char * in_text) +{ + if(!in_text) + return NULL; + + const char * ptr = in_text; + char * text = in_text; + + while(*ptr != '\0') + { + for(int i = 0; Replacements[i].orig != 0; ++i) + { + if(strncmp(ptr, Replacements[i].orig, Replacements[i].size) == 0) + { + ptr += Replacements[i].size; + *text = Replacements[i].replace; + ++text; + i = 0; + continue; + } + } + + if(*ptr == '\r') + { + ++ptr; + continue; + } + + *text = *ptr; + ++ptr; + ++text; + } + + *text = '\0'; + + return in_text; +} + +char * GameTDB::GetNodeText(char * data, const char * nodestart, const char * nodeend) +{ + if(!data || !nodestart || !nodeend) + return NULL; + + char * position = strstr(data, nodestart); + if(!position) + return NULL; + + position += strlen(nodestart); + + char * end = strstr(position, nodeend); + if(!end) + return NULL; + + *end = '\0'; + + return CleanText(position); +} + +char * GameTDB::SeekLang(char * text, const char * langcode) +{ + if(!text || !langcode) return NULL; + + char * ptr = text; + while((ptr = strstr(ptr, ""); + if(!end) + return NULL; + + end += strlen(""); + *end = '\0'; + + return ptr; + } + } + + return NULL; +} + +bool GameTDB::ParseFile() +{ + OffsetMap.clear(); + + if(!file) + return false; + + char * Line = new (std::nothrow) char[MAXREADSIZE+1]; + if(!Line) + return false; + + bool readnew = false; + int i, currentPos = 0; + int read = 0; + const char * gameNode = NULL; + const char * idNode = NULL; + const char * gameEndNode = NULL; + const char * genreNode = NULL; + const char * descriptNode = NULL; + + while((read = GetData(Line, currentPos, MAXREADSIZE)) > 0) + { + gameNode = Line; + readnew = false; + + //! Ensure the null termination at the end + Line[read] = '\0'; + + //! Try to find genre translation map + if(!genreNode && (genreNode = strstr(gameNode, "")) != NULL) + { + const char *genreNodeEnd = strstr(genreNode, ""); + if(genreNodeEnd) + { + int size = OffsetMap.size(); + OffsetMap.resize(size+1); + strcpy(OffsetMap[size].gameID, "gnrmap"); + OffsetMap[size].gamenode = currentPos+(genreNode-Line); + OffsetMap[size].nodesize = (genreNodeEnd-genreNode); + } + } + + //! Try to find description translation map + if(!descriptNode && (descriptNode = strstr(gameNode, "")) != NULL) + { + const char *descriptNodeEnd = strstr(descriptNode, ""); + if(descriptNodeEnd) + { + int size = OffsetMap.size(); + OffsetMap.resize(size+1); + strcpy(OffsetMap[size].gameID, "dscmap"); + OffsetMap[size].gamenode = currentPos+(descriptNode-Line); + OffsetMap[size].nodesize = (descriptNodeEnd-descriptNode); + } + } + + while((gameNode = strstr(gameNode, ""); + gameEndNode = strstr(gameNode, ""); + if(!idNode || !gameEndNode) + { + //! We are in the middle of the game node, reread complete node and more + currentPos += (gameNode-Line); + fseek(file, currentPos, SEEK_SET); + readnew = true; + break; + } + + idNode += strlen(""); + gameEndNode += strlen(""); + + int size = OffsetMap.size(); + OffsetMap.resize(size+1); + + for(i = 0; i < 7 && *idNode != '<'; ++i, ++idNode) + OffsetMap[size].gameID[i] = *idNode; + OffsetMap[size].gameID[i] = '\0'; + OffsetMap[size].gamenode = currentPos+(gameNode-Line); + OffsetMap[size].nodesize = (gameEndNode-gameNode); + gameNode = gameEndNode; + } + + if(readnew) + continue; + + currentPos += read; + } + + delete [] Line; + + return true; +} + +bool GameTDB::GetTitle(const char * id, string & title) +{ + if(!id) + return false; + + char * data = GetGameNode(id); + if(!data) + return false; + + char * language = SeekLang(data, LangCode.c_str()); + if(!language) + { + language = SeekLang(data, "EN"); + if(!language) + { + delete [] data; + return false; + } + } + + char * the_title = GetNodeText(language, "", ""); + if(!the_title) + { + delete [] data; + return false; + } + + title = the_title; + + delete [] data; + + return true; +} + +bool GameTDB::GetSynopsis(const char * id, string & synopsis) +{ + if(!id) + return false; + + char * data = GetGameNode(id); + if(!data) + return false; + + char * language = SeekLang(data, LangCode.c_str()); + if(!language) + { + language = SeekLang(data, "EN"); + if(!language) + { + delete [] data; + return false; + } + } + + char * the_synopsis = GetNodeText(language, "", ""); + if(!the_synopsis) + { + delete [] data; + return false; + } + + synopsis = the_synopsis; + + delete [] data; + + return true; +} + +bool GameTDB::GetRegion(const char * id, string & region) +{ + if(!id) + return false; + + char * data = GetGameNode(id); + if(!data) + return false; + + char * the_region = GetNodeText(data, "", ""); + if(!the_region) + { + delete [] data; + return false; + } + + region = the_region; + + delete [] data; + + return true; +} + +bool GameTDB::GetDeveloper(const char * id, string & dev) +{ + if(!id) + return false; + + char * data = GetGameNode(id); + if(!data) + return false; + + char * the_dev = GetNodeText(data, "", ""); + if(!the_dev) + { + delete [] data; + return false; + } + + dev = the_dev; + + delete [] data; + + return true; +} + +bool GameTDB::GetPublisher(const char * id, string & pub) +{ + if(!id) + return false; + + char * data = GetGameNode(id); + if(!data) + return false; + + char * the_pub = GetNodeText(data, "", ""); + if(!the_pub) + { + delete [] data; + return false; + } + + pub = the_pub; + + delete [] data; + + return true; +} + +unsigned int GameTDB::GetPublishDate(const char * id) +{ + if(!id) + return 0; + + char * data = GetGameNode(id); + if(!data) + return 0; + + char * year_string = GetNodeText(data, ""); + if(!year_string) + { + delete [] data; + return 0; + } + + unsigned int year, day, month; + + year = atoi(year_string); + + char * month_string = strstr(year_string, "month=\""); + if(!month_string) + { + delete [] data; + return 0; + } + + month_string += strlen("month=\""); + + month = atoi(month_string); + + char * day_string = strstr(month_string, "day=\""); + if(!day_string) + { + delete [] data; + return 0; + } + + day_string += strlen("day=\""); + + day = atoi(day_string); + + delete [] data; + + return ((year & 0xFFFF) << 16 | (month & 0xFF) << 8 | (day & 0xFF)); +} + +bool GameTDB::GetGenreList(const char * id, vector & genre) +{ + if(!id) + return false; + + char * data = GetGameNode(id); + if(!data) + return false; + + char * the_genre = GetNodeText(data, "", ""); + if(!the_genre) + { + delete [] data; + return false; + } + + unsigned int genre_num = 0; + const char * ptr = the_genre; + + while(*ptr != '\0') + { + if(genre_num >= genre.size()) + genre.resize(genre_num+1); + + if(*ptr == ',' || *ptr == '/' || *ptr == ';') + { + ptr++; + while(*ptr == ' ') ptr++; + + while(genre[genre_num].size() > 0 && genre[genre_num][genre[genre_num].size()-1] == ' ') + genre[genre_num].erase(genre[genre_num].size()-1); + + genre_num++; + continue; + } + + if(genre[genre_num].size() == 0) + genre[genre_num].push_back(toupper((int)*ptr)); + else + genre[genre_num].push_back(*ptr); + + ++ptr; + } + + while(genre.size() > genre_num && genre[genre_num].size() > 0 && genre[genre_num][genre[genre_num].size()-1] == ' ') + genre[genre_num].erase(genre[genre_num].size()-1); + + delete [] data; + + if(strcmp(LangCode.c_str(), "EN") != 0) + TranslateGenres(genre); + + return true; +} + +void GameTDB::TranslateGenres(vector &GenreList) +{ + char * data = GetGameNode("gnrmap"); + if(!data) + return; + + for(unsigned int i = 0; i < GenreList.size(); ++i) + { + for(unsigned int n = 0; n < 2; n++) + { + string nodeStart; + + if(n == 0) + nodeStart = ""); + const char *subNodeStart = strstr(genreNode, ""; + + const char *langPtr = strcasestr(genreNode, localStr.c_str()); + if(langPtr && langPtr < genreNodeEnd) + { + bool firstLetter = true; + GenreList[i].clear(); + langPtr += localStr.size(); + + while(*langPtr == ' ') + langPtr++; + + while(*langPtr != 0 && !(langPtr[0] == '<' && langPtr[1] == '/')) + { + if(firstLetter) + { + GenreList[i].push_back(toupper((int)*langPtr)); + firstLetter = false; + } + else + GenreList[i].push_back(*langPtr); + langPtr++; + } + + while(GenreList[i].size() > 0 && GenreList[i][GenreList[i].size()-1] == ' ') + GenreList[i].erase(GenreList[i].size()-1); + } + break; + } + } + + delete [] data; +} + + +const char * GameTDB::RatingToString(int rating) +{ + switch(rating) + { + case 0: + return "CERO"; + case 1: + return "ESRB"; + case 2: + return "PEGI"; + default: + break; + } + + return NULL; +} + +int GameTDB::StringToRating(const char *rate_string) +{ + if (strcasecmp(rate_string, "CERO") == 0) + return 0; + + if (strcasecmp(rate_string, "ESRB") == 0) + return 1; + + if (strcasecmp(rate_string, "PEGI") == 0) + return 2; + + return -1; +} + +int GameTDB::ConvertRating(const char *value, const char *from, const char *to) +{ + if (strcasecmp(from, to) == 0) + { + int ret = atoi(value); + if(ret < 7) + return 0; + else if(ret < 12) + return 1; + else if(ret < 16) + return 2; + else if(ret < 18) + return 3; + else + return 4; + } + + int type = -1; + int desttype = -1; + + type = StringToRating(from); + desttype = StringToRating(to); + if (type == -1 || desttype == -1) return -1; + + /* rating conversion table */ + /* the list is ordered to pick the most likely value first: */ + /* EC and AO are less likely to be used so they are moved down to only be picked up when converting ESRB to PEGI or CERO */ + /* the conversion can never be perfect because ratings can differ between regions for the same game */ + const int table_size = 12; + char ratingtable[table_size][3][5] = + { + { { "A" }, { "E" }, { "3" } }, + { { "A" }, { "E" }, { "4" } }, + { { "A" }, { "E" }, { "6" } }, + { { "A" }, { "E" }, { "7" } }, + { { "A" }, { "EC" }, { "3" } }, + { { "A" }, { "E10+" }, { "7" } }, + { { "B" }, { "T" }, { "12" } }, + { { "D" }, { "M" }, { "18" } }, + { { "D" }, { "M" }, { "16" } }, + { { "C" }, { "T" }, { "16" } }, + { { "C" }, { "T" }, { "15" } }, + { { "Z" }, { "AO" }, { "18" } }, + }; + + for (int i = 0; i < table_size; i++) + { + if (strcasecmp(ratingtable[i][type], value) == 0) + { + int res = atoi(ratingtable[i][desttype]); + if(res < 7) + return 0; + else if(res < 12) + return 1; + else if(res < 16) + return 2; + else if(res < 18) + return 3; + else + return 4; + } + } + + return -1; +} + +int GameTDB::GetRating(const char * id) +{ + int rating = -1; + + if(!id) + return rating; + + char * data = GetGameNode(id); + if(!data) + return rating; + + char * rating_text = GetNodeText(data, ""); + if(!rating_text) + { + delete [] data; + return rating; + } + + if(strncmp(rating_text, "CERO", 4) == 0) + rating = 0; + + else if(strncmp(rating_text, "ESRB", 4) == 0) + rating = 1; + + else if(strncmp(rating_text, "PEGI", 4) == 0) + rating = 2; + + delete [] data; + + return rating; +} + +bool GameTDB::GetRatingValue(const char * id, string & rating_value) +{ + if(!id) + return false; + + char * data = GetGameNode(id); + if(!data) + return false; + + char * rating_text = GetNodeText(data, ""); + if(!rating_text) + { + delete [] data; + return false; + } + + char * value_text = GetNodeText(rating_text, "value=\"", "\""); + if(!value_text) + { + delete [] data; + return false; + } + + rating_value = value_text; + + delete [] data; + + return true; +} + +int GameTDB::GetRatingDescriptorList(const char * id, vector & desc_list) +{ + if(!id) + return -1; + + char * data = GetGameNode(id); + if(!data) + return -1; + + char * descriptor_text = GetNodeText(data, "", ""); + if(!descriptor_text) + { + delete [] data; + return -1; + } + + unsigned int list_num = 0; + desc_list.clear(); + + while(*descriptor_text != '\0') + { + if(strncmp(descriptor_text, "", strlen("")) == 0) + { + descriptor_text = strstr(descriptor_text, ""); + if(!descriptor_text) + break; + + descriptor_text += strlen(""); + list_num++; + } + + if(list_num >= desc_list.size()) + desc_list.resize(list_num+1); + + desc_list[list_num].push_back(*descriptor_text); + ++descriptor_text; + } + + delete [] data; + + if(strcmp(LangCode.c_str(), "EN") != 0) + TranslateDescriptors(desc_list); + + return desc_list.size(); +} + +void GameTDB::TranslateDescriptors(vector &DescList) +{ + char * data = GetGameNode("dscmap"); + if(!data) + return; + + for(unsigned int i = 0; i < DescList.size(); ++i) + { + string nodeStart = ""); + if(!genreNodeEnd) + continue; + + string localStr = ""; + + const char *langPtr = strcasestr(genreNode, localStr.c_str()); + if(langPtr && langPtr < genreNodeEnd) + { + bool firstLetter = true; + DescList[i].clear(); + langPtr += localStr.size(); + + while(*langPtr == ' ') + langPtr++; + + while(*langPtr != 0 && !(langPtr[0] == '<' && langPtr[1] == '/')) + { + if(firstLetter) + { + DescList[i].push_back(toupper((int)*langPtr)); + firstLetter = false; + } + else + DescList[i].push_back(*langPtr); + langPtr++; + } + + while(DescList[i].size() > 0 && DescList[i][DescList[i].size()-1] == ' ') + DescList[i].erase(DescList[i].size()-1); + } + } + + delete [] data; +} + +int GameTDB::GetWifiPlayers(const char * id) +{ + int players = -1; + + if(!id) + return players; + + char * data = GetGameNode(id); + if(!data) + return players; + + char * PlayersNode = GetNodeText(data, ""); + if(!PlayersNode) + { + delete [] data; + return players; + } + + players = atoi(PlayersNode); + + delete [] data; + + return players; +} + +int GameTDB::GetWifiFeatureList(const char * id, vector & feat_list) +{ + if(!id) + return -1; + + char * data = GetGameNode(id); + if(!data) + return -1; + + char * feature_text = GetNodeText(data, "", ""); + if(!feature_text) + { + delete [] data; + return -1; + } + + unsigned int list_num = 0; + feat_list.clear(); + + while(*feature_text != '\0') + { + if(strncmp(feature_text, "", strlen("")) == 0) + { + feature_text = strstr(feature_text, ""); + if(!feature_text) + break; + + feature_text += strlen(""); + list_num++; + } + + if(list_num >= feat_list.size()) + feat_list.resize(list_num+1); + + + if(feat_list[list_num].size() == 0) + feat_list[list_num].push_back(toupper((int)*feature_text)); + else + feat_list[list_num].push_back(*feature_text); + + ++feature_text; + } + + delete [] data; + + return feat_list.size(); +} + +int GameTDB::GetPlayers(const char * id) +{ + int players = -1; + + if(!id) + return players; + + char * data = GetGameNode(id); + if(!data) + return players; + + char * PlayersNode = GetNodeText(data, ""); + if(!PlayersNode) + { + delete [] data; + return players; + } + + players = atoi(PlayersNode); + + delete [] data; + + return players; +} + +int GameTDB::GetAccessoirList(const char * id, vector & acc_list) +{ + if(!id) + return -1; + + char * data = GetGameNode(id); + if(!data) + return -1; + + char * ControlsNode = GetNodeText(data, ""); + if(!ControlsNode) + { + delete [] data; + return -1; + } + + unsigned int list_num = 0; + acc_list.clear(); + + while(ControlsNode && *ControlsNode != '\0') + { + if(list_num >= acc_list.size()) + acc_list.resize(list_num+1); + + for(const char * ptr = ControlsNode; *ptr != '"' && *ptr != '\0'; ptr++) + acc_list[list_num].Name.push_back(*ptr); + + acc_list[list_num].Required = false; + + char * requiredField = strstr(ControlsNode, "required=\""); + if(requiredField && strncmp(requiredField + strlen("required=\""), "true", 4) == 0) + { + acc_list[list_num].Required = true; + } + + ControlsNode = strstr(ControlsNode, ""); + if(!ColorNode) + { + delete [] data; + return color; + } + + color = strtoul(ColorNode, NULL, 16); + + delete [] data; + + return color; +} + +bool GameTDB::GetGameType(const char * id, string &GameType) +{ + if(!id) + return false; + + char * data = GetGameNode(id); + if(!data) + return false; + + char * TypeNode = GetNodeText(data, "", ""); + if(!TypeNode) + { + delete [] data; + return false; + } + + GameType = TypeNode; + + delete [] data; + + return true; +} + +bool GameTDB::GetGameXMLInfo(const char * id, GameXMLInfo * gameInfo) +{ + if(!id || !gameInfo) + return false; + + for(int i = 0; i < 6 && id[i] != 0; ++i) + gameInfo->GameID.push_back(id[i]); + + GetTitle(id, gameInfo->Title); + GetSynopsis(id, gameInfo->Synopsis); + GetRegion(id, gameInfo->Region); + GetDeveloper(id, gameInfo->Developer); + GetPublisher(id, gameInfo->Publisher); + gameInfo->PublishDate = GetPublishDate(id); + GetGenreList(id, gameInfo->GenreList); + gameInfo->RatingType = GetRating(id); + GetRatingValue(id, gameInfo->RatingValue); + //GetRatingDescriptorList(id, gameInfo->RatingDescriptorList); We don't use it yet + gameInfo->WifiPlayers = GetWifiPlayers(id); + GetWifiFeatureList(id, gameInfo->WifiFeatureList); + gameInfo->Players = GetPlayers(id); + GetAccessoirList(id, gameInfo->AccessoirList); + gameInfo->CaseColor = GetCaseColor(id); + + return true; +} diff --git a/source/xml/GameTDB.hpp b/source/xml/GameTDB.hpp new file mode 100644 index 0000000..233bc49 --- /dev/null +++ b/source/xml/GameTDB.hpp @@ -0,0 +1,160 @@ +/**************************************************************************** + * Copyright (C) 2010 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef GAMETDB_HPP_ +#define GAMETDB_HPP_ + +#include +#include + +using namespace std; + +typedef struct _Accessoir +{ + string Name; + bool Required; +} Accessoir; + +typedef struct _GameXMLInfo +{ + string GameID; + string Region; + string Title; + string Synopsis; + string Developer; + string Publisher; + unsigned int PublishDate; + vector GenreList; + int RatingType; + string RatingValue; + vector RatingDescriptorList; + int WifiPlayers; + vector WifiFeatureList; + int Players; + vector AccessoirList; + long CaseColor; + +} GameXMLInfo; + +typedef struct _GameOffsets +{ + char gameID[7]; + unsigned int gamenode; + unsigned int nodesize; +} __attribute__((__packed__)) GameOffsets; + +class GameTDB +{ + public: + //! Constructor + GameTDB(); + //! Constructor + //! If filepath is passed the xml file is opened and the node offsets are loaded + GameTDB(const char * filepath); + //! Destructor + ~GameTDB(); + //! If filepath is passed the xml file is opened and the node offsets are loaded + bool OpenFile(const char * filepath); + //! Closes the GameTDB xml file + void CloseFile(); + //! Set the language code which should be use to find the appropriate language + //! If the language code is not found, the language code defaults to EN + void SetLanguageCode(const char * code) { if(code) LangCode = code; }; + //! Get the current set language code + const char * GetLanguageCode() { return LangCode.c_str(); }; + //! Get the title of a specific game id in the language defined in LangCode + bool GetTitle(const char * id, string & title); + //! Get the synopsis of a specific game id in the language defined in LangCode + bool GetSynopsis(const char * id, string & synopsis); + //! Get the region of a game for a specific game id + bool GetRegion(const char * id, string & region); + //! Get the developer of a game for a specific game id + bool GetDeveloper(const char * id, string & dev); + //! Get the publisher of a game for a specific game id + bool GetPublisher(const char * id, string & pub); + //! Get the publish date of a game for a specific game id + //! First 1 byte is the day, than 1 byte month and last 2 bytes is the year + //! year = (return >> 16), month = (return >> 8) & 0xFF, day = return & 0xFF + unsigned int GetPublishDate(const char * id); + //! Get the genre list of a game for a specific game id + bool GetGenreList(const char * id, vector & genre); + //! Get the rating type for a specific game id + //! The rating type can be converted to a string with GameTDB::RatingToString(rating) + int GetRating(const char * id); + //! Get the rating value for a specific game id + bool GetRatingValue(const char * id, string & rating_value); + //! Get the rating descriptor list inside a vector for a specific game id + //! Returns the amount of descriptors found or -1 if failed + int GetRatingDescriptorList(const char * id, vector & desc_list); + //! Get the wifi player count for a specific game id + //! Returns the amount of wifi players or -1 if failed + int GetWifiPlayers(const char * id); + //! Get the wifi feature list inside a vector for a specific game id + //! Returns the amount of wifi features found or -1 if failed + int GetWifiFeatureList(const char * id, vector & feat_list); + //! Get the player count for a specific game id + //! Returns the amount of players or -1 if failed + int GetPlayers(const char * id); + //! Returns the amount of accessoirs found or -1 if failed + //! Get the accessoir (inputs) list inside a vector for a specific game id + int GetAccessoirList(const char * id, vector & acc_list); + //! Get the box (case) color for a specific game id + //! Returns the color in RGB (first 3 bytes) + int GetCaseColor(const char * id); + //! Get the complete game info in the GameXMLInfo struct + bool GetGameXMLInfo(const char * id, GameXMLInfo * gameInfo); + //! Get the type of the game. If blank the game is a Wii game. + bool GetGameType(const char * id, string &GameType); + //! Translate genre list to configure language code + void TranslateGenres(vector &GenreList); + //! Translate descriptors list to configure language code + void TranslateDescriptors(vector &DescList); + //! Convert a specific game rating to a string + static const char * RatingToString(int rating); + //! Convert a rating string to a rating number + static int StringToRating(const char *rate_string); + //! Convert a rating to another rating + static int ConvertRating(const char *value, const char *from, const char *to); + //! Get the version of the gametdb xml database + unsigned long long GetGameTDBVersion(); + //! Get the entry count in the xml database + inline size_t GetEntryCount() { return OffsetMap.size(); }; + private: + bool ParseFile(); + bool LoadGameOffsets(const char * path); + bool SaveGameOffsets(const char * path); + inline int GetData(char * data, int offset, int size); + inline char * LoadGameNode(const char * id); + inline char * GetGameNode(const char * id); + inline GameOffsets * GetGameOffset(const char * id); + inline char * SeekLang(char * text, const char * langcode); + inline char * GetNodeText(char * data, const char * nodestart, const char * nodeend); + + vector OffsetMap; + FILE * file; + string LangCode; + char * GameNodeCache; + char GameIDCache[7]; +}; + +#endif diff --git a/source/xml/tinyxml2.cpp b/source/xml/tinyxml2.cpp new file mode 100644 index 0000000..9d6be5c --- /dev/null +++ b/source/xml/tinyxml2.cpp @@ -0,0 +1,2536 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml2.h" + +#include // yes, this one new style header, is in the Android SDK. +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +#else +# include +# include +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + // Microsoft Visual Studio, version 2005 and higher. Not WinCE. + /*int _snprintf_s( + char *buffer, + size_t sizeOfBuffer, + size_t count, + const char *format [, + argument] ... + );*/ + static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) + { + va_list va; + va_start( va, format ); + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + va_end( va ); + return result; + } + + static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) + { + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + return result; + } + + #define TIXML_VSCPRINTF _vscprintf + #define TIXML_SSCANF sscanf_s +#elif defined _MSC_VER + // Microsoft Visual Studio 2003 and earlier or WinCE + #define TIXML_SNPRINTF _snprintf + #define TIXML_VSNPRINTF _vsnprintf + #define TIXML_SSCANF sscanf + #if (_MSC_VER < 1400 ) && (!defined WINCE) + // Microsoft Visual Studio 2003 and not WinCE. + #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. + #else + // Microsoft Visual Studio 2003 and earlier or WinCE. + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = 512; + for (;;) { + len = len*2; + char* str = new char[len](); + const int required = _vsnprintf(str, len, format, va); + delete[] str; + if ( required != -1 ) { + TIXMLASSERT( required >= 0 ); + len = required; + break; + } + } + TIXMLASSERT( len >= 0 ); + return len; + } + #endif +#else + // GCC version 3 and higher + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_VSNPRINTF vsnprintf + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = vsnprintf( 0, 0, format, va ); + TIXMLASSERT( len >= 0 ); + return len; + } + #define TIXML_SSCANF sscanf +#endif + + +static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF +static const char LF = LINE_FEED; +static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out +static const char CR = CARRIAGE_RETURN; +static const char SINGLE_QUOTE = '\''; +static const char DOUBLE_QUOTE = '\"'; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// ef bb bf (Microsoft "lead bytes") - designates UTF-8 + +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +namespace tinyxml2 +{ + +struct Entity { + const char* pattern; + int length; + char value; +}; + +static const int NUM_ENTITIES = 5; +static const Entity entities[NUM_ENTITIES] = { + { "quot", 4, DOUBLE_QUOTE }, + { "amp", 3, '&' }, + { "apos", 4, SINGLE_QUOTE }, + { "lt", 2, '<' }, + { "gt", 2, '>' } +}; + + +StrPair::~StrPair() +{ + Reset(); +} + + +void StrPair::TransferTo( StrPair* other ) +{ + if ( this == other ) { + return; + } + // This in effect implements the assignment operator by "moving" + // ownership (as in auto_ptr). + + TIXMLASSERT( other->_flags == 0 ); + TIXMLASSERT( other->_start == 0 ); + TIXMLASSERT( other->_end == 0 ); + + other->Reset(); + + other->_flags = _flags; + other->_start = _start; + other->_end = _end; + + _flags = 0; + _start = 0; + _end = 0; +} + +void StrPair::Reset() +{ + if ( _flags & NEEDS_DELETE ) { + delete [] _start; + } + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::SetStr( const char* str, int flags ) +{ + TIXMLASSERT( str ); + Reset(); + size_t len = strlen( str ); + TIXMLASSERT( _start == 0 ); + _start = new char[ len+1 ]; + memcpy( _start, str, len+1 ); + _end = _start + len; + _flags = flags | NEEDS_DELETE; +} + + +char* StrPair::ParseText( char* p, const char* endTag, int strFlags ) +{ + TIXMLASSERT( endTag && *endTag ); + + char* start = p; + char endChar = *endTag; + size_t length = strlen( endTag ); + + // Inner loop of text parsing. + while ( *p ) { + if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { + Set( start, p, strFlags ); + return p + length; + } + ++p; + } + return 0; +} + + +char* StrPair::ParseName( char* p ) +{ + if ( !p || !(*p) ) { + return 0; + } + if ( !XMLUtil::IsNameStartChar( *p ) ) { + return 0; + } + + char* const start = p; + ++p; + while ( *p && XMLUtil::IsNameChar( *p ) ) { + ++p; + } + + Set( start, p, 0 ); + return p; +} + + +void StrPair::CollapseWhitespace() +{ + // Adjusting _start would cause undefined behavior on delete[] + TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); + // Trim leading space. + _start = XMLUtil::SkipWhiteSpace( _start ); + + if ( *_start ) { + char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( *p ) { + if ( XMLUtil::IsWhiteSpace( *p )) { + p = XMLUtil::SkipWhiteSpace( p ); + if ( *p == 0 ) { + break; // don't write to q; this trims the trailing space. + } + *q = ' '; + ++q; + } + *q = *p; + ++q; + ++p; + } + *q = 0; + } +} + + +const char* StrPair::GetStr() +{ + TIXMLASSERT( _start ); + TIXMLASSERT( _end ); + if ( _flags & NEEDS_FLUSH ) { + *_end = 0; + _flags ^= NEEDS_FLUSH; + + if ( _flags ) { + char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( p < _end ) { + if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { + // CR-LF pair becomes LF + // CR alone becomes LF + // LF-CR becomes LF + if ( *(p+1) == LF ) { + p += 2; + } + else { + ++p; + } + *q++ = LF; + } + else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { + if ( *(p+1) == CR ) { + p += 2; + } + else { + ++p; + } + *q++ = LF; + } + else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { + // Entities handled by tinyXML2: + // - special entities in the entity table [in/out] + // - numeric character reference [in] + // 中 or 中 + + if ( *(p+1) == '#' ) { + const int buflen = 10; + char buf[buflen] = { 0 }; + int len = 0; + char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); + if ( adjusted == 0 ) { + *q = *p; + ++p; + ++q; + } + else { + TIXMLASSERT( 0 <= len && len <= buflen ); + TIXMLASSERT( q + len <= adjusted ); + p = adjusted; + memcpy( q, buf, len ); + q += len; + } + } + else { + bool entityFound = false; + for( int i = 0; i < NUM_ENTITIES; ++i ) { + const Entity& entity = entities[i]; + if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 + && *( p + entity.length + 1 ) == ';' ) { + // Found an entity - convert. + *q = entity.value; + ++q; + p += entity.length + 2; + entityFound = true; + break; + } + } + if ( !entityFound ) { + // fixme: treat as error? + ++p; + ++q; + } + } + } + else { + *q = *p; + ++p; + ++q; + } + } + *q = 0; + } + // The loop below has plenty going on, and this + // is a less useful mode. Break it out. + if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) { + CollapseWhitespace(); + } + _flags = (_flags & NEEDS_DELETE); + } + TIXMLASSERT( _start ); + return _start; +} + + + + +// --------- XMLUtil ----------- // + +const char* XMLUtil::ReadBOM( const char* p, bool* bom ) +{ + TIXMLASSERT( p ); + TIXMLASSERT( bom ); + *bom = false; + const unsigned char* pu = reinterpret_cast(p); + // Check for BOM: + if ( *(pu+0) == TIXML_UTF_LEAD_0 + && *(pu+1) == TIXML_UTF_LEAD_1 + && *(pu+2) == TIXML_UTF_LEAD_2 ) { + *bom = true; + p += 3; + } + TIXMLASSERT( p ); + return p; +} + + +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) { + *length = 1; + } + else if ( input < 0x800 ) { + *length = 2; + } + else if ( input < 0x10000 ) { + *length = 3; + } + else if ( input < 0x200000 ) { + *length = 4; + } + else { + *length = 0; // This code won't convert this correctly anyway. + return; + } + + output += *length; + + // Scary scary fall throughs. + switch (*length) { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + break; + default: + TIXMLASSERT( false ); + } +} + + +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) +{ + // Presume an entity, and pull it out. + *length = 0; + + if ( *(p+1) == '#' && *(p+2) ) { + unsigned long ucs = 0; + TIXMLASSERT( sizeof( ucs ) >= 4 ); + ptrdiff_t delta = 0; + unsigned mult = 1; + static const char SEMICOLON = ';'; + + if ( *(p+2) == 'x' ) { + // Hexadecimal. + const char* q = p+3; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != 'x' ) { + unsigned int digit = 0; + + if ( *q >= '0' && *q <= '9' ) { + digit = *q - '0'; + } + else if ( *q >= 'a' && *q <= 'f' ) { + digit = *q - 'a' + 10; + } + else if ( *q >= 'A' && *q <= 'F' ) { + digit = *q - 'A' + 10; + } + else { + return 0; + } + TIXMLASSERT( digit < 16 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + TIXMLASSERT( mult <= UINT_MAX / 16 ); + mult *= 16; + --q; + } + } + else { + // Decimal. + const char* q = p+2; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != '#' ) { + if ( *q >= '0' && *q <= '9' ) { + const unsigned int digit = *q - '0'; + TIXMLASSERT( digit < 10 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + } + else { + return 0; + } + TIXMLASSERT( mult <= UINT_MAX / 10 ); + mult *= 10; + --q; + } + } + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + return p + delta + 1; + } + return p+1; +} + + +void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); +} + + +void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); +} + + +void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 ); +} + +/* + ToStr() of a number is a very tricky topic. + https://github.com/leethomason/tinyxml2/issues/106 +*/ +void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); +} + + +void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); +} + + +void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize) +{ + // horrible syntax trick to make the compiler happy about %lld + TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v); +} + + +bool XMLUtil::ToInt( const char* str, int* value ) +{ + if ( TIXML_SSCANF( str, "%d", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToUnsigned( const char* str, unsigned *value ) +{ + if ( TIXML_SSCANF( str, "%u", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToBool( const char* str, bool* value ) +{ + int ival = 0; + if ( ToInt( str, &ival )) { + *value = (ival==0) ? false : true; + return true; + } + if ( StringEqual( str, "true" ) ) { + *value = true; + return true; + } + else if ( StringEqual( str, "false" ) ) { + *value = false; + return true; + } + return false; +} + + +bool XMLUtil::ToFloat( const char* str, float* value ) +{ + if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { + return true; + } + return false; +} + + +bool XMLUtil::ToDouble( const char* str, double* value ) +{ + if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { + return true; + } + return false; +} + + +bool XMLUtil::ToInt64(const char* str, int64_t* value) +{ + long long v = 0; // horrible syntax trick to make the compiler happy about %lld + if (TIXML_SSCANF(str, "%lld", &v) == 1) { + *value = (int64_t)v; + return true; + } + return false; +} + + +char* XMLDocument::Identify( char* p, XMLNode** node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( p ); + char* const start = p; + p = XMLUtil::SkipWhiteSpace( p ); + if( !*p ) { + *node = 0; + TIXMLASSERT( p ); + return p; + } + + // These strings define the matching patterns: + static const char* xmlHeader = { "_memPool = &_commentPool; + p += xmlHeaderLen; + } + else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); + returnNode = new (_commentPool.Alloc()) XMLComment( this ); + returnNode->_memPool = &_commentPool; + p += commentHeaderLen; + } + else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); + XMLText* text = new (_textPool.Alloc()) XMLText( this ); + returnNode = text; + returnNode->_memPool = &_textPool; + p += cdataHeaderLen; + text->SetCData( true ); + } + else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); + returnNode = new (_commentPool.Alloc()) XMLUnknown( this ); + returnNode->_memPool = &_commentPool; + p += dtdHeaderLen; + } + else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); + returnNode = new (_elementPool.Alloc()) XMLElement( this ); + returnNode->_memPool = &_elementPool; + p += elementHeaderLen; + } + else { + TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); + returnNode = new (_textPool.Alloc()) XMLText( this ); + returnNode->_memPool = &_textPool; + p = start; // Back it up, all the text counts. + } + + TIXMLASSERT( returnNode ); + TIXMLASSERT( p ); + *node = returnNode; + return p; +} + + +bool XMLDocument::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLNode ----------- // + +XMLNode::XMLNode( XMLDocument* doc ) : + _document( doc ), + _parent( 0 ), + _firstChild( 0 ), _lastChild( 0 ), + _prev( 0 ), _next( 0 ), + _userData( 0 ), + _memPool( 0 ) +{ +} + + +XMLNode::~XMLNode() +{ + DeleteChildren(); + if ( _parent ) { + _parent->Unlink( this ); + } +} + +const char* XMLNode::Value() const +{ + // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr. + if ( this->ToDocument() ) + return 0; + return _value.GetStr(); +} + +void XMLNode::SetValue( const char* str, bool staticMem ) +{ + if ( staticMem ) { + _value.SetInternedStr( str ); + } + else { + _value.SetStr( str ); + } +} + + +void XMLNode::DeleteChildren() +{ + while( _firstChild ) { + TIXMLASSERT( _lastChild ); + TIXMLASSERT( _firstChild->_document == _document ); + XMLNode* node = _firstChild; + Unlink( node ); + + DeleteNode( node ); + } + _firstChild = _lastChild = 0; +} + + +void XMLNode::Unlink( XMLNode* child ) +{ + TIXMLASSERT( child ); + TIXMLASSERT( child->_document == _document ); + TIXMLASSERT( child->_parent == this ); + if ( child == _firstChild ) { + _firstChild = _firstChild->_next; + } + if ( child == _lastChild ) { + _lastChild = _lastChild->_prev; + } + + if ( child->_prev ) { + child->_prev->_next = child->_next; + } + if ( child->_next ) { + child->_next->_prev = child->_prev; + } + child->_parent = 0; +} + + +void XMLNode::DeleteChild( XMLNode* node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( node->_document == _document ); + TIXMLASSERT( node->_parent == this ); + Unlink( node ); + DeleteNode( node ); +} + + +XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _lastChild ) { + TIXMLASSERT( _firstChild ); + TIXMLASSERT( _lastChild->_next == 0 ); + _lastChild->_next = addThis; + addThis->_prev = _lastChild; + _lastChild = addThis; + + addThis->_next = 0; + } + else { + TIXMLASSERT( _firstChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _firstChild ) { + TIXMLASSERT( _lastChild ); + TIXMLASSERT( _firstChild->_prev == 0 ); + + _firstChild->_prev = addThis; + addThis->_next = _firstChild; + _firstChild = addThis; + + addThis->_prev = 0; + } + else { + TIXMLASSERT( _lastChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + + TIXMLASSERT( afterThis ); + + if ( afterThis->_parent != this ) { + TIXMLASSERT( false ); + return 0; + } + + if ( afterThis->_next == 0 ) { + // The last node or the only node. + return InsertEndChild( addThis ); + } + InsertChildPreamble( addThis ); + addThis->_prev = afterThis; + addThis->_next = afterThis->_next; + afterThis->_next->_prev = addThis; + afterThis->_next = addThis; + addThis->_parent = this; + return addThis; +} + + + + +const XMLElement* XMLNode::FirstChildElement( const char* name ) const +{ + for( const XMLNode* node = _firstChild; node; node = node->_next ) { + const XMLElement* element = node->ToElement(); + if ( element ) { + if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { + return element; + } + } + } + return 0; +} + + +const XMLElement* XMLNode::LastChildElement( const char* name ) const +{ + for( const XMLNode* node = _lastChild; node; node = node->_prev ) { + const XMLElement* element = node->ToElement(); + if ( element ) { + if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { + return element; + } + } + } + return 0; +} + + +const XMLElement* XMLNode::NextSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _next; node; node = node->_next ) { + const XMLElement* element = node->ToElement(); + if ( element + && (!name || XMLUtil::StringEqual( name, element->Name() ))) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _prev; node; node = node->_prev ) { + const XMLElement* element = node->ToElement(); + if ( element + && (!name || XMLUtil::StringEqual( name, element->Name() ))) { + return element; + } + } + return 0; +} + + +char* XMLNode::ParseDeep( char* p, StrPair* parentEnd ) +{ + // This is a recursive method, but thinking about it "at the current level" + // it is a pretty simple flat list: + // + // + // + // With a special case: + // + // + // + // + // Where the closing element (/foo) *must* be the next thing after the opening + // element, and the names must match. BUT the tricky bit is that the closing + // element will be read by the child. + // + // 'endTag' is the end tag for this node, it is returned by a call to a child. + // 'parentEnd' is the end tag for the parent, which is filled in and returned. + + while( p && *p ) { + XMLNode* node = 0; + + p = _document->Identify( p, &node ); + if ( node == 0 ) { + break; + } + + StrPair endTag; + p = node->ParseDeep( p, &endTag ); + if ( !p ) { + DeleteNode( node ); + if ( !_document->Error() ) { + _document->SetError( XML_ERROR_PARSING, 0, 0 ); + } + break; + } + + XMLDeclaration* decl = node->ToDeclaration(); + if ( decl ) { + // A declaration can only be the first child of a document. + // Set error, if document already has children. + if ( !_document->NoChildren() ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0); + DeleteNode( decl ); + break; + } + } + + XMLElement* ele = node->ToElement(); + if ( ele ) { + // We read the end tag. Return it to the parent. + if ( ele->ClosingType() == XMLElement::CLOSING ) { + if ( parentEnd ) { + ele->_value.TransferTo( parentEnd ); + } + node->_memPool->SetTracked(); // created and then immediately deleted. + DeleteNode( node ); + return p; + } + + // Handle an end tag returned to this level. + // And handle a bunch of annoying errors. + bool mismatch = false; + if ( endTag.Empty() ) { + if ( ele->ClosingType() == XMLElement::OPEN ) { + mismatch = true; + } + } + else { + if ( ele->ClosingType() != XMLElement::OPEN ) { + mismatch = true; + } + else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { + mismatch = true; + } + } + if ( mismatch ) { + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 ); + DeleteNode( node ); + break; + } + } + InsertEndChild( node ); + } + return 0; +} + +void XMLNode::DeleteNode( XMLNode* node ) +{ + if ( node == 0 ) { + return; + } + MemPool* pool = node->_memPool; + node->~XMLNode(); + pool->Free( node ); +} + +void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const +{ + TIXMLASSERT( insertThis ); + TIXMLASSERT( insertThis->_document == _document ); + + if ( insertThis->_parent ) + insertThis->_parent->Unlink( insertThis ); + else + insertThis->_memPool->SetTracked(); +} + +// --------- XMLText ---------- // +char* XMLText::ParseDeep( char* p, StrPair* ) +{ + const char* start = p; + if ( this->CData() ) { + p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 ); + } + return p; + } + else { + int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; + if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { + flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; + } + + p = _value.ParseText( p, "<", flags ); + if ( p && *p ) { + return p-1; + } + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 ); + } + } + return 0; +} + + +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? + text->SetCData( this->CData() ); + return text; +} + + +bool XMLText::ShallowEqual( const XMLNode* compare ) const +{ + const XMLText* text = compare->ToText(); + return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); +} + + +bool XMLText::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLComment ---------- // + +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLComment::~XMLComment() +{ +} + + +char* XMLComment::ParseDeep( char* p, StrPair* ) +{ + // Comment parses as text. + const char* start = p; + p = _value.ParseText( p, "-->", StrPair::COMMENT ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 ); + } + return p; +} + + +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? + return comment; +} + + +bool XMLComment::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLComment* comment = compare->ToComment(); + return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); +} + + +bool XMLComment::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLDeclaration ---------- // + +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLDeclaration::~XMLDeclaration() +{ + //printf( "~XMLDeclaration\n" ); +} + + +char* XMLDeclaration::ParseDeep( char* p, StrPair* ) +{ + // Declaration parses as text. + const char* start = p; + p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 ); + } + return p; +} + + +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? + return dec; +} + + +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLDeclaration* declaration = compare->ToDeclaration(); + return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); +} + + + +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLUnknown ---------- // + +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLUnknown::~XMLUnknown() +{ +} + + +char* XMLUnknown::ParseDeep( char* p, StrPair* ) +{ + // Unknown parses as text. + const char* start = p; + + p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 ); + } + return p; +} + + +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? + return text; +} + + +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLUnknown* unknown = compare->ToUnknown(); + return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); +} + + +bool XMLUnknown::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLAttribute ---------- // + +const char* XMLAttribute::Name() const +{ + return _name.GetStr(); +} + +const char* XMLAttribute::Value() const +{ + return _value.GetStr(); +} + +char* XMLAttribute::ParseDeep( char* p, bool processEntities ) +{ + // Parse using the name rules: bug fix, was using ParseText before + p = _name.ParseName( p ); + if ( !p || !*p ) { + return 0; + } + + // Skip white space before = + p = XMLUtil::SkipWhiteSpace( p ); + if ( *p != '=' ) { + return 0; + } + + ++p; // move up to opening quote + p = XMLUtil::SkipWhiteSpace( p ); + if ( *p != '\"' && *p != '\'' ) { + return 0; + } + + char endTag[2] = { *p, 0 }; + ++p; // move past opening quote + + p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES ); + return p; +} + + +void XMLAttribute::SetName( const char* n ) +{ + _name.SetStr( n ); +} + + +XMLError XMLAttribute::QueryIntValue( int* value ) const +{ + if ( XMLUtil::ToInt( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const +{ + if ( XMLUtil::ToUnsigned( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryInt64Value(int64_t* value) const +{ + if (XMLUtil::ToInt64(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryBoolValue( bool* value ) const +{ + if ( XMLUtil::ToBool( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryFloatValue( float* value ) const +{ + if ( XMLUtil::ToFloat( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryDoubleValue( double* value ) const +{ + if ( XMLUtil::ToDouble( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +void XMLAttribute::SetAttribute( const char* v ) +{ + _value.SetStr( v ); +} + + +void XMLAttribute::SetAttribute( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute(int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); +} + + + +void XMLAttribute::SetAttribute( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +// --------- XMLElement ---------- // +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), + _closingType( 0 ), + _rootAttribute( 0 ) +{ +} + + +XMLElement::~XMLElement() +{ + while( _rootAttribute ) { + XMLAttribute* next = _rootAttribute->_next; + DeleteAttribute( _rootAttribute ); + _rootAttribute = next; + } +} + + +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const +{ + for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { + if ( XMLUtil::StringEqual( a->Name(), name ) ) { + return a; + } + } + return 0; +} + + +const char* XMLElement::Attribute( const char* name, const char* value ) const +{ + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return 0; + } + if ( !value || XMLUtil::StringEqual( a->Value(), value )) { + return a->Value(); + } + return 0; +} + + +const char* XMLElement::GetText() const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + return FirstChild()->Value(); + } + return 0; +} + + +void XMLElement::SetText( const char* inText ) +{ + if ( FirstChild() && FirstChild()->ToText() ) + FirstChild()->SetValue( inText ); + else { + XMLText* theText = GetDocument()->NewText( inText ); + InsertFirstChild( theText ); + } +} + + +void XMLElement::SetText( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText(int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); +} + + +void XMLElement::SetText( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +XMLError XMLElement::QueryIntText( int* ival ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToInt( t, ival ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToUnsigned( t, uval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryInt64Text(int64_t* ival) const +{ + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToInt64(t, ival)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryBoolText( bool* bval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToBool( t, bval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryDoubleText( double* dval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToDouble( t, dval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryFloatText( float* fval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToFloat( t, fval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + + +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) +{ + XMLAttribute* last = 0; + XMLAttribute* attrib = 0; + for( attrib = _rootAttribute; + attrib; + last = attrib, attrib = attrib->_next ) { + if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { + break; + } + } + if ( !attrib ) { + TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); + attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + attrib->_memPool = &_document->_attributePool; + if ( last ) { + last->_next = attrib; + } + else { + _rootAttribute = attrib; + } + attrib->SetName( name ); + attrib->_memPool->SetTracked(); // always created and linked. + } + return attrib; +} + + +void XMLElement::DeleteAttribute( const char* name ) +{ + XMLAttribute* prev = 0; + for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { + if ( XMLUtil::StringEqual( name, a->Name() ) ) { + if ( prev ) { + prev->_next = a->_next; + } + else { + _rootAttribute = a->_next; + } + DeleteAttribute( a ); + break; + } + prev = a; + } +} + + +char* XMLElement::ParseAttributes( char* p ) +{ + const char* start = p; + XMLAttribute* prevAttribute = 0; + + // Read the attributes. + while( p ) { + p = XMLUtil::SkipWhiteSpace( p ); + if ( !(*p) ) { + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() ); + return 0; + } + + // attribute. + if (XMLUtil::IsNameStartChar( *p ) ) { + TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); + XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + attrib->_memPool = &_document->_attributePool; + attrib->_memPool->SetTracked(); + + p = attrib->ParseDeep( p, _document->ProcessEntities() ); + if ( !p || Attribute( attrib->Name() ) ) { + DeleteAttribute( attrib ); + _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p ); + return 0; + } + // There is a minor bug here: if the attribute in the source xml + // document is duplicated, it will not be detected and the + // attribute will be doubly added. However, tracking the 'prevAttribute' + // avoids re-scanning the attribute list. Preferring performance for + // now, may reconsider in the future. + if ( prevAttribute ) { + prevAttribute->_next = attrib; + } + else { + _rootAttribute = attrib; + } + prevAttribute = attrib; + } + // end of the tag + else if ( *p == '>' ) { + ++p; + break; + } + // end of the tag + else if ( *p == '/' && *(p+1) == '>' ) { + _closingType = CLOSED; + return p+2; // done; sealed element. + } + else { + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p ); + return 0; + } + } + return p; +} + +void XMLElement::DeleteAttribute( XMLAttribute* attribute ) +{ + if ( attribute == 0 ) { + return; + } + MemPool* pool = attribute->_memPool; + attribute->~XMLAttribute(); + pool->Free( attribute ); +} + +// +// +// foobar +// +char* XMLElement::ParseDeep( char* p, StrPair* strPair ) +{ + // Read the element name. + p = XMLUtil::SkipWhiteSpace( p ); + + // The closing element is the form. It is + // parsed just like a regular element then deleted from + // the DOM. + if ( *p == '/' ) { + _closingType = CLOSING; + ++p; + } + + p = _value.ParseName( p ); + if ( _value.Empty() ) { + return 0; + } + + p = ParseAttributes( p ); + if ( !p || !*p || _closingType ) { + return p; + } + + p = XMLNode::ParseDeep( p, strPair ); + return p; +} + + + +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? + for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { + element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? + } + return element; +} + + +bool XMLElement::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLElement* other = compare->ToElement(); + if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { + + const XMLAttribute* a=FirstAttribute(); + const XMLAttribute* b=other->FirstAttribute(); + + while ( a && b ) { + if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { + return false; + } + a = a->Next(); + b = b->Next(); + } + if ( a || b ) { + // different count + return false; + } + return true; + } + return false; +} + + +bool XMLElement::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this, _rootAttribute ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLDocument ----------- // + +// Warning: List must match 'enum XMLError' +const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { + "XML_SUCCESS", + "XML_NO_ATTRIBUTE", + "XML_WRONG_ATTRIBUTE_TYPE", + "XML_ERROR_FILE_NOT_FOUND", + "XML_ERROR_FILE_COULD_NOT_BE_OPENED", + "XML_ERROR_FILE_READ_ERROR", + "XML_ERROR_ELEMENT_MISMATCH", + "XML_ERROR_PARSING_ELEMENT", + "XML_ERROR_PARSING_ATTRIBUTE", + "XML_ERROR_IDENTIFYING_TAG", + "XML_ERROR_PARSING_TEXT", + "XML_ERROR_PARSING_CDATA", + "XML_ERROR_PARSING_COMMENT", + "XML_ERROR_PARSING_DECLARATION", + "XML_ERROR_PARSING_UNKNOWN", + "XML_ERROR_EMPTY_DOCUMENT", + "XML_ERROR_MISMATCHED_ELEMENT", + "XML_ERROR_PARSING", + "XML_CAN_NOT_CONVERT_TEXT", + "XML_NO_TEXT_NODE" +}; + + +XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) : + XMLNode( 0 ), + _writeBOM( false ), + _processEntities( processEntities ), + _errorID(XML_SUCCESS), + _whitespace( whitespace ), + _errorStr1( 0 ), + _errorStr2( 0 ), + _charBuffer( 0 ) +{ + // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) + _document = this; +} + + +XMLDocument::~XMLDocument() +{ + Clear(); +} + + +void XMLDocument::Clear() +{ + DeleteChildren(); + +#ifdef DEBUG + const bool hadError = Error(); +#endif + _errorID = XML_SUCCESS; + _errorStr1 = 0; + _errorStr2 = 0; + + delete [] _charBuffer; + _charBuffer = 0; + +#if 0 + _textPool.Trace( "text" ); + _elementPool.Trace( "element" ); + _commentPool.Trace( "comment" ); + _attributePool.Trace( "attribute" ); +#endif + +#ifdef DEBUG + if ( !hadError ) { + TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); + TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); + TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); + TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); + } +#endif +} + + +XMLElement* XMLDocument::NewElement( const char* name ) +{ + TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); + XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this ); + ele->_memPool = &_elementPool; + ele->SetName( name ); + return ele; +} + + +XMLComment* XMLDocument::NewComment( const char* str ) +{ + TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); + XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this ); + comment->_memPool = &_commentPool; + comment->SetValue( str ); + return comment; +} + + +XMLText* XMLDocument::NewText( const char* str ) +{ + TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); + XMLText* text = new (_textPool.Alloc()) XMLText( this ); + text->_memPool = &_textPool; + text->SetValue( str ); + return text; +} + + +XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) +{ + TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() ); + XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this ); + dec->_memPool = &_commentPool; + dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); + return dec; +} + + +XMLUnknown* XMLDocument::NewUnknown( const char* str ) +{ + TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); + XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this ); + unk->_memPool = &_commentPool; + unk->SetValue( str ); + return unk; +} + +static FILE* callfopen( const char* filepath, const char* mode ) +{ + TIXMLASSERT( filepath ); + TIXMLASSERT( mode ); +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + FILE* fp = 0; + errno_t err = fopen_s( &fp, filepath, mode ); + if ( err ) { + return 0; + } +#else + FILE* fp = fopen( filepath, mode ); +#endif + return fp; +} + +void XMLDocument::DeleteNode( XMLNode* node ) { + TIXMLASSERT( node ); + TIXMLASSERT(node->_document == this ); + if (node->_parent) { + node->_parent->DeleteChild( node ); + } + else { + // Isn't in the tree. + // Use the parent delete. + // Also, we need to mark it tracked: we 'know' + // it was never used. + node->_memPool->SetTracked(); + // Call the static XMLNode version: + XMLNode::DeleteNode(node); + } +} + + +XMLError XMLDocument::LoadFile( const char* filename ) +{ + Clear(); + FILE* fp = callfopen( filename, "rb" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 ); + return _errorID; + } + LoadFile( fp ); + fclose( fp ); + return _errorID; +} + +// This is likely overengineered template art to have a check that unsigned long value incremented +// by one still fits into size_t. If size_t type is larger than unsigned long type +// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit +// -Wtype-limits warning. This piece makes the compiler select code with a check when a check +// is useful and code with no check when a check is redundant depending on how size_t and unsigned long +// types sizes relate to each other. +template += sizeof(size_t))> +struct LongFitsIntoSizeTMinusOne { + static bool Fits( unsigned long value ) + { + return value < (size_t)-1; + } +}; + +template <> +struct LongFitsIntoSizeTMinusOne { + static bool Fits( unsigned long ) + { + return true; + } +}; + +XMLError XMLDocument::LoadFile( FILE* fp ) +{ + Clear(); + + fseek( fp, 0, SEEK_SET ); + if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + fseek( fp, 0, SEEK_END ); + const long filelength = ftell( fp ); + fseek( fp, 0, SEEK_SET ); + if ( filelength == -1L ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + TIXMLASSERT( filelength >= 0 ); + + if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) { + // Cannot handle files which won't fit in buffer together with null terminator + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + if ( filelength == 0 ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + + const size_t size = filelength; + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[size+1]; + size_t read = fread( _charBuffer, 1, size, fp ); + if ( read != size ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + _charBuffer[size] = 0; + + Parse(); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( const char* filename, bool compact ) +{ + FILE* fp = callfopen( filename, "w" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 ); + return _errorID; + } + SaveFile(fp, compact); + fclose( fp ); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) +{ + // Clear any error from the last save, otherwise it will get reported + // for *this* call. + SetError(XML_SUCCESS, 0, 0); + XMLPrinter stream( fp, compact ); + Print( &stream ); + return _errorID; +} + + +XMLError XMLDocument::Parse( const char* p, size_t len ) +{ + Clear(); + + if ( len == 0 || !p || !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + if ( len == (size_t)(-1) ) { + len = strlen( p ); + } + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[ len+1 ]; + memcpy( _charBuffer, p, len ); + _charBuffer[len] = 0; + + Parse(); + if ( Error() ) { + // clean up now essentially dangling memory. + // and the parse fail can put objects in the + // pools that are dead and inaccessible. + DeleteChildren(); + _elementPool.Clear(); + _attributePool.Clear(); + _textPool.Clear(); + _commentPool.Clear(); + } + return _errorID; +} + + +void XMLDocument::Print( XMLPrinter* streamer ) const +{ + if ( streamer ) { + Accept( streamer ); + } + else { + XMLPrinter stdoutStreamer( stdout ); + Accept( &stdoutStreamer ); + } +} + + +void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 ) +{ + TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); + _errorID = error; + _errorStr1 = str1; + _errorStr2 = str2; +} + +const char* XMLDocument::ErrorName() const +{ + TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT ); + const char* errorName = _errorNames[_errorID]; + TIXMLASSERT( errorName && errorName[0] ); + return errorName; +} + +void XMLDocument::PrintError() const +{ + if ( Error() ) { + static const int LEN = 20; + char buf1[LEN] = { 0 }; + char buf2[LEN] = { 0 }; + + if ( _errorStr1 ) { + TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 ); + } + if ( _errorStr2 ) { + TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 ); + } + + // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that + // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning + TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX ); + printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n", + static_cast( _errorID ), ErrorName(), buf1, buf2 ); + } +} + +void XMLDocument::Parse() +{ + TIXMLASSERT( NoChildren() ); // Clear() must have been called previously + TIXMLASSERT( _charBuffer ); + char* p = _charBuffer; + p = XMLUtil::SkipWhiteSpace( p ); + p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); + if ( !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return; + } + ParseDeep(p, 0 ); +} + +XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : + _elementJustOpened( false ), + _firstElement( true ), + _fp( file ), + _depth( depth ), + _textDepth( -1 ), + _processEntities( true ), + _compactMode( compact ) +{ + for( int i=0; i'] = true; // not required, but consistency is nice + _buffer.Push( 0 ); +} + + +void XMLPrinter::Print( const char* format, ... ) +{ + va_list va; + va_start( va, format ); + + if ( _fp ) { + vfprintf( _fp, format, va ); + } + else { + const int len = TIXML_VSCPRINTF( format, va ); + // Close out and re-start the va-args + va_end( va ); + TIXMLASSERT( len >= 0 ); + va_start( va, format ); + TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); + char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. + TIXML_VSNPRINTF( p, len+1, format, va ); + } + va_end( va ); +} + + +void XMLPrinter::PrintSpace( int depth ) +{ + for( int i=0; i 0 && *q < ENTITY_RANGE ) { + // Check for entities. If one is found, flush + // the stream up until the entity, write the + // entity, and keep looking. + if ( flag[(unsigned char)(*q)] ) { + while ( p < q ) { + const size_t delta = q - p; + // %.*s accepts type int as "precision" + const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta; + Print( "%.*s", toPrint, p ); + p += toPrint; + } + bool entityPatternPrinted = false; + for( int i=0; i" ); + } + else { + if ( _textDepth < 0 && !compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + Print( "", name ); + } + + if ( _textDepth == _depth ) { + _textDepth = -1; + } + if ( _depth == 0 && !compactMode) { + Print( "\n" ); + } + _elementJustOpened = false; +} + + +void XMLPrinter::SealElementIfJustOpened() +{ + if ( !_elementJustOpened ) { + return; + } + _elementJustOpened = false; + Print( ">" ); +} + + +void XMLPrinter::PushText( const char* text, bool cdata ) +{ + _textDepth = _depth-1; + + SealElementIfJustOpened(); + if ( cdata ) { + Print( "", text ); + } + else { + PrintString( text, true ); + } +} + +void XMLPrinter::PushText( int value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( unsigned value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( bool value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( float value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( double value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushComment( const char* comment ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "", comment ); +} + + +void XMLPrinter::PushDeclaration( const char* value ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "", value ); +} + + +void XMLPrinter::PushUnknown( const char* value ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "", value ); +} + + +bool XMLPrinter::VisitEnter( const XMLDocument& doc ) +{ + _processEntities = doc.ProcessEntities(); + if ( doc.HasBOM() ) { + PushHeader( true, false ); + } + return true; +} + + +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) +{ + const XMLElement* parentElem = 0; + if ( element.Parent() ) { + parentElem = element.Parent()->ToElement(); + } + const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; + OpenElement( element.Name(), compactMode ); + while ( attribute ) { + PushAttribute( attribute->Name(), attribute->Value() ); + attribute = attribute->Next(); + } + return true; +} + + +bool XMLPrinter::VisitExit( const XMLElement& element ) +{ + CloseElement( CompactMode(element) ); + return true; +} + + +bool XMLPrinter::Visit( const XMLText& text ) +{ + PushText( text.Value(), text.CData() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLComment& comment ) +{ + PushComment( comment.Value() ); + return true; +} + +bool XMLPrinter::Visit( const XMLDeclaration& declaration ) +{ + PushDeclaration( declaration.Value() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLUnknown& unknown ) +{ + PushUnknown( unknown.Value() ); + return true; +} + +} // namespace tinyxml2 + diff --git a/source/xml/tinyxml2.h b/source/xml/tinyxml2.h new file mode 100644 index 0000000..fb4376d --- /dev/null +++ b/source/xml/tinyxml2.h @@ -0,0 +1,2170 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef TINYXML2_INCLUDED +#define TINYXML2_INCLUDED + +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +# include +# include +# include +# if defined(__PS3__) +# include +# endif +#else +# include +# include +# include +# include +# include +#endif +#include + +/* + TODO: intern strings instead of allocation. +*/ +/* + gcc: + g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe + + Formatting, Artistic Style: + AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h +*/ + +#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__) +# ifndef DEBUG +# define DEBUG +# endif +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4251) +#endif + +#ifdef _WIN32 +# ifdef TINYXML2_EXPORT +# define TINYXML2_LIB __declspec(dllexport) +# elif defined(TINYXML2_IMPORT) +# define TINYXML2_LIB __declspec(dllimport) +# else +# define TINYXML2_LIB +# endif +#else +# define TINYXML2_LIB +#endif + + +#if defined(DEBUG) +# if defined(_MSC_VER) +# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like +# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } +# elif defined (ANDROID_NDK) +# include +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# else +# include +# define TIXMLASSERT assert +# endif +#else +# define TIXMLASSERT( x ) {} +#endif + + +/* Versioning, past 1.0.14: + http://semver.org/ +*/ +static const int TIXML2_MAJOR_VERSION = 4; +static const int TIXML2_MINOR_VERSION = 0; +static const int TIXML2_PATCH_VERSION = 1; + +namespace tinyxml2 +{ +class XMLDocument; +class XMLElement; +class XMLAttribute; +class XMLComment; +class XMLText; +class XMLDeclaration; +class XMLUnknown; +class XMLPrinter; + +/* + A class that wraps strings. Normally stores the start and end + pointers into the XML file itself, and will apply normalization + and entity translation if actually read. Can also store (and memory + manage) a traditional char[] +*/ +class StrPair +{ +public: + enum { + NEEDS_ENTITY_PROCESSING = 0x01, + NEEDS_NEWLINE_NORMALIZATION = 0x02, + NEEDS_WHITESPACE_COLLAPSING = 0x04, + + TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_NAME = 0, + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + COMMENT = NEEDS_NEWLINE_NORMALIZATION + }; + + StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} + ~StrPair(); + + void Set( char* start, char* end, int flags ) { + Reset(); + _start = start; + _end = end; + _flags = flags | NEEDS_FLUSH; + } + + const char* GetStr(); + + bool Empty() const { + return _start == _end; + } + + void SetInternedStr( const char* str ) { + Reset(); + _start = const_cast(str); + } + + void SetStr( const char* str, int flags=0 ); + + char* ParseText( char* in, const char* endTag, int strFlags ); + char* ParseName( char* in ); + + void TransferTo( StrPair* other ); + +private: + void Reset(); + void CollapseWhitespace(); + + enum { + NEEDS_FLUSH = 0x100, + NEEDS_DELETE = 0x200 + }; + + int _flags; + char* _start; + char* _end; + + StrPair( const StrPair& other ); // not supported + void operator=( StrPair& other ); // not supported, use TransferTo() +}; + + +/* + A dynamic array of Plain Old Data. Doesn't support constructors, etc. + Has a small initial memory pool, so that low or no usage will not + cause a call to new/delete +*/ +template +class DynArray +{ +public: + DynArray() { + _mem = _pool; + _allocated = INITIAL_SIZE; + _size = 0; + } + + ~DynArray() { + if ( _mem != _pool ) { + delete [] _mem; + } + } + + void Clear() { + _size = 0; + } + + void Push( T t ) { + TIXMLASSERT( _size < INT_MAX ); + EnsureCapacity( _size+1 ); + _mem[_size++] = t; + } + + T* PushArr( int count ) { + TIXMLASSERT( count >= 0 ); + TIXMLASSERT( _size <= INT_MAX - count ); + EnsureCapacity( _size+count ); + T* ret = &_mem[_size]; + _size += count; + return ret; + } + + T Pop() { + TIXMLASSERT( _size > 0 ); + return _mem[--_size]; + } + + void PopArr( int count ) { + TIXMLASSERT( _size >= count ); + _size -= count; + } + + bool Empty() const { + return _size == 0; + } + + T& operator[](int i) { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& operator[](int i) const { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& PeekTop() const { + TIXMLASSERT( _size > 0 ); + return _mem[ _size - 1]; + } + + int Size() const { + TIXMLASSERT( _size >= 0 ); + return _size; + } + + int Capacity() const { + TIXMLASSERT( _allocated >= INITIAL_SIZE ); + return _allocated; + } + + const T* Mem() const { + TIXMLASSERT( _mem ); + return _mem; + } + + T* Mem() { + TIXMLASSERT( _mem ); + return _mem; + } + +private: + DynArray( const DynArray& ); // not supported + void operator=( const DynArray& ); // not supported + + void EnsureCapacity( int cap ) { + TIXMLASSERT( cap > 0 ); + if ( cap > _allocated ) { + TIXMLASSERT( cap <= INT_MAX / 2 ); + int newAllocated = cap * 2; + T* newMem = new T[newAllocated]; + memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs + if ( _mem != _pool ) { + delete [] _mem; + } + _mem = newMem; + _allocated = newAllocated; + } + } + + T* _mem; + T _pool[INITIAL_SIZE]; + int _allocated; // objects allocated + int _size; // number objects in use +}; + + +/* + Parent virtual class of a pool for fast allocation + and deallocation of objects. +*/ +class MemPool +{ +public: + MemPool() {} + virtual ~MemPool() {} + + virtual int ItemSize() const = 0; + virtual void* Alloc() = 0; + virtual void Free( void* ) = 0; + virtual void SetTracked() = 0; + virtual void Clear() = 0; +}; + + +/* + Template child class to create pools of the correct type. +*/ +template< int SIZE > +class MemPoolT : public MemPool +{ +public: + MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} + ~MemPoolT() { + Clear(); + } + + void Clear() { + // Delete the blocks. + while( !_blockPtrs.Empty()) { + Block* b = _blockPtrs.Pop(); + delete b; + } + _root = 0; + _currentAllocs = 0; + _nAllocs = 0; + _maxAllocs = 0; + _nUntracked = 0; + } + + virtual int ItemSize() const { + return SIZE; + } + int CurrentAllocs() const { + return _currentAllocs; + } + + virtual void* Alloc() { + if ( !_root ) { + // Need a new block. + Block* block = new Block(); + _blockPtrs.Push( block ); + + for( int i=0; ichunk[i].next = &block->chunk[i+1]; + } + block->chunk[COUNT-1].next = 0; + _root = block->chunk; + } + void* result = _root; + _root = _root->next; + + ++_currentAllocs; + if ( _currentAllocs > _maxAllocs ) { + _maxAllocs = _currentAllocs; + } + _nAllocs++; + _nUntracked++; + return result; + } + + virtual void Free( void* mem ) { + if ( !mem ) { + return; + } + --_currentAllocs; + Chunk* chunk = static_cast( mem ); +#ifdef DEBUG + memset( chunk, 0xfe, sizeof(Chunk) ); +#endif + chunk->next = _root; + _root = chunk; + } + void Trace( const char* name ) { + printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", + name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() ); + } + + void SetTracked() { + _nUntracked--; + } + + int Untracked() const { + return _nUntracked; + } + + // This number is perf sensitive. 4k seems like a good tradeoff on my machine. + // The test file is large, 170k. + // Release: VS2010 gcc(no opt) + // 1k: 4000 + // 2k: 4000 + // 4k: 3900 21000 + // 16k: 5200 + // 32k: 4300 + // 64k: 4000 21000 + enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private + +private: + MemPoolT( const MemPoolT& ); // not supported + void operator=( const MemPoolT& ); // not supported + + union Chunk { + Chunk* next; + char mem[SIZE]; + }; + struct Block { + Chunk chunk[COUNT]; + }; + DynArray< Block*, 10 > _blockPtrs; + Chunk* _root; + + int _currentAllocs; + int _nAllocs; + int _maxAllocs; + int _nUntracked; +}; + + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a XMLVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its siblings will be visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the XMLDocument, although all nodes support visiting. + + You should never change the document from a callback. + + @sa XMLNode::Accept() +*/ +class TINYXML2_LIB XMLVisitor +{ +public: + virtual ~XMLVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { + return true; + } + /// Visit a document. + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + /// Visit an element. + virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { + return true; + } + /// Visit an element. + virtual bool VisitExit( const XMLElement& /*element*/ ) { + return true; + } + + /// Visit a declaration. + virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { + return true; + } + /// Visit a text node. + virtual bool Visit( const XMLText& /*text*/ ) { + return true; + } + /// Visit a comment node. + virtual bool Visit( const XMLComment& /*comment*/ ) { + return true; + } + /// Visit an unknown node. + virtual bool Visit( const XMLUnknown& /*unknown*/ ) { + return true; + } +}; + +// WARNING: must match XMLDocument::_errorNames[] +enum XMLError { + XML_SUCCESS = 0, + XML_NO_ATTRIBUTE, + XML_WRONG_ATTRIBUTE_TYPE, + XML_ERROR_FILE_NOT_FOUND, + XML_ERROR_FILE_COULD_NOT_BE_OPENED, + XML_ERROR_FILE_READ_ERROR, + XML_ERROR_ELEMENT_MISMATCH, + XML_ERROR_PARSING_ELEMENT, + XML_ERROR_PARSING_ATTRIBUTE, + XML_ERROR_IDENTIFYING_TAG, + XML_ERROR_PARSING_TEXT, + XML_ERROR_PARSING_CDATA, + XML_ERROR_PARSING_COMMENT, + XML_ERROR_PARSING_DECLARATION, + XML_ERROR_PARSING_UNKNOWN, + XML_ERROR_EMPTY_DOCUMENT, + XML_ERROR_MISMATCHED_ELEMENT, + XML_ERROR_PARSING, + XML_CAN_NOT_CONVERT_TEXT, + XML_NO_TEXT_NODE, + + XML_ERROR_COUNT +}; + + +/* + Utility functionality. +*/ +class XMLUtil +{ +public: + static const char* SkipWhiteSpace( const char* p ) { + TIXMLASSERT( p ); + while( IsWhiteSpace(*p) ) { + ++p; + } + TIXMLASSERT( p ); + return p; + } + static char* SkipWhiteSpace( char* p ) { + return const_cast( SkipWhiteSpace( const_cast(p) ) ); + } + + // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't + // correct, but simple, and usually works. + static bool IsWhiteSpace( char p ) { + return !IsUTF8Continuation(p) && isspace( static_cast(p) ); + } + + inline static bool IsNameStartChar( unsigned char ch ) { + if ( ch >= 128 ) { + // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() + return true; + } + if ( isalpha( ch ) ) { + return true; + } + return ch == ':' || ch == '_'; + } + + inline static bool IsNameChar( unsigned char ch ) { + return IsNameStartChar( ch ) + || isdigit( ch ) + || ch == '.' + || ch == '-'; + } + + inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { + if ( p == q ) { + return true; + } + return strncmp( p, q, nChar ) == 0; + } + + inline static bool IsUTF8Continuation( char p ) { + return ( p & 0x80 ) != 0; + } + + static const char* ReadBOM( const char* p, bool* hasBOM ); + // p is the starting location, + // the UTF-8 value of the entity will be placed in value, and length filled in. + static const char* GetCharacterRef( const char* p, char* value, int* length ); + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + + // converts primitive types to strings + static void ToStr( int v, char* buffer, int bufferSize ); + static void ToStr( unsigned v, char* buffer, int bufferSize ); + static void ToStr( bool v, char* buffer, int bufferSize ); + static void ToStr( float v, char* buffer, int bufferSize ); + static void ToStr( double v, char* buffer, int bufferSize ); + static void ToStr(int64_t v, char* buffer, int bufferSize); + + // converts strings to primitive types + static bool ToInt( const char* str, int* value ); + static bool ToUnsigned( const char* str, unsigned* value ); + static bool ToBool( const char* str, bool* value ); + static bool ToFloat( const char* str, float* value ); + static bool ToDouble( const char* str, double* value ); + static bool ToInt64(const char* str, int64_t* value); +}; + + +/** XMLNode is a base class for every object that is in the + XML Document Object Model (DOM), except XMLAttributes. + Nodes have siblings, a parent, and children which can + be navigated. A node is always in a XMLDocument. + The type of a XMLNode can be queried, and it can + be cast to its more defined type. + + A XMLDocument allocates memory for all its Nodes. + When the XMLDocument gets deleted, all its Nodes + will also be deleted. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + @endverbatim +*/ +class TINYXML2_LIB XMLNode +{ + friend class XMLDocument; + friend class XMLElement; +public: + + /// Get the XMLDocument that owns this XMLNode. + const XMLDocument* GetDocument() const { + TIXMLASSERT( _document ); + return _document; + } + /// Get the XMLDocument that owns this XMLNode. + XMLDocument* GetDocument() { + TIXMLASSERT( _document ); + return _document; + } + + /// Safely cast to an Element, or null. + virtual XMLElement* ToElement() { + return 0; + } + /// Safely cast to Text, or null. + virtual XMLText* ToText() { + return 0; + } + /// Safely cast to a Comment, or null. + virtual XMLComment* ToComment() { + return 0; + } + /// Safely cast to a Document, or null. + virtual XMLDocument* ToDocument() { + return 0; + } + /// Safely cast to a Declaration, or null. + virtual XMLDeclaration* ToDeclaration() { + return 0; + } + /// Safely cast to an Unknown, or null. + virtual XMLUnknown* ToUnknown() { + return 0; + } + + virtual const XMLElement* ToElement() const { + return 0; + } + virtual const XMLText* ToText() const { + return 0; + } + virtual const XMLComment* ToComment() const { + return 0; + } + virtual const XMLDocument* ToDocument() const { + return 0; + } + virtual const XMLDeclaration* ToDeclaration() const { + return 0; + } + virtual const XMLUnknown* ToUnknown() const { + return 0; + } + + /** The meaning of 'value' changes for the specific type. + @verbatim + Document: empty (NULL is returned, not an empty string) + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + const char* Value() const; + + /** Set the Value of an XML node. + @sa Value() + */ + void SetValue( const char* val, bool staticMem=false ); + + /// Get the parent of this node on the DOM. + const XMLNode* Parent() const { + return _parent; + } + + XMLNode* Parent() { + return _parent; + } + + /// Returns true if this node has no children. + bool NoChildren() const { + return !_firstChild; + } + + /// Get the first child node, or null if none exists. + const XMLNode* FirstChild() const { + return _firstChild; + } + + XMLNode* FirstChild() { + return _firstChild; + } + + /** Get the first child element, or optionally the first child + element with the specified name. + */ + const XMLElement* FirstChildElement( const char* name = 0 ) const; + + XMLElement* FirstChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->FirstChildElement( name )); + } + + /// Get the last child node, or null if none exists. + const XMLNode* LastChild() const { + return _lastChild; + } + + XMLNode* LastChild() { + return _lastChild; + } + + /** Get the last child element or optionally the last child + element with the specified name. + */ + const XMLElement* LastChildElement( const char* name = 0 ) const; + + XMLElement* LastChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->LastChildElement(name) ); + } + + /// Get the previous (left) sibling node of this node. + const XMLNode* PreviousSibling() const { + return _prev; + } + + XMLNode* PreviousSibling() { + return _prev; + } + + /// Get the previous (left) sibling element of this node, with an optionally supplied name. + const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; + + XMLElement* PreviousSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->PreviousSiblingElement( name ) ); + } + + /// Get the next (right) sibling node of this node. + const XMLNode* NextSibling() const { + return _next; + } + + XMLNode* NextSibling() { + return _next; + } + + /// Get the next (right) sibling element of this node, with an optionally supplied name. + const XMLElement* NextSiblingElement( const char* name = 0 ) const; + + XMLElement* NextSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->NextSiblingElement( name ) ); + } + + /** + Add a child node as the last (right) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertEndChild( XMLNode* addThis ); + + XMLNode* LinkEndChild( XMLNode* addThis ) { + return InsertEndChild( addThis ); + } + /** + Add a child node as the first (left) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertFirstChild( XMLNode* addThis ); + /** + Add a node after the specified child node. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the afterThis node + is not a child of this node, or if the node does not + belong to the same document. + */ + XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); + + /** + Delete all the children of this node. + */ + void DeleteChildren(); + + /** + Delete a child of this node. + */ + void DeleteChild( XMLNode* node ); + + /** + Make a copy of this node, but not its children. + You may pass in a Document pointer that will be + the owner of the new Node. If the 'document' is + null, then the node returned will be allocated + from the current Document. (this->GetDocument()) + + Note: if called on a XMLDocument, this will return null. + */ + virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; + + /** + Test if 2 nodes are the same, but don't test children. + The 2 nodes do not need to be in the same Document. + + Note: if called on a XMLDocument, this will return false. + */ + virtual bool ShallowEqual( const XMLNode* compare ) const = 0; + + /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the XMLVisitor interface. + + This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + XMLPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( XMLVisitor* visitor ) const = 0; + + /** + Set user data into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void SetUserData(void* userData) { _userData = userData; } + + /** + Get user data set into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void* GetUserData() const { return _userData; } + +protected: + XMLNode( XMLDocument* ); + virtual ~XMLNode(); + + virtual char* ParseDeep( char*, StrPair* ); + + XMLDocument* _document; + XMLNode* _parent; + mutable StrPair _value; + + XMLNode* _firstChild; + XMLNode* _lastChild; + + XMLNode* _prev; + XMLNode* _next; + + void* _userData; + +private: + MemPool* _memPool; + void Unlink( XMLNode* child ); + static void DeleteNode( XMLNode* node ); + void InsertChildPreamble( XMLNode* insertThis ) const; + + XMLNode( const XMLNode& ); // not supported + XMLNode& operator=( const XMLNode& ); // not supported +}; + + +/** XML text. + + Note that a text node can have child element nodes, for example: + @verbatim + This is bold + @endverbatim + + A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCData() and query it with CData(). +*/ +class TINYXML2_LIB XMLText : public XMLNode +{ + friend class XMLDocument; +public: + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLText* ToText() { + return this; + } + virtual const XMLText* ToText() const { + return this; + } + + /// Declare whether this should be CDATA or standard text. + void SetCData( bool isCData ) { + _isCData = isCData; + } + /// Returns true if this is a CDATA text element. + bool CData() const { + return _isCData; + } + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} + virtual ~XMLText() {} + + char* ParseDeep( char*, StrPair* endTag ); + +private: + bool _isCData; + + XMLText( const XMLText& ); // not supported + XMLText& operator=( const XMLText& ); // not supported +}; + + +/** An XML Comment. */ +class TINYXML2_LIB XMLComment : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLComment* ToComment() { + return this; + } + virtual const XMLComment* ToComment() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLComment( XMLDocument* doc ); + virtual ~XMLComment(); + + char* ParseDeep( char*, StrPair* endTag ); + +private: + XMLComment( const XMLComment& ); // not supported + XMLComment& operator=( const XMLComment& ); // not supported +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXML-2 will happily read or write files without a declaration, + however. + + The text of the declaration isn't interpreted. It is parsed + and written as a string. +*/ +class TINYXML2_LIB XMLDeclaration : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLDeclaration* ToDeclaration() { + return this; + } + virtual const XMLDeclaration* ToDeclaration() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLDeclaration( XMLDocument* doc ); + virtual ~XMLDeclaration(); + + char* ParseDeep( char*, StrPair* endTag ); + +private: + XMLDeclaration( const XMLDeclaration& ); // not supported + XMLDeclaration& operator=( const XMLDeclaration& ); // not supported +}; + + +/** Any tag that TinyXML-2 doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into XMLUnknowns. +*/ +class TINYXML2_LIB XMLUnknown : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLUnknown* ToUnknown() { + return this; + } + virtual const XMLUnknown* ToUnknown() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLUnknown( XMLDocument* doc ); + virtual ~XMLUnknown(); + + char* ParseDeep( char*, StrPair* endTag ); + +private: + XMLUnknown( const XMLUnknown& ); // not supported + XMLUnknown& operator=( const XMLUnknown& ); // not supported +}; + + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not XMLNodes. You may only query the + Next() attribute in a list. +*/ +class TINYXML2_LIB XMLAttribute +{ + friend class XMLElement; +public: + /// The name of the attribute. + const char* Name() const; + + /// The value of the attribute. + const char* Value() const; + + /// The next attribute in the list. + const XMLAttribute* Next() const { + return _next; + } + + /** IntValue interprets the attribute as an integer, and returns the value. + If the value isn't an integer, 0 will be returned. There is no error checking; + use QueryIntValue() if you need error checking. + */ + int IntValue() const { + int i = 0; + QueryIntValue(&i); + return i; + } + + int64_t Int64Value() const { + int64_t i = 0; + QueryInt64Value(&i); + return i; + } + + /// Query as an unsigned integer. See IntValue() + unsigned UnsignedValue() const { + unsigned i=0; + QueryUnsignedValue( &i ); + return i; + } + /// Query as a boolean. See IntValue() + bool BoolValue() const { + bool b=false; + QueryBoolValue( &b ); + return b; + } + /// Query as a double. See IntValue() + double DoubleValue() const { + double d=0; + QueryDoubleValue( &d ); + return d; + } + /// Query as a float. See IntValue() + float FloatValue() const { + float f=0; + QueryFloatValue( &f ); + return f; + } + + /** QueryIntValue interprets the attribute as an integer, and returns the value + in the provided parameter. The function will return XML_NO_ERROR on success, + and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. + */ + XMLError QueryIntValue( int* value ) const; + /// See QueryIntValue + XMLError QueryUnsignedValue( unsigned int* value ) const; + /// See QueryIntValue + XMLError QueryInt64Value(int64_t* value) const; + /// See QueryIntValue + XMLError QueryBoolValue( bool* value ) const; + /// See QueryIntValue + XMLError QueryDoubleValue( double* value ) const; + /// See QueryIntValue + XMLError QueryFloatValue( float* value ) const; + + /// Set the attribute to a string value. + void SetAttribute( const char* value ); + /// Set the attribute to value. + void SetAttribute( int value ); + /// Set the attribute to value. + void SetAttribute( unsigned value ); + /// Set the attribute to value. + void SetAttribute(int64_t value); + /// Set the attribute to value. + void SetAttribute( bool value ); + /// Set the attribute to value. + void SetAttribute( double value ); + /// Set the attribute to value. + void SetAttribute( float value ); + +private: + enum { BUF_SIZE = 200 }; + + XMLAttribute() : _next( 0 ), _memPool( 0 ) {} + virtual ~XMLAttribute() {} + + XMLAttribute( const XMLAttribute& ); // not supported + void operator=( const XMLAttribute& ); // not supported + void SetName( const char* name ); + + char* ParseDeep( char* p, bool processEntities ); + + mutable StrPair _name; + mutable StrPair _value; + XMLAttribute* _next; + MemPool* _memPool; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TINYXML2_LIB XMLElement : public XMLNode +{ + friend class XMLDocument; +public: + /// Get the name of an element (which is the Value() of the node.) + const char* Name() const { + return Value(); + } + /// Set the name of the element. + void SetName( const char* str, bool staticMem=false ) { + SetValue( str, staticMem ); + } + + virtual XMLElement* ToElement() { + return this; + } + virtual const XMLElement* ToElement() const { + return this; + } + virtual bool Accept( XMLVisitor* visitor ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none + exists. For example: + + @verbatim + const char* value = ele->Attribute( "foo" ); + @endverbatim + + The 'value' parameter is normally null. However, if specified, + the attribute will only be returned if the 'name' and 'value' + match. This allow you to write code: + + @verbatim + if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); + @endverbatim + + rather than: + @verbatim + if ( ele->Attribute( "foo" ) ) { + if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); + } + @endverbatim + */ + const char* Attribute( const char* name, const char* value=0 ) const; + + /** Given an attribute name, IntAttribute() returns the value + of the attribute interpreted as an integer. 0 will be + returned if there is an error. For a method with error + checking, see QueryIntAttribute() + */ + int IntAttribute( const char* name ) const { + int i=0; + QueryIntAttribute( name, &i ); + return i; + } + + /// See IntAttribute() + unsigned UnsignedAttribute( const char* name ) const { + unsigned i=0; + QueryUnsignedAttribute( name, &i ); + return i; + } + + /// See IntAttribute() + int64_t Int64Attribute(const char* name) const { + int64_t i = 0; + QueryInt64Attribute(name, &i); + return i; + } + + /// See IntAttribute() + bool BoolAttribute( const char* name ) const { + bool b=false; + QueryBoolAttribute( name, &b ); + return b; + } + /// See IntAttribute() + double DoubleAttribute( const char* name ) const { + double d=0; + QueryDoubleAttribute( name, &d ); + return d; + } + /// See IntAttribute() + float FloatAttribute( const char* name ) const { + float f=0; + QueryFloatAttribute( name, &f ); + return f; + } + + /** Given an attribute name, QueryIntAttribute() returns + XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryIntAttribute( const char* name, int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryIntValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsignedValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryInt64Attribute(const char* name, int64_t* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryInt64Value(value); + } + + /// See QueryIntAttribute() + XMLError QueryBoolAttribute( const char* name, bool* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryBoolValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryDoubleAttribute( const char* name, double* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryDoubleValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryFloatAttribute( const char* name, float* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryFloatValue( value ); + } + + + /** Given an attribute name, QueryAttribute() returns + XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. It is overloaded for the primitive types, + and is a generally more convenient replacement of + QueryIntAttribute() and related functions. + + If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + int QueryAttribute( const char* name, int* value ) const { + return QueryIntAttribute( name, value ); + } + + int QueryAttribute( const char* name, unsigned int* value ) const { + return QueryUnsignedAttribute( name, value ); + } + + int QueryAttribute(const char* name, int64_t* value) const { + return QueryInt64Attribute(name, value); + } + + int QueryAttribute( const char* name, bool* value ) const { + return QueryBoolAttribute( name, value ); + } + + int QueryAttribute( const char* name, double* value ) const { + return QueryDoubleAttribute( name, value ); + } + + int QueryAttribute( const char* name, float* value ) const { + return QueryFloatAttribute( name, value ); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, const char* value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, int value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, unsigned value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, int64_t value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, bool value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, double value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, float value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /** + Delete an attribute. + */ + void DeleteAttribute( const char* name ); + + /// Return the first attribute in the list. + const XMLAttribute* FirstAttribute() const { + return _rootAttribute; + } + /// Query a specific attribute in the list. + const XMLAttribute* FindAttribute( const char* name ) const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the XMLText child + and accessing it directly. + + If the first child of 'this' is a XMLText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + */ + const char* GetText() const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, SetText() is limited compared to creating an XMLText child + and mutating it directly. + + If the first child of 'this' is a XMLText, SetText() sets its value to + the given string, otherwise it will create a first child that is an XMLText. + + This is a convenient method for setting the text of simple contained text: + @verbatim + This is text + fooElement->SetText( "Hullaballoo!" ); + Hullaballoo! + @endverbatim + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then it will not change "This is text", but rather prefix it with a text element: + @verbatim + Hullaballoo!This is text + @endverbatim + + For this XML: + @verbatim + + @endverbatim + SetText() will generate + @verbatim + Hullaballoo! + @endverbatim + */ + void SetText( const char* inText ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( int value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( unsigned value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(int64_t value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( bool value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( double value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( float value ); + + /** + Convenience method to query the value of a child text node. This is probably best + shown by example. Given you have a document is this form: + @verbatim + + 1 + 1.4 + + @endverbatim + + The QueryIntText() and similar functions provide a safe and easier way to get to the + "value" of x and y. + + @verbatim + int x = 0; + float y = 0; // types of x and y are contrived for example + const XMLElement* xElement = pointElement->FirstChildElement( "x" ); + const XMLElement* yElement = pointElement->FirstChildElement( "y" ); + xElement->QueryIntText( &x ); + yElement->QueryFloatText( &y ); + @endverbatim + + @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted + to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. + + */ + XMLError QueryIntText( int* ival ) const; + /// See QueryIntText() + XMLError QueryUnsignedText( unsigned* uval ) const; + /// See QueryIntText() + XMLError QueryInt64Text(int64_t* uval) const; + /// See QueryIntText() + XMLError QueryBoolText( bool* bval ) const; + /// See QueryIntText() + XMLError QueryDoubleText( double* dval ) const; + /// See QueryIntText() + XMLError QueryFloatText( float* fval ) const; + + // internal: + enum { + OPEN, // + CLOSED, // + CLOSING // + }; + int ClosingType() const { + return _closingType; + } + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + char* ParseDeep( char* p, StrPair* endTag ); + +private: + XMLElement( XMLDocument* doc ); + virtual ~XMLElement(); + XMLElement( const XMLElement& ); // not supported + void operator=( const XMLElement& ); // not supported + + XMLAttribute* FindAttribute( const char* name ) { + return const_cast(const_cast(this)->FindAttribute( name )); + } + XMLAttribute* FindOrCreateAttribute( const char* name ); + //void LinkAttribute( XMLAttribute* attrib ); + char* ParseAttributes( char* p ); + static void DeleteAttribute( XMLAttribute* attribute ); + + enum { BUF_SIZE = 200 }; + int _closingType; + // The attribute list is ordered; there is no 'lastAttribute' + // because the list needs to be scanned for dupes before adding + // a new attribute. + XMLAttribute* _rootAttribute; +}; + + +enum Whitespace { + PRESERVE_WHITESPACE, + COLLAPSE_WHITESPACE +}; + + +/** A Document binds together all the functionality. + It can be saved, loaded, and printed to the screen. + All Nodes are connected and allocated to a Document. + If the Document is deleted, all its Nodes are also deleted. +*/ +class TINYXML2_LIB XMLDocument : public XMLNode +{ + friend class XMLElement; +public: + /// constructor + XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE ); + ~XMLDocument(); + + virtual XMLDocument* ToDocument() { + TIXMLASSERT( this == _document ); + return this; + } + virtual const XMLDocument* ToDocument() const { + TIXMLASSERT( this == _document ); + return this; + } + + /** + Parse an XML file from a character string. + Returns XML_NO_ERROR (0) on success, or + an errorID. + + You may optionally pass in the 'nBytes', which is + the number of bytes which will be parsed. If not + specified, TinyXML-2 will assume 'xml' points to a + null terminated string. + */ + XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) ); + + /** + Load an XML file from disk. + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError LoadFile( const char* filename ); + + /** + Load an XML file from disk. You are responsible + for providing and closing the FILE*. + + NOTE: The file should be opened as binary ("rb") + not text in order for TinyXML-2 to correctly + do newline normalization. + + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError LoadFile( FILE* ); + + /** + Save the XML file to disk. + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError SaveFile( const char* filename, bool compact = false ); + + /** + Save the XML file to disk. You are responsible + for providing and closing the FILE*. + + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError SaveFile( FILE* fp, bool compact = false ); + + bool ProcessEntities() const { + return _processEntities; + } + Whitespace WhitespaceMode() const { + return _whitespace; + } + + /** + Returns true if this document has a leading Byte Order Mark of UTF8. + */ + bool HasBOM() const { + return _writeBOM; + } + /** Sets whether to write the BOM when writing the file. + */ + void SetBOM( bool useBOM ) { + _writeBOM = useBOM; + } + + /** Return the root element of DOM. Equivalent to FirstChildElement(). + To get the first node, use FirstChild(). + */ + XMLElement* RootElement() { + return FirstChildElement(); + } + const XMLElement* RootElement() const { + return FirstChildElement(); + } + + /** Print the Document. If the Printer is not provided, it will + print to stdout. If you provide Printer, this can print to a file: + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Or you can use a printer to print to memory: + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + // printer.CStr() has a const char* to the XML + @endverbatim + */ + void Print( XMLPrinter* streamer=0 ) const; + virtual bool Accept( XMLVisitor* visitor ) const; + + /** + Create a new Element associated with + this Document. The memory for the Element + is managed by the Document. + */ + XMLElement* NewElement( const char* name ); + /** + Create a new Comment associated with + this Document. The memory for the Comment + is managed by the Document. + */ + XMLComment* NewComment( const char* comment ); + /** + Create a new Text associated with + this Document. The memory for the Text + is managed by the Document. + */ + XMLText* NewText( const char* text ); + /** + Create a new Declaration associated with + this Document. The memory for the object + is managed by the Document. + + If the 'text' param is null, the standard + declaration is used.: + @verbatim + + @endverbatim + */ + XMLDeclaration* NewDeclaration( const char* text=0 ); + /** + Create a new Unknown associated with + this Document. The memory for the object + is managed by the Document. + */ + XMLUnknown* NewUnknown( const char* text ); + + /** + Delete a node associated with this document. + It will be unlinked from the DOM. + */ + void DeleteNode( XMLNode* node ); + + void SetError( XMLError error, const char* str1, const char* str2 ); + + /// Return true if there was an error parsing the document. + bool Error() const { + return _errorID != XML_SUCCESS; + } + /// Return the errorID. + XMLError ErrorID() const { + return _errorID; + } + const char* ErrorName() const; + + /// Return a possibly helpful diagnostic location or string. + const char* GetErrorStr1() const { + return _errorStr1; + } + /// Return a possibly helpful secondary diagnostic location or string. + const char* GetErrorStr2() const { + return _errorStr2; + } + /// If there is an error, print it to stdout. + void PrintError() const; + + /// Clear the document, resetting it to the initial state. + void Clear(); + + // internal + char* Identify( char* p, XMLNode** node ); + + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { + return 0; + } + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { + return false; + } + +private: + XMLDocument( const XMLDocument& ); // not supported + void operator=( const XMLDocument& ); // not supported + + bool _writeBOM; + bool _processEntities; + XMLError _errorID; + Whitespace _whitespace; + const char* _errorStr1; + const char* _errorStr2; + char* _charBuffer; + + MemPoolT< sizeof(XMLElement) > _elementPool; + MemPoolT< sizeof(XMLAttribute) > _attributePool; + MemPoolT< sizeof(XMLText) > _textPool; + MemPoolT< sizeof(XMLComment) > _commentPool; + + static const char* _errorNames[XML_ERROR_COUNT]; + + void Parse(); +}; + + +/** + A XMLHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + XMLElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + XMLElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + XMLElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + XMLElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. XMLHandle addresses the verbosity + of such code. A XMLHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + XMLHandle docHandle( &document ); + XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + XMLHandle handleCopy = handle; + @endverbatim + + See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. +*/ +class TINYXML2_LIB XMLHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + XMLHandle( XMLNode* node ) { + _node = node; + } + /// Create a handle from a node. + XMLHandle( XMLNode& node ) { + _node = &node; + } + /// Copy constructor + XMLHandle( const XMLHandle& ref ) { + _node = ref._node; + } + /// Assignment + XMLHandle& operator=( const XMLHandle& ref ) { + _node = ref._node; + return *this; + } + + /// Get the first child of this handle. + XMLHandle FirstChild() { + return XMLHandle( _node ? _node->FirstChild() : 0 ); + } + /// Get the first child element of this handle. + XMLHandle FirstChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + /// Get the last child of this handle. + XMLHandle LastChild() { + return XMLHandle( _node ? _node->LastChild() : 0 ); + } + /// Get the last child element of this handle. + XMLHandle LastChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + /// Get the previous sibling of this handle. + XMLHandle PreviousSibling() { + return XMLHandle( _node ? _node->PreviousSibling() : 0 ); + } + /// Get the previous sibling element of this handle. + XMLHandle PreviousSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + /// Get the next sibling of this handle. + XMLHandle NextSibling() { + return XMLHandle( _node ? _node->NextSibling() : 0 ); + } + /// Get the next sibling element of this handle. + XMLHandle NextSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + /// Safe cast to XMLNode. This can return null. + XMLNode* ToNode() { + return _node; + } + /// Safe cast to XMLElement. This can return null. + XMLElement* ToElement() { + return ( ( _node == 0 ) ? 0 : _node->ToElement() ); + } + /// Safe cast to XMLText. This can return null. + XMLText* ToText() { + return ( ( _node == 0 ) ? 0 : _node->ToText() ); + } + /// Safe cast to XMLUnknown. This can return null. + XMLUnknown* ToUnknown() { + return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); + } + /// Safe cast to XMLDeclaration. This can return null. + XMLDeclaration* ToDeclaration() { + return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); + } + +private: + XMLNode* _node; +}; + + +/** + A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the + same in all regards, except for the 'const' qualifiers. See XMLHandle for API. +*/ +class TINYXML2_LIB XMLConstHandle +{ +public: + XMLConstHandle( const XMLNode* node ) { + _node = node; + } + XMLConstHandle( const XMLNode& node ) { + _node = &node; + } + XMLConstHandle( const XMLConstHandle& ref ) { + _node = ref._node; + } + + XMLConstHandle& operator=( const XMLConstHandle& ref ) { + _node = ref._node; + return *this; + } + + const XMLConstHandle FirstChild() const { + return XMLConstHandle( _node ? _node->FirstChild() : 0 ); + } + const XMLConstHandle FirstChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + const XMLConstHandle LastChild() const { + return XMLConstHandle( _node ? _node->LastChild() : 0 ); + } + const XMLConstHandle LastChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + const XMLConstHandle PreviousSibling() const { + return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); + } + const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + const XMLConstHandle NextSibling() const { + return XMLConstHandle( _node ? _node->NextSibling() : 0 ); + } + const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + + const XMLNode* ToNode() const { + return _node; + } + const XMLElement* ToElement() const { + return ( ( _node == 0 ) ? 0 : _node->ToElement() ); + } + const XMLText* ToText() const { + return ( ( _node == 0 ) ? 0 : _node->ToText() ); + } + const XMLUnknown* ToUnknown() const { + return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); + } + const XMLDeclaration* ToDeclaration() const { + return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); + } + +private: + const XMLNode* _node; +}; + + +/** + Printing functionality. The XMLPrinter gives you more + options than the XMLDocument::Print() method. + + It can: + -# Print to memory. + -# Print to a file you provide. + -# Print XML without a XMLDocument. + + Print to Memory + + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + SomeFunction( printer.CStr() ); + @endverbatim + + Print to a File + + You provide the file pointer. + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Print without a XMLDocument + + When loading, an XML parser is very useful. However, sometimes + when saving, it just gets in the way. The code is often set up + for streaming, and constructing the DOM is just overhead. + + The Printer supports the streaming case. The following code + prints out a trivially simple XML file without ever creating + an XML document. + + @verbatim + XMLPrinter printer( fp ); + printer.OpenElement( "foo" ); + printer.PushAttribute( "foo", "bar" ); + printer.CloseElement(); + @endverbatim +*/ +class TINYXML2_LIB XMLPrinter : public XMLVisitor +{ +public: + /** Construct the printer. If the FILE* is specified, + this will print to the FILE. Else it will print + to memory, and the result is available in CStr(). + If 'compact' is set to true, then output is created + with only required whitespace and newlines. + */ + XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); + virtual ~XMLPrinter() {} + + /** If streaming, write the BOM and declaration. */ + void PushHeader( bool writeBOM, bool writeDeclaration ); + /** If streaming, start writing an element. + The element must be closed with CloseElement() + */ + void OpenElement( const char* name, bool compactMode=false ); + /// If streaming, add an attribute to an open element. + void PushAttribute( const char* name, const char* value ); + void PushAttribute( const char* name, int value ); + void PushAttribute( const char* name, unsigned value ); + void PushAttribute(const char* name, int64_t value); + void PushAttribute( const char* name, bool value ); + void PushAttribute( const char* name, double value ); + /// If streaming, close the Element. + virtual void CloseElement( bool compactMode=false ); + + /// Add a text node. + void PushText( const char* text, bool cdata=false ); + /// Add a text node from an integer. + void PushText( int value ); + /// Add a text node from an unsigned. + void PushText( unsigned value ); + /// Add a text node from an unsigned. + void PushText(int64_t value); + /// Add a text node from a bool. + void PushText( bool value ); + /// Add a text node from a float. + void PushText( float value ); + /// Add a text node from a double. + void PushText( double value ); + + /// Add a comment + void PushComment( const char* comment ); + + void PushDeclaration( const char* value ); + void PushUnknown( const char* value ); + + virtual bool VisitEnter( const XMLDocument& /*doc*/ ); + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); + virtual bool VisitExit( const XMLElement& element ); + + virtual bool Visit( const XMLText& text ); + virtual bool Visit( const XMLComment& comment ); + virtual bool Visit( const XMLDeclaration& declaration ); + virtual bool Visit( const XMLUnknown& unknown ); + + /** + If in print to memory mode, return a pointer to + the XML file in memory. + */ + const char* CStr() const { + return _buffer.Mem(); + } + /** + If in print to memory mode, return the size + of the XML file in memory. (Note the size returned + includes the terminating null.) + */ + int CStrSize() const { + return _buffer.Size(); + } + /** + If in print to memory mode, reset the buffer to the + beginning. + */ + void ClearBuffer() { + _buffer.Clear(); + _buffer.Push(0); + } + +protected: + virtual bool CompactMode( const XMLElement& ) { return _compactMode; } + + /** Prints out the space before an element. You may override to change + the space and tabs used. A PrintSpace() override should call Print(). + */ + virtual void PrintSpace( int depth ); + void Print( const char* format, ... ); + + void SealElementIfJustOpened(); + bool _elementJustOpened; + DynArray< const char*, 10 > _stack; + +private: + void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. + + bool _firstElement; + FILE* _fp; + int _depth; + int _textDepth; + bool _processEntities; + bool _compactMode; + + enum { + ENTITY_RANGE = 64, + BUF_SIZE = 200 + }; + bool _entityFlag[ENTITY_RANGE]; + bool _restrictedEntityFlag[ENTITY_RANGE]; + + DynArray< char, 20 > _buffer; +}; + + +} // tinyxml2 + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // TINYXML2_INCLUDED diff --git a/svnrev.sh b/svnrev.sh new file mode 100755 index 0000000..da214e4 --- /dev/null +++ b/svnrev.sh @@ -0,0 +1,103 @@ +#! /bin/bash +# +rev_new_raw=$(svnversion -n . 2>/dev/null | tr '\n' ' ' | tr -d '\r') +[ -n "$rev_new_raw" ] || rev_new_raw=$(SubWCRev . 2>/dev/null | tr '\n' ' ' | tr -d '\r') + + +rev_new_raw=$(echo $rev_new_raw | sed 's/[^0-9]*\([0-9]*\)\(.*\)/\1 \2/') +rev_new=1273 +a=$(echo $rev_new_raw | sed 's/\([0-9]*\).*/\1/') +let "a+=0" +#find max rev +while [ "$a" ]; do + [ "$a" -gt "$rev_new" ] && rev_new=$a + rev_new_raw=$(echo -n $rev_new_raw | sed 's/[0-9]*[^0-9]*\([0-9]*\)\(.*\)/\1 \2/') + a=$(echo $rev_new_raw | sed 's/\([0-9]*\).*/\1/') +done + +rev_old=$(cat ./source/svnrev.c 2>/dev/null | tr -d '\n' | sed 's/[^0-9]*\([0-9]*\).*/\1/') + +if [ "$rev_new" != "$rev_old" ] || [ ! -f ./source/svnrev.c ]; then + + cat < ./source/svnrev.c +#define SVN_REV "$rev_new" + +const char *GetRev() +{ + return SVN_REV; +} +EOF + + if [ -n "$rev_new" ]; then + echo "Changed Rev $rev_old to $rev_new" >&2 + else + echo "svnrev.c created" >&2 + fi + echo >&2 +fi + + +rev_new=`expr $rev_new + 1` +rev_date=`date -u +%Y%m%d%H%M%S` + +cat < ./USBLoaderGX/meta.xml + + + USB Loader GX + USB Loader GX Team / Asayu + 3.0 r$rev_new + $rev_date + + + Loads games from USB-devices + USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times. +The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller. +Features are automatic widescreen detection, coverdownload, parental control, theme support and many more. + +Credits: +Coding: Cyan, Dimok, nIxx, giantpune, ardi, Hungyip84, DrayX7, Lustar, r-win, WiiShizzza, Asayu +Artworks: cyrex, NeoRame +Validation: Cyan and many others +Issue management: Cyan +WiiTDB / Hosting covers: Lustar +USBLoader sources: Waninkoko, Kwiirk, Hermes +cIOS maintenance: davebaol, xabby666, XFlak and Rodries +Languages files updates: Kinyo and translaters +Hosting themes: Deak Phreak + +Libwiigui: Tantric +Libogc/Devkit: Shagkur and Wintermute +FreeTypeGX: Armin Tamzarian. + +Links: +Asayu's USB Loader GX Project Page: +https://github.com/AsayuGit/USBLoaderGX + +Original USB Loader GX Project Page +https://sourceforge.net/projects/usbloadergx/ +Support Site: +http://gbatemp.net/index.php?showtopic=149922 +Help Website: +http://usbloadergx.koureio.net/ +WiiTDB Site: +http://wiitdb.com +Themes Site: +http://wii.spiffy360.com +Languages Translaters Page: +http://gbatemp.net/index.php?showtopic=155252 + +Libwiigui Website: +http://wiibrew.org/wiki/Libwiigui/ +FreeTypeGX Project Page: +http://code.google.com/p/freetypegx/ +Gettext Official Page: +http://www.gnu.org/software/gettext/gettext.html + + +EOF