First commit
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					qcma.pro.user*
 | 
				
			||||||
							
								
								
									
										674
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										674
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,674 @@
 | 
				
			|||||||
 | 
					                    GNU GENERAL PUBLIC LICENSE
 | 
				
			||||||
 | 
					                       Version 3, 29 June 2007
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 | 
				
			||||||
 | 
					 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <one line to give the program's name and a brief idea of what it does.>
 | 
				
			||||||
 | 
					    Copyright (C) <year>  <name of author>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <program>  Copyright (C) <year>  <name of author>
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					<http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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
 | 
				
			||||||
 | 
					<http://www.gnu.org/philosophy/why-not-lgpl.html>.
 | 
				
			||||||
							
								
								
									
										58
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					QCMA
 | 
				
			||||||
 | 
					====
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QCMA is an cross-platform application to provide a Open Source implementation
 | 
				
			||||||
 | 
					of the original Content Manager Assistant that comes with the PS Vita. QCMA is
 | 
				
			||||||
 | 
					meant to be compatible with Linux, Windows and MAC OS X.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The aim of this project is to provide a implementation that is on par with the
 | 
				
			||||||
 | 
					official CMA and also offer some features missing in the original one.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Implemented features missing in OpenCMA (Yifan Lu CLI application)
 | 
				
			||||||
 | 
					* Metadata for PSP savedatas.
 | 
				
			||||||
 | 
					* Basic metadata for single songs (album, artist, title).
 | 
				
			||||||
 | 
					* Basic metadata for videos (duration, dimensions).
 | 
				
			||||||
 | 
					* Basic metadata for photos (dimensions).
 | 
				
			||||||
 | 
					* Easy wireless pairing (show PIN to the user when a Vita is detected).
 | 
				
			||||||
 | 
					* Ability to restart the connection if the Vita is reconnected (on test).
 | 
				
			||||||
 | 
					* Ability to change the connection mode (usb/wireless) on the fly (on test).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### TODO:
 | 
				
			||||||
 | 
					* Fix remaining bugs with thread synchronizations.
 | 
				
			||||||
 | 
					* Implement thumbnails for videos and album art for music.
 | 
				
			||||||
 | 
					* Folder categories for music/videos.
 | 
				
			||||||
 | 
					* SQLite backend for database.
 | 
				
			||||||
 | 
					* Fix wireless streaming for music/videos.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Planned features
 | 
				
			||||||
 | 
					* **Backup browser**: provide a human readable listing of the games saved on the
 | 
				
			||||||
 | 
					computer (name, icon, side on disk) and provide some actions (delete savedata,
 | 
				
			||||||
 | 
					patches or the whole game without need of the Vita). Also some sort of interface
 | 
				
			||||||
 | 
					to prepare VHBL homebrew in the folder of the exploited savedata.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* **DLNA bridge**: connect an existing DLNA server to interface with the Vita
 | 
				
			||||||
 | 
					using the wireless streaming feature.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Dependencies
 | 
				
			||||||
 | 
					* [Qt 4.x or 5.x](http://qt-project.org/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* [VitaMTP](https://github.com/yifanlu/VitaMTP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* [MediaInfo](http://mediaarea.net/en/MediaInfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Where do I get the source code?
 | 
				
			||||||
 | 
					Check the GitHub repo here: https://github.com/codestation/qcma
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### I want to contribute 
 | 
				
			||||||
 | 
					Contact me on [GitHub](https://github.com/codestation/) 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Thanks to
 | 
				
			||||||
 | 
					[Yifan Lu](https://github.com/yifanlu/vitamtp/) - for the vitamtp library and
 | 
				
			||||||
 | 
					the reference implementation of OpenCMA.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### License
 | 
				
			||||||
 | 
					GPL v3: since some parts of QCMA are based on the reference implementation of
 | 
				
			||||||
 | 
					OpenCMA.
 | 
				
			||||||
							
								
								
									
										57
									
								
								baseworker.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								baseworker.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "baseworker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BaseWorker::BaseWorker(QObject *parent) :
 | 
				
			||||||
 | 
					    QObject(parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    thread = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BaseWorker::onFinished()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BaseWorker::start()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    thread = new QThread();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Move this service to a new thread
 | 
				
			||||||
 | 
					    this->moveToThread(thread);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The main loop will be executed when the thread
 | 
				
			||||||
 | 
					    // signals that it has started.
 | 
				
			||||||
 | 
					    connect(thread, SIGNAL(started()), this, SLOT(process()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Make sure that we notify ourselves when the thread
 | 
				
			||||||
 | 
					    // is finished in order to correctly clean-up the thread.
 | 
				
			||||||
 | 
					    connect(thread, SIGNAL(finished()), this, SLOT(onFinished()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The thread will quit when the sercives
 | 
				
			||||||
 | 
					    // signals that it's finished.
 | 
				
			||||||
 | 
					    connect(this, SIGNAL(finished()), thread, SLOT(quit()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The thread will be scheduled for deletion when the
 | 
				
			||||||
 | 
					    // service signals that it's finished
 | 
				
			||||||
 | 
					    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start the thread
 | 
				
			||||||
 | 
					    thread->start();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										48
									
								
								baseworker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								baseworker.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef BASEWORKER_H
 | 
				
			||||||
 | 
					#define BASEWORKER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QObject>
 | 
				
			||||||
 | 
					#include <QThread>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BaseWorker : public QObject
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit BaseWorker(QObject *parent = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    QThread *thread;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
					    void finished();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected slots:
 | 
				
			||||||
 | 
					    virtual void process() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
					    virtual void onFinished();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // BASEWORKER_H
 | 
				
			||||||
							
								
								
									
										112
									
								
								capability.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								capability.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "capability.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QDebug>
 | 
				
			||||||
 | 
					#include <QHostInfo>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DeviceCapability::exchangeInfo(vita_device_t *device)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(VitaMTP_GetVitaInfo(device, &vita_info) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Cannot retreve device information.");
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(vita_info.protocolVersion > VITAMTP_PROTOCOL_MAX_VERSION) {
 | 
				
			||||||
 | 
					        qWarning("Vita wants protocol version %08d while we only support %08d. Attempting to continue.",
 | 
				
			||||||
 | 
					            vita_info.protocolVersion, VITAMTP_PROTOCOL_MAX_VERSION);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QString hostname = QHostInfo::localHostName();
 | 
				
			||||||
 | 
					    const initiator_info_t *pc_info = VitaMTP_Data_Initiator_New(hostname.toUtf8().data(), vita_info.protocolVersion);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Next, we send the client's (this program) info (discard the const here)
 | 
				
			||||||
 | 
					    if(VitaMTP_SendInitiatorInfo(device, (initiator_info_t *)pc_info) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Cannot send host information.");
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(vita_info.protocolVersion >= VITAMTP_PROTOCOL_FW_2_10) {
 | 
				
			||||||
 | 
					        // Get the device's capabilities
 | 
				
			||||||
 | 
					        capability_info_t *vita_capabilities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(VitaMTP_GetVitaCapabilityInfo(device, &vita_capabilities) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					            qWarning("Failed to get capability information from Vita.");
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        VitaMTP_Data_Free_Capability(vita_capabilities); // TODO: Use this data
 | 
				
			||||||
 | 
					        // Send the host's capabilities
 | 
				
			||||||
 | 
					        capability_info_t *pc_capabilities = generate_pc_capability_info();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(VitaMTP_SendPCCapabilityInfo(device, pc_capabilities) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					            qWarning("Failed to send capability information to Vita.");
 | 
				
			||||||
 | 
					            free_pc_capability_info(pc_capabilities);
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        free_pc_capability_info(pc_capabilities);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Finally, we tell the Vita we are connected
 | 
				
			||||||
 | 
					    if(VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_Connected) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Cannot send host status.");
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VitaMTP_Data_Free_Initiator(pc_info);
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DeviceCapability::free_pc_capability_info(capability_info_t *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    delete &info->functions.formats.next_item[-1];
 | 
				
			||||||
 | 
					    delete &info->functions.next_item[-1];
 | 
				
			||||||
 | 
					    delete info;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					capability_info_t *DeviceCapability::generate_pc_capability_info()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    typedef capability_info::capability_info_function tfunction;
 | 
				
			||||||
 | 
					    typedef tfunction::capability_info_format tformat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: Actually do this based on QCMA capabilities
 | 
				
			||||||
 | 
					    capability_info_t *pc_capabilities = new capability_info_t;
 | 
				
			||||||
 | 
					    pc_capabilities->version = "1.0";
 | 
				
			||||||
 | 
					    tfunction *functions = new tfunction[3]();
 | 
				
			||||||
 | 
					    tformat *game_formats = new tformat[5]();
 | 
				
			||||||
 | 
					    game_formats[0].contentType = "vitaApp";
 | 
				
			||||||
 | 
					    game_formats[0].next_item = &game_formats[1];
 | 
				
			||||||
 | 
					    game_formats[1].contentType = "PSPGame";
 | 
				
			||||||
 | 
					    game_formats[1].next_item = &game_formats[2];
 | 
				
			||||||
 | 
					    game_formats[2].contentType = "PSPSaveData";
 | 
				
			||||||
 | 
					    game_formats[2].next_item = &game_formats[3];
 | 
				
			||||||
 | 
					    game_formats[3].contentType = "PSGame";
 | 
				
			||||||
 | 
					    game_formats[3].next_item = &game_formats[4];
 | 
				
			||||||
 | 
					    game_formats[4].contentType = "PSMApp";
 | 
				
			||||||
 | 
					    functions[0].type = "game";
 | 
				
			||||||
 | 
					    functions[0].formats = game_formats[0];
 | 
				
			||||||
 | 
					    functions[0].next_item = &functions[1];
 | 
				
			||||||
 | 
					    functions[1].type = "backup";
 | 
				
			||||||
 | 
					    functions[1].next_item = &functions[2];
 | 
				
			||||||
 | 
					    functions[2].type = "systemUpdate";
 | 
				
			||||||
 | 
					    pc_capabilities->functions = functions[0];
 | 
				
			||||||
 | 
					    return pc_capabilities;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								capability.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								capability.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CAPABILITY_H
 | 
				
			||||||
 | 
					#define CAPABILITY_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include <vitamtp.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DeviceCapability
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit DeviceCapability() {}
 | 
				
			||||||
 | 
					    bool exchangeInfo(vita_device_t *device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //TODO: vita_info_t doesn't retrieve this info, update vitamtp to get it
 | 
				
			||||||
 | 
					    const char *getVersion() { return ""; }
 | 
				
			||||||
 | 
					    const char *getProtocol()  { return ""; }
 | 
				
			||||||
 | 
					    const char *getOnlineId()  { return "PS Vita"; }
 | 
				
			||||||
 | 
					    const char *getModelInfo()  { return ""; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    capability_info_t *generate_pc_capability_info();
 | 
				
			||||||
 | 
					    void free_pc_capability_info(capability_info_t *info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vita_info_t vita_info;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CAPABILITY_H
 | 
				
			||||||
							
								
								
									
										300
									
								
								cmaobject.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								cmaobject.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,300 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "cmaobject.h"
 | 
				
			||||||
 | 
					#include "sforeader.h"
 | 
				
			||||||
 | 
					#include "utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QDir>
 | 
				
			||||||
 | 
					#include <QDateTime>
 | 
				
			||||||
 | 
					#include <QDebug>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <MediaInfo/MediaInfo.h>
 | 
				
			||||||
 | 
					#include <MediaInfo/File__Analyse_Automatic.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int CMAObject::ohfi_count = OHFI_OFFSET;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMAObject::CMAObject(CMAObject *obj_parent) :
 | 
				
			||||||
 | 
					    parent(obj_parent), metadata()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMAObject::~CMAObject()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    free(metadata.name);
 | 
				
			||||||
 | 
					    free(metadata.path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(MASK_SET(metadata.dataType, SaveData | Folder)) {
 | 
				
			||||||
 | 
					        free(metadata.data.saveData.title);
 | 
				
			||||||
 | 
					        free(metadata.data.saveData.detail);
 | 
				
			||||||
 | 
					        free(metadata.data.saveData.dirName);
 | 
				
			||||||
 | 
					        free(metadata.data.saveData.savedataTitle);
 | 
				
			||||||
 | 
					    } else if(MASK_SET(metadata.dataType, Photo | File)) {
 | 
				
			||||||
 | 
					        free(metadata.data.photo.title);
 | 
				
			||||||
 | 
					        free(metadata.data.photo.fileName);
 | 
				
			||||||
 | 
					        delete metadata.data.photo.tracks;
 | 
				
			||||||
 | 
					    } else if(MASK_SET(metadata.dataType, Music | File)) {
 | 
				
			||||||
 | 
					        free(metadata.data.music.title);
 | 
				
			||||||
 | 
					        free(metadata.data.music.fileName);
 | 
				
			||||||
 | 
					        free(metadata.data.music.album);
 | 
				
			||||||
 | 
					        free(metadata.data.music.artist);
 | 
				
			||||||
 | 
					        delete metadata.data.music.tracks;
 | 
				
			||||||
 | 
					    } else if(MASK_SET(metadata.dataType, Video | File)) {
 | 
				
			||||||
 | 
					        free(metadata.data.video.title);
 | 
				
			||||||
 | 
					        free(metadata.data.video.explanation);
 | 
				
			||||||
 | 
					        free(metadata.data.video.fileName);
 | 
				
			||||||
 | 
					        free(metadata.data.video.copyright);
 | 
				
			||||||
 | 
					        delete metadata.data.video.tracks;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CMAObject::loadSfoMetadata(const QString &path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QString sfo = QDir(path).absoluteFilePath("PARAM.SFO");
 | 
				
			||||||
 | 
					    SfoReader reader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(reader.load(sfo)) {
 | 
				
			||||||
 | 
					        metadata.data.saveData.title = strdup(reader.value("TITLE", ""));
 | 
				
			||||||
 | 
					        metadata.data.saveData.detail = strdup(reader.value("SAVEDATA_DETAIL", ""));
 | 
				
			||||||
 | 
					        metadata.data.saveData.savedataTitle = strdup(reader.value("SAVEDATA_TITLE", ""));
 | 
				
			||||||
 | 
					        metadata.data.saveData.dateTimeUpdated = QFileInfo(sfo).created().toTime_t();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        metadata.data.saveData.title = strdup(metadata.name);
 | 
				
			||||||
 | 
					        metadata.data.saveData.detail = strdup("");
 | 
				
			||||||
 | 
					        metadata.data.saveData.savedataTitle = strdup("");
 | 
				
			||||||
 | 
					        metadata.data.saveData.dateTimeUpdated = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CMAObject::loadMusicMetadata(const QString &path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MediaInfoLib::MediaInfo media;
 | 
				
			||||||
 | 
					    if(media.Open(path.toStdWString())) {
 | 
				
			||||||
 | 
					        QString data;
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_General, 0, MediaInfoLib::General_Album));
 | 
				
			||||||
 | 
					        metadata.data.music.album = strdup(!data.isEmpty() ? data.toUtf8().data() : (parent->metadata.name ? parent->metadata.name : ""));
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_General, 0, MediaInfoLib::General_Performer));
 | 
				
			||||||
 | 
					        metadata.data.music.artist = strdup(data.toUtf8().data());
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_General, 0, MediaInfoLib::General_Title));
 | 
				
			||||||
 | 
					        metadata.data.music.title = strdup(!data.isEmpty() ? data.toUtf8().data() : metadata.name);
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_Audio, 0, MediaInfoLib::Audio_BitRate));
 | 
				
			||||||
 | 
					        bool ok;
 | 
				
			||||||
 | 
					        int bitrate = data.toInt(&ok);
 | 
				
			||||||
 | 
					        if(ok) {
 | 
				
			||||||
 | 
					            metadata.data.music.tracks->data.track_audio.bitrate = bitrate;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        metadata.data.music.album = strdup(parent->metadata.name ? parent->metadata.name : "");
 | 
				
			||||||
 | 
					        metadata.data.music.artist = strdup("");
 | 
				
			||||||
 | 
					        metadata.data.music.title = strdup(metadata.name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CMAObject::loadVideoMetadata(const QString &path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MediaInfoLib::MediaInfo media;
 | 
				
			||||||
 | 
					    if(media.Open(path.toStdWString())) {
 | 
				
			||||||
 | 
					        bool ok;
 | 
				
			||||||
 | 
					        QString data;
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_General, 0, MediaInfoLib::General_Title));
 | 
				
			||||||
 | 
					        metadata.data.video.title = strdup(!data.isEmpty() ? data.toUtf8().data() : metadata.name);
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_General, 0, MediaInfoLib::General_Comment));
 | 
				
			||||||
 | 
					        metadata.data.video.explanation = strdup(data.toUtf8().data());
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_General, 0, MediaInfoLib::General_Copyright));
 | 
				
			||||||
 | 
					        metadata.data.video.copyright = strdup(data.toUtf8().data());
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_Video, 0, MediaInfoLib::Video_BitRate));
 | 
				
			||||||
 | 
					        int bitrate = data.toInt(&ok);
 | 
				
			||||||
 | 
					        if(ok) {
 | 
				
			||||||
 | 
					            metadata.data.video.tracks->data.track_video.bitrate = bitrate;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_Video, 0, MediaInfoLib::Video_Duration));
 | 
				
			||||||
 | 
					        int duration = data.toInt(&ok);
 | 
				
			||||||
 | 
					        if(ok) {
 | 
				
			||||||
 | 
					            metadata.data.video.tracks->data.track_video.duration = duration;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_Video, 0, MediaInfoLib::Video_Width));
 | 
				
			||||||
 | 
					        int width = data.toInt(&ok);
 | 
				
			||||||
 | 
					        if(ok) {
 | 
				
			||||||
 | 
					            metadata.data.video.tracks->data.track_video.width = width;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_Video, 0, MediaInfoLib::Video_Height));
 | 
				
			||||||
 | 
					        int height = data.toInt(&ok);
 | 
				
			||||||
 | 
					        if(ok) {
 | 
				
			||||||
 | 
					            metadata.data.video.tracks->data.track_video.height = height;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        metadata.data.video.title = strdup(metadata.name);
 | 
				
			||||||
 | 
					        metadata.data.video.explanation = strdup("");
 | 
				
			||||||
 | 
					        metadata.data.video.copyright = strdup("");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CMAObject::loadPhotoMetadata(const QString &path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MediaInfoLib::MediaInfo media;
 | 
				
			||||||
 | 
					    if(media.Open(path.toStdWString())) {
 | 
				
			||||||
 | 
					        bool ok;
 | 
				
			||||||
 | 
					        QString data;
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_General, 0, MediaInfoLib::General_Title));
 | 
				
			||||||
 | 
					        metadata.data.photo.title = strdup(!data.isEmpty() ? data.toUtf8().data() : metadata.name);
 | 
				
			||||||
 | 
					        data = QString::fromStdWString(media.Get(MediaInfoLib::Stream_Image, 0, MediaInfoLib::Image_Height));
 | 
				
			||||||
 | 
					        int height = data.toInt(&ok);
 | 
				
			||||||
 | 
					        if(ok) {
 | 
				
			||||||
 | 
					            metadata.data.photo.tracks->data.track_photo.height = height;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        int width = data.toInt(&ok);
 | 
				
			||||||
 | 
					        if(ok) {
 | 
				
			||||||
 | 
					            metadata.data.photo.tracks->data.track_photo.width = width;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        metadata.data.photo.title = strdup(metadata.name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CMAObject::initObject(const QFileInfo &file)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    metadata.name = strdup(file.fileName().toUtf8().data());
 | 
				
			||||||
 | 
					    metadata.ohfiParent = parent->metadata.ohfi;
 | 
				
			||||||
 | 
					    metadata.ohfi = ohfi_count++;
 | 
				
			||||||
 | 
					    if(metadata.ohfi == 1494) {
 | 
				
			||||||
 | 
					        metadata.ohfi = metadata.ohfi;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    metadata.type = VITA_DIR_TYPE_MASK_REGULAR; // ignored for files
 | 
				
			||||||
 | 
					    metadata.dateTimeCreated = file.created().toTime_t();
 | 
				
			||||||
 | 
					    metadata.size = file.size();
 | 
				
			||||||
 | 
					    DataType type = file.isFile() ? File : Folder;
 | 
				
			||||||
 | 
					    metadata.dataType = (DataType)(type | (parent->metadata.dataType & ~Folder));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // create additional metadata
 | 
				
			||||||
 | 
					    if(MASK_SET(metadata.dataType, SaveData | Folder)) {
 | 
				
			||||||
 | 
					        metadata.data.saveData.dirName = strdup(metadata.name);
 | 
				
			||||||
 | 
					        metadata.data.saveData.statusType = 1;        
 | 
				
			||||||
 | 
					        loadSfoMetadata(file.absoluteFilePath());
 | 
				
			||||||
 | 
					    } else if(MASK_SET(metadata.dataType, Music | File)) {
 | 
				
			||||||
 | 
					        metadata.data.music.fileName = strdup(metadata.name);
 | 
				
			||||||
 | 
					        metadata.data.music.fileFormatType = 20;
 | 
				
			||||||
 | 
					        metadata.data.music.statusType = 1;
 | 
				
			||||||
 | 
					        metadata.data.music.numTracks = 1;
 | 
				
			||||||
 | 
					        metadata.data.music.tracks = new media_track();
 | 
				
			||||||
 | 
					        metadata.data.music.tracks->type = VITA_TRACK_TYPE_AUDIO;
 | 
				
			||||||
 | 
					        metadata.data.music.tracks->data.track_photo.codecType = 12; // MP3?
 | 
				
			||||||
 | 
					        loadMusicMetadata(file.absoluteFilePath());
 | 
				
			||||||
 | 
					    } else if(MASK_SET(metadata.dataType, Video | File)) {
 | 
				
			||||||
 | 
					        metadata.data.video.fileName = strdup(metadata.name);
 | 
				
			||||||
 | 
					        metadata.data.video.dateTimeUpdated = file.created().toTime_t();
 | 
				
			||||||
 | 
					        metadata.data.video.statusType = 1;
 | 
				
			||||||
 | 
					        metadata.data.video.fileFormatType = 1;
 | 
				
			||||||
 | 
					        metadata.data.video.parentalLevel = 0;
 | 
				
			||||||
 | 
					        metadata.data.video.numTracks = 1;
 | 
				
			||||||
 | 
					        metadata.data.video.tracks = new media_track();
 | 
				
			||||||
 | 
					        metadata.data.video.tracks->type = VITA_TRACK_TYPE_VIDEO;
 | 
				
			||||||
 | 
					        metadata.data.video.tracks->data.track_video.codecType = 3; // this codec is working
 | 
				
			||||||
 | 
					        loadVideoMetadata(file.absoluteFilePath());
 | 
				
			||||||
 | 
					    } else if(MASK_SET(metadata.dataType, Photo | File)) {
 | 
				
			||||||
 | 
					        metadata.data.photo.fileName = strdup(metadata.name);
 | 
				
			||||||
 | 
					        metadata.data.photo.fileFormatType = 28; // working
 | 
				
			||||||
 | 
					        metadata.data.photo.statusType = 1;
 | 
				
			||||||
 | 
					        metadata.data.photo.dateTimeOriginal = file.created().toTime_t();
 | 
				
			||||||
 | 
					        metadata.data.photo.numTracks = 1;
 | 
				
			||||||
 | 
					        metadata.data.photo.tracks = new media_track();
 | 
				
			||||||
 | 
					        metadata.data.photo.tracks->type = VITA_TRACK_TYPE_PHOTO;
 | 
				
			||||||
 | 
					        metadata.data.photo.tracks->data.track_photo.codecType = 17; // JPEG?
 | 
				
			||||||
 | 
					        loadPhotoMetadata(file.absoluteFilePath());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    path = file.absoluteFilePath();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(parent->metadata.path == NULL) {
 | 
				
			||||||
 | 
					        metadata.path = strdup(metadata.name);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        QString newpath = QString(parent->metadata.path) + QDir::separator() + metadata.name;
 | 
				
			||||||
 | 
					        metadata.path = strdup(newpath.toUtf8().data());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    updateParentSize(metadata.size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CMAObject::removeReferencedObject()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(metadata.dataType & Folder) {
 | 
				
			||||||
 | 
					        return removeRecursively(path);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return QFile::remove(path);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CMAObject::updateParentSize(unsigned long size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(parent) {
 | 
				
			||||||
 | 
					        parent->metadata.size += size;
 | 
				
			||||||
 | 
					        parent->updateParentSize(size);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CMAObject::rename(const QString &newname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    free(metadata.name);
 | 
				
			||||||
 | 
					    metadata.name = strdup(newname.toUtf8().data());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(metadata.path) {
 | 
				
			||||||
 | 
					        QStringList metadata_path(QString(metadata.path).split(QDir::separator()));
 | 
				
			||||||
 | 
					        metadata_path.replace(metadata_path.count() - 1, newname);
 | 
				
			||||||
 | 
					        free(metadata.path);
 | 
				
			||||||
 | 
					        metadata.path = strdup(metadata_path.join(QDir::separator()).toUtf8().data());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    path = QFileInfo(path).absoluteDir().path() + QDir::separator() + newname;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CMAObject::refreshPath()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(parent) {
 | 
				
			||||||
 | 
					        free(metadata.path);
 | 
				
			||||||
 | 
					        QString newpath(QString(parent->metadata.path) + QDir::separator() + metadata.name);
 | 
				
			||||||
 | 
					        metadata.path = strdup(newpath.toUtf8().data());
 | 
				
			||||||
 | 
					        path = parent->path + QDir::separator() + metadata.name;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CMAObject::hasParent(const CMAObject *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(parent) {
 | 
				
			||||||
 | 
					        if(metadata.ohfiParent == obj->metadata.ohfi) {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return parent->hasParent(obj);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CMAObject::operator==(const CMAObject &obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return metadata.ohfi == obj.metadata.ohfi;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CMAObject::operator!=(const CMAObject &obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return metadata.ohfi != obj.metadata.ohfi;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CMAObject::operator<(const CMAObject &obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return metadata.ohfi < obj.metadata.ohfi;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										71
									
								
								cmaobject.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								cmaobject.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CMAOBJECT_H
 | 
				
			||||||
 | 
					#define CMAOBJECT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QFileInfo>
 | 
				
			||||||
 | 
					#include <QString>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include <vitamtp.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OHFI_OFFSET 1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CMAObject
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit CMAObject(CMAObject *parent = 0);
 | 
				
			||||||
 | 
					    ~CMAObject();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void refreshPath();
 | 
				
			||||||
 | 
					    void rename(const QString &name);
 | 
				
			||||||
 | 
					    bool removeReferencedObject();
 | 
				
			||||||
 | 
					    void initObject(const QFileInfo &file);
 | 
				
			||||||
 | 
					    void updateParentSize(unsigned long size);
 | 
				
			||||||
 | 
					    bool hasParent(const CMAObject *obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool operator==(const CMAObject &obj);
 | 
				
			||||||
 | 
					    bool operator!=(const CMAObject &obj);
 | 
				
			||||||
 | 
					    bool operator<(const CMAObject &obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void setOhfi(int ohfi) {
 | 
				
			||||||
 | 
					        metadata.ohfi = ohfi;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static void resetOhfiCounter() {
 | 
				
			||||||
 | 
					        ohfi_count = OHFI_OFFSET;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QString path;
 | 
				
			||||||
 | 
					    CMAObject *parent;
 | 
				
			||||||
 | 
					    metadata_t metadata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					    static int ohfi_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    void loadSfoMetadata(const QString &path);
 | 
				
			||||||
 | 
					    void loadMusicMetadata(const QString &path);
 | 
				
			||||||
 | 
					    void loadVideoMetadata(const QString &path);
 | 
				
			||||||
 | 
					    void loadPhotoMetadata(const QString &path);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CMAOBJECT_H
 | 
				
			||||||
							
								
								
									
										139
									
								
								cmarootobject.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								cmarootobject.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "cmarootobject.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QDir>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QString CMARootObject::uuid = "ffffffffffffffff";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMARootObject::CMARootObject(int ohfi) :
 | 
				
			||||||
 | 
					    num_filters(0), filters(NULL), root_ohfi(ohfi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CMARootObject::initObject(const QString &path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    metadata.ohfi = root_ohfi;
 | 
				
			||||||
 | 
					    metadata.type = VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_REGULAR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch(root_ohfi) {
 | 
				
			||||||
 | 
					        case VITA_OHFI_PHOTO:
 | 
				
			||||||
 | 
					            metadata.dataType = Photo;
 | 
				
			||||||
 | 
					            this->path = path;
 | 
				
			||||||
 | 
					            num_filters = 2;
 | 
				
			||||||
 | 
					            filters = new metadata_t[2];
 | 
				
			||||||
 | 
					            createFilter(&filters[0], "Folders", VITA_DIR_TYPE_MASK_PHOTO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_REGULAR);
 | 
				
			||||||
 | 
					            createFilter(&filters[1], "All", VITA_DIR_TYPE_MASK_PHOTO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ALL);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case VITA_OHFI_VIDEO:
 | 
				
			||||||
 | 
					            metadata.dataType = Video;
 | 
				
			||||||
 | 
					            this->path = path;
 | 
				
			||||||
 | 
					            num_filters = 2;
 | 
				
			||||||
 | 
					            filters = new metadata_t[2];
 | 
				
			||||||
 | 
					            createFilter(&filters[0], "Folders", VITA_DIR_TYPE_MASK_VIDEO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_REGULAR);
 | 
				
			||||||
 | 
					            createFilter(&filters[1], "All", VITA_DIR_TYPE_MASK_VIDEO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ALL);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case VITA_OHFI_MUSIC:
 | 
				
			||||||
 | 
					            metadata.dataType = Music;
 | 
				
			||||||
 | 
					            this->path = path;
 | 
				
			||||||
 | 
					            num_filters = 1;
 | 
				
			||||||
 | 
					            filters = new metadata_t[1];
 | 
				
			||||||
 | 
					            //createFilter(&filters[0], "Folders", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_PLAYLISTS);
 | 
				
			||||||
 | 
					            createFilter(&filters[0], "All", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_SONGS);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case VITA_OHFI_VITAAPP:
 | 
				
			||||||
 | 
					            metadata.dataType = App;
 | 
				
			||||||
 | 
					            this->path = QDir(QDir(path).absoluteFilePath("APP")).absoluteFilePath(uuid);
 | 
				
			||||||
 | 
					            num_filters = 0;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case VITA_OHFI_PSPAPP:
 | 
				
			||||||
 | 
					            metadata.dataType = App;
 | 
				
			||||||
 | 
					            this->path = QDir(QDir(path).absoluteFilePath("PGAME")).absoluteFilePath(uuid);
 | 
				
			||||||
 | 
					            num_filters = 0;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case VITA_OHFI_PSPSAVE:
 | 
				
			||||||
 | 
					            metadata.dataType = SaveData;
 | 
				
			||||||
 | 
					            this->path = QDir(QDir(path).absoluteFilePath("PSAVEDATA")).absoluteFilePath(uuid);
 | 
				
			||||||
 | 
					            num_filters = 0;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case VITA_OHFI_PSXAPP:
 | 
				
			||||||
 | 
					            metadata.dataType = App;
 | 
				
			||||||
 | 
					            this->path = QDir(QDir(path).absoluteFilePath("PSGAME")).absoluteFilePath(uuid);
 | 
				
			||||||
 | 
					            num_filters = 0;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case VITA_OHFI_PSMAPP:
 | 
				
			||||||
 | 
					            metadata.dataType = App;
 | 
				
			||||||
 | 
					            this->path = QDir(QDir(path).absoluteFilePath("PSM")).absoluteFilePath(uuid);
 | 
				
			||||||
 | 
					            num_filters = 0;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case VITA_OHFI_BACKUP:
 | 
				
			||||||
 | 
					            metadata.dataType = App;
 | 
				
			||||||
 | 
					            this->path = QDir(QDir(path).absoluteFilePath("SYSTEM")).absoluteFilePath(uuid);
 | 
				
			||||||
 | 
					            num_filters = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMARootObject::~CMARootObject()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for(int i = 0; i < num_filters; i++) {
 | 
				
			||||||
 | 
					        free(filters[i].name);
 | 
				
			||||||
 | 
					        free(filters[i].path);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    delete[] filters;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CMARootObject::createFilter(metadata_t *filter, const char *name, int type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    filter->ohfiParent = metadata.ohfi;
 | 
				
			||||||
 | 
					    filter->ohfi = ohfi_count++;
 | 
				
			||||||
 | 
					    filter->name = strdup(name);
 | 
				
			||||||
 | 
					    filter->path = strdup(metadata.path ? metadata.path : "");
 | 
				
			||||||
 | 
					    filter->type = type;
 | 
				
			||||||
 | 
					    filter->dateTimeCreated = 0;
 | 
				
			||||||
 | 
					    filter->size = 0;
 | 
				
			||||||
 | 
					    filter->dataType = static_cast<DataType>(Folder | Special);
 | 
				
			||||||
 | 
					    filter->next_metadata = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int CMARootObject::getFilters(metadata_t **p_head)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int numObjects = num_filters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0; i < numObjects; i++) {
 | 
				
			||||||
 | 
					        filters[i].next_metadata = &filters[i + 1];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    filters[numObjects - 1].next_metadata = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(p_head != NULL) {
 | 
				
			||||||
 | 
					        *p_head = filters;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return numObjects;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										51
									
								
								cmarootobject.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								cmarootobject.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CMAROOTOBJECT_H
 | 
				
			||||||
 | 
					#define CMAROOTOBJECT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "cmaobject.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QList>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include <vitamtp.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CMARootObject : public CMAObject
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit CMARootObject(int ohfi);
 | 
				
			||||||
 | 
					    ~CMARootObject();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void initObject(const QString &path);
 | 
				
			||||||
 | 
					    void remove(const CMAObject *obj);
 | 
				
			||||||
 | 
					    int getFilters(metadata_t **p_head);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int num_filters;
 | 
				
			||||||
 | 
					    metadata_t *filters;
 | 
				
			||||||
 | 
					    static QString uuid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    void createFilter(metadata_t *filter, const char *name, int type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int root_ohfi;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CMAROOTOBJECT_H
 | 
				
			||||||
							
								
								
									
										155
									
								
								configwidget.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								configwidget.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "configwidget.h"
 | 
				
			||||||
 | 
					#include "ui_configwidget.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include <vitamtp.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QFileDialog>
 | 
				
			||||||
 | 
					#include <QSettings>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
 | 
				
			||||||
 | 
					#include <QStandardPaths>
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#include <QDesktopServices>
 | 
				
			||||||
 | 
					#define QStandardPaths QDesktopServices
 | 
				
			||||||
 | 
					#define writableLocation storageLocation
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ConfigWidget::ConfigWidget(QWidget *parent) :
 | 
				
			||||||
 | 
					    QDialog(parent),
 | 
				
			||||||
 | 
					    ui(new Ui::ConfigWidget)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ui->setupUi(this);
 | 
				
			||||||
 | 
					    connectSignals();
 | 
				
			||||||
 | 
					    setDefaultDirs();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigWidget::connectSignals()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QSignalMapper *mapper = new QSignalMapper(this);
 | 
				
			||||||
 | 
					    mapper->setMapping(ui->photoBtn, BTN_PHOTO);
 | 
				
			||||||
 | 
					    mapper->setMapping(ui->musicBtn, BTN_MUSIC);
 | 
				
			||||||
 | 
					    mapper->setMapping(ui->videoBtn, BTN_VIDEO);
 | 
				
			||||||
 | 
					    mapper->setMapping(ui->appBtn, BTN_APPS);
 | 
				
			||||||
 | 
					    mapper->setMapping(ui->urlBtn, BTN_URL);
 | 
				
			||||||
 | 
					    connect(ui->photoBtn, SIGNAL(clicked()), mapper, SLOT(map()));
 | 
				
			||||||
 | 
					    connect(ui->musicBtn, SIGNAL(clicked()), mapper, SLOT(map()));
 | 
				
			||||||
 | 
					    connect(ui->videoBtn, SIGNAL(clicked()), mapper, SLOT(map()));
 | 
				
			||||||
 | 
					    connect(ui->appBtn, SIGNAL(clicked()), mapper, SLOT(map()));
 | 
				
			||||||
 | 
					    connect(ui->urlBtn, SIGNAL(clicked()), mapper, SLOT(map()));
 | 
				
			||||||
 | 
					    connect(mapper, SIGNAL(mapped(int)), this, SLOT(browseBtnPressed(int)));
 | 
				
			||||||
 | 
					    connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
 | 
				
			||||||
 | 
					    connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigWidget::setDefaultDirs()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QString defaultdir;
 | 
				
			||||||
 | 
					    QSettings settings;
 | 
				
			||||||
 | 
					    defaultdir = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
 | 
				
			||||||
 | 
					    ui->photoPath->setText(settings.value("photoPath", defaultdir).toString());
 | 
				
			||||||
 | 
					    defaultdir = QStandardPaths::writableLocation(QStandardPaths::MusicLocation);
 | 
				
			||||||
 | 
					    ui->musicPath->setText(settings.value("musicPath", defaultdir).toString());
 | 
				
			||||||
 | 
					    defaultdir = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
 | 
				
			||||||
 | 
					    ui->videoPath->setText(settings.value("videoPath", defaultdir).toString());
 | 
				
			||||||
 | 
					    defaultdir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
 | 
				
			||||||
 | 
					    defaultdir.append(QDir::separator()).append("PS Vita");
 | 
				
			||||||
 | 
					    ui->appPath->setText(settings.value("appsPath", defaultdir).toString());
 | 
				
			||||||
 | 
					    defaultdir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
 | 
				
			||||||
 | 
					    defaultdir.append(QDir::separator()).append("PSV Updates");
 | 
				
			||||||
 | 
					    ui->urlPath->setText(settings.value("urlPath", defaultdir).toString());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ConfigWidget::~ConfigWidget()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    delete ui;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigWidget::browseBtnPressed(int btn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QString msg;
 | 
				
			||||||
 | 
					    QLineEdit *lineedit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch(btn) {
 | 
				
			||||||
 | 
					        case BTN_PHOTO:
 | 
				
			||||||
 | 
					            lineedit = ui->photoPath;
 | 
				
			||||||
 | 
					            msg = tr("Select the folder to be used as a photo source");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case BTN_MUSIC:
 | 
				
			||||||
 | 
					            lineedit = ui->musicPath;
 | 
				
			||||||
 | 
					            msg = tr("Select the folder to be used as a music source");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case BTN_VIDEO:
 | 
				
			||||||
 | 
					            lineedit = ui->videoPath;
 | 
				
			||||||
 | 
					            msg = tr("Select the folder to be used as a video source");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case BTN_APPS:
 | 
				
			||||||
 | 
					            lineedit = ui->appPath;
 | 
				
			||||||
 | 
					            msg = tr("Select the folder to be used to save PS Vita games and backups");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case BTN_URL:
 | 
				
			||||||
 | 
					            lineedit = ui->urlPath;
 | 
				
			||||||
 | 
					            msg = tr("Select the folder to be used to fetch software updates");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QFileDialog dialog;
 | 
				
			||||||
 | 
					    dialog.setFileMode(QFileDialog::Directory);
 | 
				
			||||||
 | 
					    dialog.setOption(QFileDialog::ShowDirsOnly);
 | 
				
			||||||
 | 
					    dialog.setDirectory(lineedit->text());
 | 
				
			||||||
 | 
					    dialog.setWindowTitle(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(dialog.exec()) {
 | 
				
			||||||
 | 
					        QStringList list = dialog.selectedFiles();
 | 
				
			||||||
 | 
					        lineedit->setText(list.first());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigWidget::savePath(QSettings &settings, const QLineEdit *edit, const QString &key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QString path = edit->text();
 | 
				
			||||||
 | 
					    if(path.endsWith(QDir::separator())) {
 | 
				
			||||||
 | 
					        path.chop(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    settings.setValue(key, path);
 | 
				
			||||||
 | 
					    QDir(QDir::root()).mkpath(path);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ConfigWidget::accept()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QSettings settings;    
 | 
				
			||||||
 | 
					    savePath(settings, ui->photoPath, "photoPath");
 | 
				
			||||||
 | 
					    savePath(settings, ui->musicPath, "musicPath");
 | 
				
			||||||
 | 
					    savePath(settings, ui->videoPath, "videoPath");
 | 
				
			||||||
 | 
					    savePath(settings, ui->appPath, "appsPath");
 | 
				
			||||||
 | 
					    savePath(settings, ui->urlPath, "urlPath");
 | 
				
			||||||
 | 
					    settings.sync();
 | 
				
			||||||
 | 
					    done(Accepted);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										55
									
								
								configwidget.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								configwidget.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CONFIGWIDGET_H
 | 
				
			||||||
 | 
					#define CONFIGWIDGET_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QDialog>
 | 
				
			||||||
 | 
					#include <QLineEdit>
 | 
				
			||||||
 | 
					#include <QSettings>
 | 
				
			||||||
 | 
					#include <QSignalMapper>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ui
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					class ConfigWidget;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConfigWidget : public QDialog
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit ConfigWidget(QWidget *parent = 0);
 | 
				
			||||||
 | 
					    ~ConfigWidget();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    enum browse_buttons {BTN_PHOTO, BTN_MUSIC, BTN_VIDEO, BTN_APPS, BTN_URL};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void connectSignals();
 | 
				
			||||||
 | 
					    void setDefaultDirs();
 | 
				
			||||||
 | 
					    void savePath(QSettings &settings, const QLineEdit *edit, const QString &key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ui::ConfigWidget *ui;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
					    void browseBtnPressed(int from);
 | 
				
			||||||
 | 
					    void accept();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // CONFIGWIDGET_H
 | 
				
			||||||
							
								
								
									
										210
									
								
								configwidget.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								configwidget.ui
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,210 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>ConfigWidget</class>
 | 
				
			||||||
 | 
					 <widget class="QWidget" name="ConfigWidget">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>520</width>
 | 
				
			||||||
 | 
					    <height>405</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>QCMA Settings</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QGridLayout" name="gridLayout">
 | 
				
			||||||
 | 
					   <item row="0" column="0">
 | 
				
			||||||
 | 
					    <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					     <item>
 | 
				
			||||||
 | 
					      <widget class="QTabWidget" name="tabWidget">
 | 
				
			||||||
 | 
					       <property name="currentIndex">
 | 
				
			||||||
 | 
					        <number>0</number>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					       <widget class="QWidget" name="tab">
 | 
				
			||||||
 | 
					        <attribute name="title">
 | 
				
			||||||
 | 
					         <string>Folders</string>
 | 
				
			||||||
 | 
					        </attribute>
 | 
				
			||||||
 | 
					        <layout class="QGridLayout" name="gridLayout_2">
 | 
				
			||||||
 | 
					         <item row="1" column="0">
 | 
				
			||||||
 | 
					          <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QLabel" name="label">
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Specify the folders that the PS Vita will access for each content type</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="wordWrap">
 | 
				
			||||||
 | 
					              <bool>true</bool>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <widget class="QLabel" name="label_2">
 | 
				
			||||||
 | 
					               <property name="text">
 | 
				
			||||||
 | 
					                <string>Photo Folder</string>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					              </widget>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <layout class="QHBoxLayout" name="horizontalLayout_7">
 | 
				
			||||||
 | 
					               <item>
 | 
				
			||||||
 | 
					                <widget class="QLineEdit" name="photoPath">
 | 
				
			||||||
 | 
					                 <property name="readOnly">
 | 
				
			||||||
 | 
					                  <bool>true</bool>
 | 
				
			||||||
 | 
					                 </property>
 | 
				
			||||||
 | 
					                </widget>
 | 
				
			||||||
 | 
					               </item>
 | 
				
			||||||
 | 
					               <item>
 | 
				
			||||||
 | 
					                <widget class="QPushButton" name="photoBtn">
 | 
				
			||||||
 | 
					                 <property name="text">
 | 
				
			||||||
 | 
					                  <string>Browse...</string>
 | 
				
			||||||
 | 
					                 </property>
 | 
				
			||||||
 | 
					                </widget>
 | 
				
			||||||
 | 
					               </item>
 | 
				
			||||||
 | 
					              </layout>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					            </layout>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <layout class="QVBoxLayout" name="verticalLayout_4">
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <widget class="QLabel" name="label_3">
 | 
				
			||||||
 | 
					               <property name="text">
 | 
				
			||||||
 | 
					                <string>Video Folder</string>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					              </widget>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <layout class="QHBoxLayout" name="horizontalLayout_8">
 | 
				
			||||||
 | 
					               <item>
 | 
				
			||||||
 | 
					                <widget class="QLineEdit" name="videoPath">
 | 
				
			||||||
 | 
					                 <property name="readOnly">
 | 
				
			||||||
 | 
					                  <bool>true</bool>
 | 
				
			||||||
 | 
					                 </property>
 | 
				
			||||||
 | 
					                </widget>
 | 
				
			||||||
 | 
					               </item>
 | 
				
			||||||
 | 
					               <item>
 | 
				
			||||||
 | 
					                <widget class="QPushButton" name="videoBtn">
 | 
				
			||||||
 | 
					                 <property name="text">
 | 
				
			||||||
 | 
					                  <string>Browse...</string>
 | 
				
			||||||
 | 
					                 </property>
 | 
				
			||||||
 | 
					                </widget>
 | 
				
			||||||
 | 
					               </item>
 | 
				
			||||||
 | 
					              </layout>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					            </layout>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <layout class="QVBoxLayout" name="verticalLayout_5">
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <widget class="QLabel" name="label_4">
 | 
				
			||||||
 | 
					               <property name="text">
 | 
				
			||||||
 | 
					                <string>Music Folder</string>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					              </widget>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <layout class="QHBoxLayout" name="horizontalLayout_9">
 | 
				
			||||||
 | 
					               <item>
 | 
				
			||||||
 | 
					                <widget class="QLineEdit" name="musicPath">
 | 
				
			||||||
 | 
					                 <property name="readOnly">
 | 
				
			||||||
 | 
					                  <bool>true</bool>
 | 
				
			||||||
 | 
					                 </property>
 | 
				
			||||||
 | 
					                </widget>
 | 
				
			||||||
 | 
					               </item>
 | 
				
			||||||
 | 
					               <item>
 | 
				
			||||||
 | 
					                <widget class="QPushButton" name="musicBtn">
 | 
				
			||||||
 | 
					                 <property name="text">
 | 
				
			||||||
 | 
					                  <string>Browse...</string>
 | 
				
			||||||
 | 
					                 </property>
 | 
				
			||||||
 | 
					                </widget>
 | 
				
			||||||
 | 
					               </item>
 | 
				
			||||||
 | 
					              </layout>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					            </layout>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <layout class="QVBoxLayout" name="verticalLayout_7">
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <widget class="QLabel" name="label_6">
 | 
				
			||||||
 | 
					               <property name="text">
 | 
				
			||||||
 | 
					                <string>Applications / Backups</string>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					              </widget>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <layout class="QHBoxLayout" name="horizontalLayout_2">
 | 
				
			||||||
 | 
					               <item>
 | 
				
			||||||
 | 
					                <widget class="QLineEdit" name="appPath">
 | 
				
			||||||
 | 
					                 <property name="readOnly">
 | 
				
			||||||
 | 
					                  <bool>true</bool>
 | 
				
			||||||
 | 
					                 </property>
 | 
				
			||||||
 | 
					                </widget>
 | 
				
			||||||
 | 
					               </item>
 | 
				
			||||||
 | 
					               <item>
 | 
				
			||||||
 | 
					                <widget class="QPushButton" name="appBtn">
 | 
				
			||||||
 | 
					                 <property name="text">
 | 
				
			||||||
 | 
					                  <string>Browse...</string>
 | 
				
			||||||
 | 
					                 </property>
 | 
				
			||||||
 | 
					                </widget>
 | 
				
			||||||
 | 
					               </item>
 | 
				
			||||||
 | 
					              </layout>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					            </layout>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <layout class="QVBoxLayout" name="verticalLayout_6">
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <widget class="QLabel" name="label_5">
 | 
				
			||||||
 | 
					               <property name="text">
 | 
				
			||||||
 | 
					                <string>Updates / Web content</string>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					              </widget>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <layout class="QHBoxLayout" name="horizontalLayout_10">
 | 
				
			||||||
 | 
					               <item>
 | 
				
			||||||
 | 
					                <widget class="QLineEdit" name="urlPath">
 | 
				
			||||||
 | 
					                 <property name="readOnly">
 | 
				
			||||||
 | 
					                  <bool>true</bool>
 | 
				
			||||||
 | 
					                 </property>
 | 
				
			||||||
 | 
					                </widget>
 | 
				
			||||||
 | 
					               </item>
 | 
				
			||||||
 | 
					               <item>
 | 
				
			||||||
 | 
					                <widget class="QPushButton" name="urlBtn">
 | 
				
			||||||
 | 
					                 <property name="text">
 | 
				
			||||||
 | 
					                  <string>Browse...</string>
 | 
				
			||||||
 | 
					                 </property>
 | 
				
			||||||
 | 
					                </widget>
 | 
				
			||||||
 | 
					               </item>
 | 
				
			||||||
 | 
					              </layout>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					            </layout>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					          </layout>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					       <widget class="QWidget" name="tab_2">
 | 
				
			||||||
 | 
					        <attribute name="title">
 | 
				
			||||||
 | 
					         <string>Other</string>
 | 
				
			||||||
 | 
					        </attribute>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </widget>
 | 
				
			||||||
 | 
					     </item>
 | 
				
			||||||
 | 
					     <item>
 | 
				
			||||||
 | 
					      <widget class="QDialogButtonBox" name="buttonBox">
 | 
				
			||||||
 | 
					       <property name="standardButtons">
 | 
				
			||||||
 | 
					        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
				
			||||||
 | 
					       </property>
 | 
				
			||||||
 | 
					      </widget>
 | 
				
			||||||
 | 
					     </item>
 | 
				
			||||||
 | 
					    </layout>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections/>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
							
								
								
									
										334
									
								
								database.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								database.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,334 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "database.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QDir>
 | 
				
			||||||
 | 
					#include <QDirIterator>
 | 
				
			||||||
 | 
					#include <QSettings>
 | 
				
			||||||
 | 
					#include <QTextStream>
 | 
				
			||||||
 | 
					#include <QDebug>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OHFI_OFFSET 1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Database::Database(QObject *parent) :
 | 
				
			||||||
 | 
					    QObject(parent), mutex(QMutex::Recursive)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Database::~Database()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    destroy();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Database::setUUID(const QString uuid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CMARootObject::uuid = uuid;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Database::create()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int total_objects = 0;
 | 
				
			||||||
 | 
					    QMutexLocker locker(&mutex);
 | 
				
			||||||
 | 
					    const int ohfi_array[] = { VITA_OHFI_MUSIC, VITA_OHFI_PHOTO, VITA_OHFI_VIDEO,
 | 
				
			||||||
 | 
					                               VITA_OHFI_BACKUP, VITA_OHFI_VITAAPP, VITA_OHFI_PSPAPP,
 | 
				
			||||||
 | 
					                               VITA_OHFI_PSPSAVE, VITA_OHFI_PSXAPP, VITA_OHFI_PSMAPP
 | 
				
			||||||
 | 
					                             };
 | 
				
			||||||
 | 
					    CMAObject::resetOhfiCounter();
 | 
				
			||||||
 | 
					    QSettings settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i = 0, max = sizeof(ohfi_array) / sizeof(int); i < max; i++) {
 | 
				
			||||||
 | 
					        CMARootObject *obj = new CMARootObject(ohfi_array[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch(ohfi_array[i]) {
 | 
				
			||||||
 | 
					            case VITA_OHFI_MUSIC:
 | 
				
			||||||
 | 
					                obj->initObject(settings.value("musicPath").toString());
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case VITA_OHFI_PHOTO:
 | 
				
			||||||
 | 
					                obj->initObject(settings.value("photoPath").toString());
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case VITA_OHFI_VIDEO:
 | 
				
			||||||
 | 
					                obj->initObject(settings.value("videoPath").toString());
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case VITA_OHFI_BACKUP:
 | 
				
			||||||
 | 
					            case VITA_OHFI_VITAAPP:
 | 
				
			||||||
 | 
					            case VITA_OHFI_PSPAPP:
 | 
				
			||||||
 | 
					            case VITA_OHFI_PSPSAVE:
 | 
				
			||||||
 | 
					            case VITA_OHFI_PSXAPP:
 | 
				
			||||||
 | 
					            case VITA_OHFI_PSMAPP:
 | 
				
			||||||
 | 
					                obj->initObject(settings.value("appsPath").toString());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        root_list list;
 | 
				
			||||||
 | 
					        list << obj;
 | 
				
			||||||
 | 
					        total_objects += scanRootDirectory(list);
 | 
				
			||||||
 | 
					        object_list[ohfi_array[i]] = list;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return total_objects;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMAObject *Database::getParent(CMAObject *last_dir, const QString ¤t_path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    while(last_dir && current_path != last_dir->path) {
 | 
				
			||||||
 | 
					        last_dir = last_dir->parent;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return last_dir;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Database::scanRootDirectory(root_list &list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int total_objects = 0;
 | 
				
			||||||
 | 
					    CMAObject *last_dir = list.first();
 | 
				
			||||||
 | 
					    QDir dir(last_dir->path);
 | 
				
			||||||
 | 
					    dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
 | 
				
			||||||
 | 
					    QDirIterator it(dir, QDirIterator::Subdirectories);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(it.hasNext()) {
 | 
				
			||||||
 | 
					        it.next();
 | 
				
			||||||
 | 
					        CMAObject *obj = new CMAObject(getParent(last_dir, it.fileInfo().path()));
 | 
				
			||||||
 | 
					        obj->initObject(it.fileInfo());
 | 
				
			||||||
 | 
					        list << obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(obj->metadata.dataType & Folder) {
 | 
				
			||||||
 | 
					            last_dir = obj;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            total_objects++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return total_objects;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Database::destroy()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QMutexLocker locker(&mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
 | 
				
			||||||
 | 
					        qDeleteAll(*root);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    object_list.clear();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Database::removeInternal(root_list &list, const CMAObject *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    bool found = false;
 | 
				
			||||||
 | 
					    QList<CMAObject *>::iterator it = list.begin();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(it != list.end()) {
 | 
				
			||||||
 | 
					        if(!found && (*it) == obj) {
 | 
				
			||||||
 | 
					            it = list.erase(it);
 | 
				
			||||||
 | 
					            found = true;
 | 
				
			||||||
 | 
					        } else if(found && (*it)->metadata.ohfiParent == obj->metadata.ohfi) {
 | 
				
			||||||
 | 
					            it = list.erase(it);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ++it;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return found;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Database::remove(const CMAObject *obj, int ohfi_root)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QMutexLocker locker(&mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(ohfi_root) {
 | 
				
			||||||
 | 
					        return removeInternal(object_list[ohfi_root], obj);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
 | 
				
			||||||
 | 
					            if(removeInternal(*root, obj)) {
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Database::lessThanComparator(const CMAObject *a, const CMAObject *b)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return a->metadata.ohfi < b->metadata.ohfi;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Database::hasFilter(const CMARootObject *object,int ohfi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for(int i = 0; i < object->num_filters; i++) {
 | 
				
			||||||
 | 
					        if(object->filters[i].ohfi == ohfi) {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Database::findInternal(const root_list &list, int ohfi, find_data &data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(hasFilter(static_cast<CMARootObject *>(list.first()), ohfi)) {
 | 
				
			||||||
 | 
					        data.it = list.begin();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        CMAObject obj;
 | 
				
			||||||
 | 
					        obj.setOhfi(ohfi);
 | 
				
			||||||
 | 
					        data.it = qBinaryFind(list.begin(), list.end(), &obj, Database::lessThanComparator);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    data.end = list.end();
 | 
				
			||||||
 | 
					    return data.it != data.end;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Database::find(int ohfi, Database::find_data &data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QMutexLocker locker(&mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
 | 
				
			||||||
 | 
					        if(findInternal(*root, ohfi, data)) {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Database::append(int parent_ohfi, CMAObject *object)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QMutexLocker locker(&mutex);
 | 
				
			||||||
 | 
					    CMAObject parent;
 | 
				
			||||||
 | 
					    parent.setOhfi(parent_ohfi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
 | 
				
			||||||
 | 
					        root_list *cat_list = &(*root);
 | 
				
			||||||
 | 
					        root_list::const_iterator it = qBinaryFind(cat_list->begin(), cat_list->end(), &parent, Database::lessThanComparator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(it != cat_list->end()) {
 | 
				
			||||||
 | 
					            cat_list->append(object);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMAObject *Database::ohfiToObject(int ohfi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QMutexLocker locker(&mutex);
 | 
				
			||||||
 | 
					    find_data data;
 | 
				
			||||||
 | 
					    return find(ohfi, data) ? *data.it : NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMAObject *Database::pathToObjectInternal(const root_list &list, const char *path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // skip the first element since is the root element
 | 
				
			||||||
 | 
					    root_list::const_iterator skipped_first = ++list.begin();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(root_list::const_iterator obj = skipped_first; obj != list.end(); ++obj) {
 | 
				
			||||||
 | 
					        if(strcmp(path, (*obj)->metadata.path) == 0) {
 | 
				
			||||||
 | 
					            return (*obj);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMAObject *Database::pathToObject(const char *path, int ohfiRoot)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QMutexLocker locker(&mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(ohfiRoot && (*root).first()->metadata.ohfi != ohfiRoot) {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        CMAObject *obj = pathToObjectInternal(*root, path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(obj) {
 | 
				
			||||||
 | 
					            return obj;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Database::acceptFilteredObject(const CMAObject *parent, const CMAObject *current, int type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QMutexLocker locker(&mutex);
 | 
				
			||||||
 | 
					    int result = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(MASK_SET(type, VITA_DIR_TYPE_MASK_PHOTO)) {
 | 
				
			||||||
 | 
					        result = (current->metadata.dataType & Photo);
 | 
				
			||||||
 | 
					    } else if(MASK_SET(type, VITA_DIR_TYPE_MASK_VIDEO)) {
 | 
				
			||||||
 | 
					        result = (current->metadata.dataType & Video);
 | 
				
			||||||
 | 
					    } else if(MASK_SET(type, VITA_DIR_TYPE_MASK_MUSIC)) {
 | 
				
			||||||
 | 
					        result = (current->metadata.dataType & Music);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(type & (VITA_DIR_TYPE_MASK_ALL | VITA_DIR_TYPE_MASK_SONGS)) {
 | 
				
			||||||
 | 
					        result = result && (current->metadata.dataType & File);
 | 
				
			||||||
 | 
					    } else if(type & (VITA_DIR_TYPE_MASK_REGULAR)) {
 | 
				
			||||||
 | 
					        result = (parent->metadata.ohfi == current->metadata.ohfiParent);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: Support other filter types
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int Database::filterObjects(int ohfiParent, metadata_t **p_head)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QMutexLocker locker(&mutex);
 | 
				
			||||||
 | 
					    CMARootObject *parent = static_cast<CMARootObject *>(ohfiToObject(ohfiParent));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(parent == NULL) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int type = parent->metadata.type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(parent->metadata.ohfi < OHFI_OFFSET && parent->filters) { // if we have filters
 | 
				
			||||||
 | 
					        if(ohfiParent == parent->metadata.ohfi) { // if we are looking at root
 | 
				
			||||||
 | 
					            return parent->getFilters(p_head);
 | 
				
			||||||
 | 
					        } else { // we are looking at a filter
 | 
				
			||||||
 | 
					            for(int j = 0; j < parent->num_filters; j++) {
 | 
				
			||||||
 | 
					                if(parent->filters[j].ohfi == ohfiParent) {
 | 
				
			||||||
 | 
					                    type = parent->filters[j].type;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int numObjects = 0;
 | 
				
			||||||
 | 
					    metadata_t temp = metadata_t();
 | 
				
			||||||
 | 
					    metadata_t *tail = &temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
 | 
				
			||||||
 | 
					        for(root_list::iterator object = (*root).begin(); object != (*root).end(); ++object) {
 | 
				
			||||||
 | 
					            if(acceptFilteredObject(parent, *object, type)) {
 | 
				
			||||||
 | 
					                tail->next_metadata = &(*object)->metadata;
 | 
				
			||||||
 | 
					                tail = tail->next_metadata;
 | 
				
			||||||
 | 
					                numObjects++;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(numObjects > 0) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tail->next_metadata = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(p_head != NULL) {
 | 
				
			||||||
 | 
					        *p_head = temp.next_metadata;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return numObjects;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										79
									
								
								database.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								database.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DATABASE_H
 | 
				
			||||||
 | 
					#define DATABASE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "cmarootobject.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QList>
 | 
				
			||||||
 | 
					#include <QMap>
 | 
				
			||||||
 | 
					#include <QMutex>
 | 
				
			||||||
 | 
					#include <QObject>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include <vitamtp.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Database : public QObject
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    typedef struct {
 | 
				
			||||||
 | 
					        QList<CMAObject *>::const_iterator it;
 | 
				
			||||||
 | 
					        QList<CMAObject *>::const_iterator end;
 | 
				
			||||||
 | 
					    } find_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    explicit Database(QObject *parent = 0);
 | 
				
			||||||
 | 
					    ~Database();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void destroy();
 | 
				
			||||||
 | 
					    void setUUID(const QString uuid);
 | 
				
			||||||
 | 
					    int create();
 | 
				
			||||||
 | 
					    void addEntries(CMAObject *root);
 | 
				
			||||||
 | 
					    CMAObject *ohfiToObject(int ohfi);
 | 
				
			||||||
 | 
					    bool find(int ohfi, find_data &data);
 | 
				
			||||||
 | 
					    void append(int parent_ohfi, CMAObject *object);
 | 
				
			||||||
 | 
					    bool remove(const CMAObject *obj, int ohfi_root = 0);
 | 
				
			||||||
 | 
					    int filterObjects(int ohfiParent, metadata_t **p_head);
 | 
				
			||||||
 | 
					    CMAObject *pathToObject(const char *path, int ohfiRoot);
 | 
				
			||||||
 | 
					    int acceptFilteredObject(const CMAObject *parent, const CMAObject *current, int type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutex mutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    typedef QList<CMAObject *> root_list;
 | 
				
			||||||
 | 
					    typedef QMap<int, root_list> map_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int scanRootDirectory(root_list &list);
 | 
				
			||||||
 | 
					    bool hasFilter(const CMARootObject *object,int ohfi);
 | 
				
			||||||
 | 
					    bool removeInternal(root_list &list, const CMAObject *obj);
 | 
				
			||||||
 | 
					    bool findInternal(const root_list &list, int ohfi, find_data &data);
 | 
				
			||||||
 | 
					    CMAObject *getParent(CMAObject *last_dir, const QString ¤t_path);
 | 
				
			||||||
 | 
					    CMAObject *pathToObjectInternal(const root_list &list, const char *path);
 | 
				
			||||||
 | 
					    static bool lessThanComparator(const CMAObject *a, const CMAObject *b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    map_list object_list;    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
					    void finished();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // DATABASE_H
 | 
				
			||||||
							
								
								
									
										906
									
								
								listenerworker.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										906
									
								
								listenerworker.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,906 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "listenerworker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <locale.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QBuffer>
 | 
				
			||||||
 | 
					#include <QDateTime>
 | 
				
			||||||
 | 
					#include <QDir>
 | 
				
			||||||
 | 
					#include <QImage>
 | 
				
			||||||
 | 
					#include <QSettings>
 | 
				
			||||||
 | 
					#include <QUrl>
 | 
				
			||||||
 | 
					#include <QMutexLocker>
 | 
				
			||||||
 | 
					#include <QDebug>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CALL_MEMBER_FUNC(obj,memberptr)  ((obj).*(memberptr))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const metadata_t ListenerWorker::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ListenerWorker::ListenerWorker(QObject *parent) :
 | 
				
			||||||
 | 
					    BaseWorker(parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    connected = true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ListenerWorker::rebuildDatabase()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    db.destroy();
 | 
				
			||||||
 | 
					    return db.create();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::setDevice(vita_device_t *device)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    this->device = device;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ListenerWorker::isConnected()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return connected;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::disconnect()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Stopping event listener");
 | 
				
			||||||
 | 
					    connected = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::process()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    vita_event_t event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qDebug() << "From listener: "<< QThread::currentThreadId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(connected) {
 | 
				
			||||||
 | 
					        if(VitaMTP_Read_Event(device, &event) < 0) {
 | 
				
			||||||
 | 
					            qWarning("Error reading event from Vita.");
 | 
				
			||||||
 | 
					            connected = false;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        qDebug("Event 0x%04X recieved", event.Code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch(event.Code) {
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendNumOfObject:
 | 
				
			||||||
 | 
					            vitaEventSendNumOfObject(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendObjectMetadata:
 | 
				
			||||||
 | 
					            vitaEventSendObjectMetadata(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendObject:
 | 
				
			||||||
 | 
					            vitaEventSendObject(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestCancelTask: // unimplemented
 | 
				
			||||||
 | 
					            vitaEventCancelTask(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendHttpObjectFromURL:
 | 
				
			||||||
 | 
					            vitaEventSendHttpObjectFromURL(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_Unknown1: // unimplemented
 | 
				
			||||||
 | 
					            vitaEventUnimplementated(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendObjectStatus:
 | 
				
			||||||
 | 
					            vitaEventSendObjectStatus(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendObjectThumb:
 | 
				
			||||||
 | 
					            vitaEventSendObjectThumb(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestDeleteObject:
 | 
				
			||||||
 | 
					            vitaEventDeleteObject(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestGetSettingInfo:
 | 
				
			||||||
 | 
					            vitaEventGetSettingInfo(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendHttpObjectPropFromURL:
 | 
				
			||||||
 | 
					            vitaEventSendHttpObjectPropFromURL(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendPartOfObject:
 | 
				
			||||||
 | 
					            vitaEventSendPartOfObject(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestOperateObject:
 | 
				
			||||||
 | 
					            vitaEventOperateObject(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestGetPartOfObject:
 | 
				
			||||||
 | 
					            vitaEventGetPartOfObject(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendStorageSize:
 | 
				
			||||||
 | 
					            vitaEventSendStorageSize(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestCheckExistance:
 | 
				
			||||||
 | 
					            vitaEventCheckExistance(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestGetTreatObject:
 | 
				
			||||||
 | 
					            vitaEventGetTreatObject(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendCopyConfirmationInfo:
 | 
				
			||||||
 | 
					            vitaEventSendCopyConfirmationInfo(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendObjectMetadataItems:
 | 
				
			||||||
 | 
					            vitaEventSendObjectMetadataItems(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestSendNPAccountInfo:
 | 
				
			||||||
 | 
					            vitaEventSendNPAccountInfo(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case PTP_EC_VITA_RequestTerminate:
 | 
				
			||||||
 | 
					            vitaEventRequestTerminate(&event, event.Param1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            vitaEventUnimplementated(&event, event.Param1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    emit finished();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					quint16 ListenerWorker::processAllObjects(CMAObject *parent, quint32 handle)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
					        unsigned char *fileData;
 | 
				
			||||||
 | 
					        uint32_t *handles;
 | 
				
			||||||
 | 
					    } data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    metadata_t remote_meta;
 | 
				
			||||||
 | 
					    unsigned int length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_GetObject(device, handle, &remote_meta, (void **)&data, &length) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Cannot get object for handle %d", handle);
 | 
				
			||||||
 | 
					        return PTP_RC_VITA_Invalid_Data;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CMAObject *object =  db.pathToObject(remote_meta.name, parent->metadata.ohfi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(object) {
 | 
				
			||||||
 | 
					        qDebug("Deleting %s", object->path.toStdString().c_str());
 | 
				
			||||||
 | 
					        removeRecursively(object->path);
 | 
				
			||||||
 | 
					        db.remove(object);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QDir dir(parent->path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(remote_meta.dataType & Folder) {
 | 
				
			||||||
 | 
					        if(!dir.mkpath(remote_meta.name)) {
 | 
				
			||||||
 | 
					            qWarning("Cannot create directory: %s", remote_meta.name);
 | 
				
			||||||
 | 
					            free(data.fileData);
 | 
				
			||||||
 | 
					            free(remote_meta.name);
 | 
				
			||||||
 | 
					            return PTP_RC_VITA_Failed_Operate_Object;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        QFile file(dir.absoluteFilePath(remote_meta.name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!file.open(QIODevice::WriteOnly)) {
 | 
				
			||||||
 | 
					            qWarning("Cannot write to %s", remote_meta.name);
 | 
				
			||||||
 | 
					            free(data.fileData);
 | 
				
			||||||
 | 
					            free(remote_meta.name);
 | 
				
			||||||
 | 
					            return PTP_RC_VITA_Invalid_Permission;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            file.write((const char *)data.fileData, remote_meta.size);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QFileInfo info(dir, remote_meta.name);
 | 
				
			||||||
 | 
					    object = new CMAObject(parent);
 | 
				
			||||||
 | 
					    object->initObject(info);
 | 
				
			||||||
 | 
					    object->metadata.handle = remote_meta.handle;
 | 
				
			||||||
 | 
					    db.append(parent->metadata.ohfi, object);
 | 
				
			||||||
 | 
					    free(remote_meta.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qDebug("Added object %s with OHFI %i to database", object->metadata.path, object->metadata.ohfi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(remote_meta.dataType & Folder) {
 | 
				
			||||||
 | 
					        for(unsigned int i = 0; i < length; i++) {
 | 
				
			||||||
 | 
					            quint16 ret = processAllObjects(object, data.handles[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(ret != PTP_RC_OK) {
 | 
				
			||||||
 | 
					                qDebug("Deleteting object with OHFI %d", object->metadata.ohfi);
 | 
				
			||||||
 | 
					                db.remove(object);
 | 
				
			||||||
 | 
					                free(data.fileData);
 | 
				
			||||||
 | 
					                return ret;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(data.fileData);
 | 
				
			||||||
 | 
					    return PTP_RC_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventGetTreatObject(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    treat_object_t treatObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_GetTreatObject(device, eventId, &treatObject) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Cannot get information on object to get");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CMAObject *parent = db.ohfiToObject(treatObject.ohfiParent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(parent == NULL) {
 | 
				
			||||||
 | 
					        qWarning("Cannot find parent OHFI %d", treatObject.ohfiParent);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VitaMTP_ReportResult(device, eventId, processAllObjects(parent, treatObject.handle));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    copy_confirmation_info_t *info;
 | 
				
			||||||
 | 
					    if(VitaMTP_SendCopyConfirmationInfoInit(device, eventId, &info) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Error recieving initial information.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    quint64 size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(quint32 i = 0; i < info->count; i++) {
 | 
				
			||||||
 | 
					        CMAObject *object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if((object = db.ohfiToObject(info->ohfi[i])) == NULL) {
 | 
				
			||||||
 | 
					            qWarning("Cannot find OHFI %d", info->ohfi[i]);
 | 
				
			||||||
 | 
					            free(info);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        size += object->metadata.size;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_SendCopyConfirmationInfo(device, eventId, info, size) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Error sending copy confirmation");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendObjectMetadataItems(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    quint32 ohfi;
 | 
				
			||||||
 | 
					    if(VitaMTP_SendObjectMetadataItems(device, eventId, &ohfi) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Cannot get OHFI for retreving metadata");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CMAObject *object = db.ohfiToObject(ohfi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(object == NULL) {
 | 
				
			||||||
 | 
					        qWarning("Cannot find OHFI %d in database", ohfi);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    metadata_t *metadata = &object->metadata;
 | 
				
			||||||
 | 
					    metadata->next_metadata = NULL;
 | 
				
			||||||
 | 
					    qDebug("Sending metadata for OHFI %d (%s)", ohfi, metadata->path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_SendObjectMetadata(device, eventId, metadata) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Error sending metadata");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendNPAccountInfo(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					    // AFAIK, Sony hasn't even implemented this in their CMA
 | 
				
			||||||
 | 
					    qWarning("Event 0x%x unimplemented!", event->Code);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventRequestTerminate(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					    qWarning("Event 0x%x unimplemented!", event->Code);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventUnimplementated(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qWarning("Unknown event not handled, code: 0x%x, id: %d", event->Code, eventId);
 | 
				
			||||||
 | 
					    qWarning("Param1: 0x%08X, Param2: 0x%08X, Param3: 0x%08X", event->Param1, event->Param2, event->Param3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendNumOfObject(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint ohfi = event->Param2;
 | 
				
			||||||
 | 
					    int items = db.filterObjects(ohfi, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_SendNumOfObject(device, eventId, items) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Error occured receiving object count for OHFI parent %d", ohfi);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        qDebug("Returned count of %d objects for OHFI parent %d", items, ohfi);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendObjectMetadata(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    browse_info_t browse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_GetBrowseInfo(device, eventId, &browse) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("GetBrowseInfo failed");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    metadata_t *meta;
 | 
				
			||||||
 | 
					    int count = db.filterObjects(browse.ohfiParent, &meta);  // if meta is null, will return empty XML
 | 
				
			||||||
 | 
					    qDebug("Sending %i metadata filtered objects for OHFI %id", count, browse.ohfiParent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_SendObjectMetadata(device, eventId, meta) != PTP_RC_OK) {  // send all objects with OHFI parent
 | 
				
			||||||
 | 
					        qWarning("Sending metadata for OHFI parent %d failed", browse.ohfiParent);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendObject(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ohfi = event->Param2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Database::find_data iters;
 | 
				
			||||||
 | 
					    if(!db.find(ohfi, iters)) {
 | 
				
			||||||
 | 
					        qWarning("Failed to find OHFI %d", ohfi);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned long len = 0;
 | 
				
			||||||
 | 
					    CMAObject *object = *iters.it;
 | 
				
			||||||
 | 
					    CMAObject *start = object;
 | 
				
			||||||
 | 
					    uint parentHandle = event->Param3;
 | 
				
			||||||
 | 
					    uint handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        uchar *data = NULL;
 | 
				
			||||||
 | 
					        len = object->metadata.size;
 | 
				
			||||||
 | 
					        QFile file(object->path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // read the file to send if it's not a directory
 | 
				
			||||||
 | 
					        // if it is a directory, data and len are not used by VitaMTP
 | 
				
			||||||
 | 
					        if(object->metadata.dataType & File) {
 | 
				
			||||||
 | 
					            if(!file.open(QIODevice::ReadOnly) || (data = file.map(0, file.size())) == NULL) {
 | 
				
			||||||
 | 
					                qWarning("Failed to read %s", object->path.toStdString().c_str());
 | 
				
			||||||
 | 
					                VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Not_Exist_Object);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // get the PTP object ID for the parent to put the object
 | 
				
			||||||
 | 
					        // we know the parent has to be before the current node
 | 
				
			||||||
 | 
					        // the first time this is called, parentHandle is left untouched
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(start != object) {
 | 
				
			||||||
 | 
					            parentHandle = object->parent->metadata.handle;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // send the data over
 | 
				
			||||||
 | 
					        qDebug("Sending %s of %lu bytes to device", object->metadata.name, len);
 | 
				
			||||||
 | 
					        qDebug("OHFI %d with handle 0x%08X", ohfi, parentHandle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(VitaMTP_SendObject(device, &parentHandle, &handle, &object->metadata, data) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					            qWarning("Sending of %s failed.", object->metadata.name);
 | 
				
			||||||
 | 
					            file.unmap(data);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        object->metadata.handle = handle;
 | 
				
			||||||
 | 
					        file.unmap(data);
 | 
				
			||||||
 | 
					        object = *iters.it++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } while(iters.it != iters.end && object->metadata.ohfiParent >= OHFI_OFFSET); // get everything under this "folder"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, handle);
 | 
				
			||||||
 | 
					    VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data);  // TODO: Send thumbnail
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventCancelTask(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int eventIdToCancel = event->Param2;
 | 
				
			||||||
 | 
					    VitaMTP_CancelTask(device, eventIdToCancel);
 | 
				
			||||||
 | 
					    qWarning("Event CancelTask (0x%x) unimplemented!", event->Code);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendHttpObjectFromURL(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *url;
 | 
				
			||||||
 | 
					    if(VitaMTP_GetUrl(device, eventId, &url) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Failed to recieve URL");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QString urlpath = QSettings().value("urlPath").toString();
 | 
				
			||||||
 | 
					    QString basename = QFileInfo(QUrl(url).path()).fileName();
 | 
				
			||||||
 | 
					    QFile file(QDir(urlpath).absoluteFilePath(basename));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QByteArray data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!file.open(QIODevice::ReadOnly)) {
 | 
				
			||||||
 | 
					        if(basename == "psp2-updatelist.xml") {
 | 
				
			||||||
 | 
					            qDebug("Found request for update list. Sending cached data");
 | 
				
			||||||
 | 
					            QFile res(":/main/psp2-updatelist.xml");
 | 
				
			||||||
 | 
					            res.open(QIODevice::ReadOnly);
 | 
				
			||||||
 | 
					            data = res.readAll();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            qWarning("Failed to download %s", url);
 | 
				
			||||||
 | 
					            VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Download);
 | 
				
			||||||
 | 
					            free(url);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        data = file.readAll();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qDebug("Sending %i bytes of data for HTTP request %s", data.size(), url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_SendHttpObjectFromURL(device, eventId, data.data(), data.size()) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Failed to send HTTP object");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(url);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendObjectStatus(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    object_status_t objectstatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_SendObjectStatus(device, eventId, &objectstatus) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Failed to get information for object status.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CMAObject *object = db.pathToObject(objectstatus.title, objectstatus.ohfiRoot);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(object == NULL) { // not in database, don't return metadata
 | 
				
			||||||
 | 
					        qDebug("Object %s not in database (OHFI: %i). Sending OK response for non-existence", objectstatus.title, objectstatus.ohfiRoot);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        metadata_t *metadata = &object->metadata;
 | 
				
			||||||
 | 
					        metadata->next_metadata = NULL;
 | 
				
			||||||
 | 
					        qDebug("Sending metadata for OHFI %d", object->metadata.ohfi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(VitaMTP_SendObjectMetadata(device, eventId, metadata) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					            qWarning("Error sending metadata for %d", object->metadata.ohfi);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(objectstatus.title);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendObjectThumb(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ohfi = event->Param2;
 | 
				
			||||||
 | 
					    CMAObject *object = db.ohfiToObject(ohfi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(object == NULL) {
 | 
				
			||||||
 | 
					        qWarning("Cannot find OHFI %d in database.", ohfi);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QByteArray data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(MASK_SET(object->metadata.dataType, SaveData)) {
 | 
				
			||||||
 | 
					        QString thumbpath = QDir(object->path).absoluteFilePath("ICON0.PNG");
 | 
				
			||||||
 | 
					        qDebug("Sending savedata thumbnail from %s", thumbpath.toStdString().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        QFile file(thumbpath);
 | 
				
			||||||
 | 
					        if(!file.open(QIODevice::ReadOnly)) {
 | 
				
			||||||
 | 
					            qWarning("Cannot find thumbnail %s", thumbpath.toStdString().c_str());
 | 
				
			||||||
 | 
					            VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        data = file.readAll();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        QImage img;
 | 
				
			||||||
 | 
					        if(!MASK_SET(object->metadata.dataType, Photo) || !img.load(object->path)) {
 | 
				
			||||||
 | 
					            qWarning("Thumbnail sending for the file %s is not supported", object->metadata.path);
 | 
				
			||||||
 | 
					            VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        qDebug("Creating thumbnail of %s", object->metadata.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        QBuffer buffer(&data);
 | 
				
			||||||
 | 
					        buffer.open(QIODevice::WriteOnly);
 | 
				
			||||||
 | 
					        QImage result = img.scaled(256, 256, Qt::KeepAspectRatio, Qt::FastTransformation);
 | 
				
			||||||
 | 
					        result.save(&buffer, "JPEG");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // workaround for the vitamtp locale bug
 | 
				
			||||||
 | 
					    char *locale = strdup(setlocale(LC_ALL, NULL));
 | 
				
			||||||
 | 
					    setlocale(LC_ALL, "C");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_SendObjectThumb(device, eventId, (metadata_t *)&g_thumbmeta, (uchar *)data.data(), data.size()) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Error sending thumbnail");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // restore locale
 | 
				
			||||||
 | 
					    setlocale(LC_ALL, locale);
 | 
				
			||||||
 | 
					    free(locale);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventDeleteObject(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ohfi = event->Param2;
 | 
				
			||||||
 | 
					    CMAObject *object = db.ohfiToObject(ohfi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(object == NULL) {
 | 
				
			||||||
 | 
					        qWarning("OHFI %d not found", ohfi);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qDebug("Deleting %s, OHFI: %i", object->metadata.path, object->metadata.ohfi);
 | 
				
			||||||
 | 
					    removeRecursively(object->path);    
 | 
				
			||||||
 | 
					    db.remove(object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventGetSettingInfo(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    settings_info_t *settingsinfo;
 | 
				
			||||||
 | 
					    if(VitaMTP_GetSettingInfo(device, eventId, &settingsinfo) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Failed to get setting info from Vita.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qDebug("Current account id: %s", settingsinfo->current_account.accountId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    db.setUUID(settingsinfo->current_account.accountId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // set the database to be updated ASAP    
 | 
				
			||||||
 | 
					    emit refreshDatabase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // free all the information
 | 
				
			||||||
 | 
					    VitaMTP_Data_Free_Settings(settingsinfo);
 | 
				
			||||||
 | 
					    VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendHttpObjectPropFromURL(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *url;
 | 
				
			||||||
 | 
					    if(VitaMTP_GetUrl(device, eventId, &url) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Failed to get URL");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QString urlpath = QSettings().value("urlPath").toString();
 | 
				
			||||||
 | 
					    QString basename = QFileInfo(url).fileName();
 | 
				
			||||||
 | 
					    QFileInfo file(QDir(urlpath).absoluteFilePath(basename));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!file.exists()) {
 | 
				
			||||||
 | 
					        qWarning("The file %s is not accesible", url);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Download);
 | 
				
			||||||
 | 
					        free(url);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QString timestamp = file.lastModified().toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http_object_prop_t httpobjectprop;
 | 
				
			||||||
 | 
					    httpobjectprop.timestamp = timestamp.toUtf8().data();
 | 
				
			||||||
 | 
					    httpobjectprop.timestamp_len = timestamp.toUtf8().size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_SendHttpObjectPropFromURL(device, eventId, &httpobjectprop) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Failed to send object properties");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(url);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendPartOfObject(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    send_part_init_t part_init;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_SendPartOfObjectInit(device, eventId, &part_init) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Cannot get information on object to send");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CMAObject *object = db.ohfiToObject(part_init.ohfi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(object == NULL) {
 | 
				
			||||||
 | 
					        qWarning("Cannot find object for OHFI %d", part_init.ohfi);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Context);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QFile file(object->path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!file.open(QIODevice::ReadOnly)) {
 | 
				
			||||||
 | 
					        qWarning("Cannot read %s", object->path.toStdString().c_str());
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Not_Exist_Object);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        file.seek(part_init.offset);
 | 
				
			||||||
 | 
					        QByteArray data = file.read(part_init.size);
 | 
				
			||||||
 | 
					        qDebug("Sending %s at file offset %zu for %zu bytes", object->metadata.path, part_init.offset, part_init.size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(VitaMTP_SendPartOfObject(device, eventId, (unsigned char *)data.data(), data.size()) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					            qWarning("Failed to send part of object OHFI %d", part_init.ohfi);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventOperateObject(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operate_object_t operateobject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_OperateObject(device, eventId, &operateobject) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Cannot get information on object to operate");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CMAObject *root = db.ohfiToObject(operateobject.ohfi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // end for renaming only
 | 
				
			||||||
 | 
					    if(root == NULL) {
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Not_Exist_Object);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch(operateobject.cmd) {
 | 
				
			||||||
 | 
					    case VITA_OPERATE_CREATE_FOLDER: {
 | 
				
			||||||
 | 
					        qDebug("Operate command %d: Create folder %s", operateobject.cmd, operateobject.title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        QDir dir(root->path);
 | 
				
			||||||
 | 
					        if(!dir.mkdir(operateobject.title)) {
 | 
				
			||||||
 | 
					            qWarning("Unable to create temporary folder: %s", operateobject.title);
 | 
				
			||||||
 | 
					            VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            CMAObject *newobj = new CMAObject(root);
 | 
				
			||||||
 | 
					            newobj->initObject(QFileInfo(dir, operateobject.title));
 | 
				
			||||||
 | 
					            db.append(operateobject.ohfi, newobj);
 | 
				
			||||||
 | 
					            qDebug("Created folder %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path);
 | 
				
			||||||
 | 
					            VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case VITA_OPERATE_CREATE_FILE: {
 | 
				
			||||||
 | 
					        qDebug("Operate command %d: Create file %s", operateobject.cmd, operateobject.title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        QFile file(root->path + QDir::separator() + operateobject.title);
 | 
				
			||||||
 | 
					        if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
 | 
				
			||||||
 | 
					            qWarning("Unable to create temporary file: %s", operateobject.title);
 | 
				
			||||||
 | 
					            VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            CMAObject *newobj = new CMAObject(root);
 | 
				
			||||||
 | 
					            newobj->initObject(file);
 | 
				
			||||||
 | 
					            db.append(root->metadata.ohfi, newobj);
 | 
				
			||||||
 | 
					            qDebug("Created file %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path);
 | 
				
			||||||
 | 
					            VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case VITA_OPERATE_RENAME: {
 | 
				
			||||||
 | 
					        qDebug("Operate command %d: Rename %s to %s", operateobject.cmd, root->metadata.name, operateobject.title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        QString oldpath = root->path;
 | 
				
			||||||
 | 
					        QString oldname = root->metadata.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //rename the current object
 | 
				
			||||||
 | 
					        root->rename(operateobject.title);
 | 
				
			||||||
 | 
					        Database::find_data iters;
 | 
				
			||||||
 | 
					        db.find(root->metadata.ohfi, iters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // rename the rest of the list only if has the renamed parent in some part of the chain
 | 
				
			||||||
 | 
					        while(iters.it != iters.end) {
 | 
				
			||||||
 | 
					            CMAObject *obj = *iters.it++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(obj->hasParent(root)) {
 | 
				
			||||||
 | 
					                obj->refreshPath();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // rename in filesystem
 | 
				
			||||||
 | 
					        if(!QFile(oldpath).rename(root->path)) {
 | 
				
			||||||
 | 
					            qWarning("Unable to rename %s to %s", oldname.toStdString().c_str(), operateobject.title);
 | 
				
			||||||
 | 
					            VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        qDebug("Renamed OHFI %d from %s to %s", root->metadata.ohfi, oldname.toStdString().c_str(), root->metadata.name);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, root->metadata.ohfi);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        qWarning("Operate command %d: Not implemented", operateobject.cmd);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(operateobject.title);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventGetPartOfObject(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned char *data;
 | 
				
			||||||
 | 
					    send_part_init_t part_init;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_GetPartOfObject(device, eventId, &part_init, &data) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Cannot get object from device");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					    CMAObject *object = db.ohfiToObject(part_init.ohfi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(object == NULL) {
 | 
				
			||||||
 | 
					        qWarning("Cannot find OHFI %d", part_init.ohfi);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
 | 
				
			||||||
 | 
					        free(data);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qDebug("Receiving %s at offset %zu for %zu bytes", object->metadata.path, part_init.offset, part_init.size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QFile file(object->path);
 | 
				
			||||||
 | 
					    if(!file.open(QIODevice::ReadWrite)) {
 | 
				
			||||||
 | 
					        qWarning("Cannot write to file %s", object->path.toStdString().c_str());
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Permission);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        file.seek(part_init.offset);
 | 
				
			||||||
 | 
					        file.write((const char *)data, part_init.size);
 | 
				
			||||||
 | 
					        object->metadata.size += part_init.size;
 | 
				
			||||||
 | 
					        object->updateParentSize(part_init.size);
 | 
				
			||||||
 | 
					        qDebug("Written %zu bytes to %s at offset %zu.", part_init.size, object->path.toStdString().c_str(), part_init.offset);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventSendStorageSize(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ohfi = event->Param2;
 | 
				
			||||||
 | 
					    CMAObject *object = db.ohfiToObject(ohfi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(object == NULL) {
 | 
				
			||||||
 | 
					        qWarning("Error: Cannot find OHFI %d", ohfi);
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        QFile file(object->path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!file.exists()) {
 | 
				
			||||||
 | 
					            // create the directory if doesn't exist so the query don't fail
 | 
				
			||||||
 | 
					            qDebug("Creating %s", object->path.toStdString().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(!QDir(QDir::root()).mkpath(object->path)) {
 | 
				
			||||||
 | 
					                qWarning("Create directory failed");
 | 
				
			||||||
 | 
					                VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Permission);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    quint64 total;
 | 
				
			||||||
 | 
					    quint64 free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!getDiskSpace(object->path, &free, &total)) {
 | 
				
			||||||
 | 
					        qWarning("Cannot get disk space");
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Permission);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qDebug("Storage stats for drive containing OHFI %d, free: %llu, total: %llu", ohfi, free, total);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_SendStorageSize(device, eventId, total, free) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Send storage size failed");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ListenerWorker::vitaEventCheckExistance(vita_event_t *event, int eventId)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int handle = event->Param2;
 | 
				
			||||||
 | 
					    existance_object_t existance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(VitaMTP_CheckExistance(device, handle, &existance) != PTP_RC_OK) {
 | 
				
			||||||
 | 
					        qWarning("Cannot read information on object to be sent");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutexLocker locker(&db.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CMAObject *object = db.pathToObject(existance.name, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(object == NULL) {
 | 
				
			||||||
 | 
					        VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Different_Object);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_VITA_Same_Object, object->metadata.ohfi);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VitaMTP_ReportResult(device, eventId, PTP_RC_OK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										82
									
								
								listenerworker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								listenerworker.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef LISTENERWORKER_H
 | 
				
			||||||
 | 
					#define LISTENERWORKER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "database.h"
 | 
				
			||||||
 | 
					#include "baseworker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QObject>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include <vitamtp.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ListenerWorker : public BaseWorker
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit ListenerWorker(QObject *parent = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void setDevice(vita_device_t *device);
 | 
				
			||||||
 | 
					    bool isConnected();
 | 
				
			||||||
 | 
					    void disconnect();
 | 
				
			||||||
 | 
					    int rebuildDatabase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Database db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    uint16_t processAllObjects(CMAObject *parent, uint32_t handle);
 | 
				
			||||||
 | 
					    void vitaEventSendObject(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventSendObjectMetadata(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventSendNumOfObject(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventCancelTask(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventSendHttpObjectFromURL(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventUnimplementated(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventSendObjectStatus(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventSendObjectThumb(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventDeleteObject(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventGetSettingInfo(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventSendHttpObjectPropFromURL(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventSendPartOfObject(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventOperateObject(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventGetPartOfObject(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventSendStorageSize(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventCheckExistance(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventGetTreatObject(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventSendCopyConfirmationInfo(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventSendObjectMetadataItems(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventSendNPAccountInfo(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					    void vitaEventRequestTerminate(vita_event_t *event, int eventId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vita_device_t *device;
 | 
				
			||||||
 | 
					    volatile bool connected;
 | 
				
			||||||
 | 
					    static const metadata_t g_thumbmeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
					    void refreshDatabase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
					    void process();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // LISTENERWORKER_H
 | 
				
			||||||
							
								
								
									
										69
									
								
								main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								main.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QDebug>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "singleapplication.h"
 | 
				
			||||||
 | 
					#include "mainwidget.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
 | 
				
			||||||
 | 
					void noMessageOutput(QtMsgType type, const QMessageLogContext &, const QString & str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const char * msg = str.toStdString().c_str();
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					void noMessageOutput(QtMsgType type, const char *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					     Q_UNUSED(type);
 | 
				
			||||||
 | 
					     Q_UNUSED(msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(SingleApplication::sendMessage(QObject::tr("A instance of QCMA is already running"))) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SingleApplication app(argc, argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!app.arguments().contains("--with-debug")) {
 | 
				
			||||||
 | 
					#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
 | 
				
			||||||
 | 
					        qInstallMessageHandler(noMessageOutput);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        qInstallMsgHandler(noMessageOutput);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qDebug()<<"From main thread: "<<QThread::currentThreadId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // set the organization/application for QSettings to work properly
 | 
				
			||||||
 | 
					    app.setOrganizationName("qcma");
 | 
				
			||||||
 | 
					    app.setApplicationName("qcma");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //TODO: check if this is actually needed since we don't have a main window by default
 | 
				
			||||||
 | 
					    QApplication::setQuitOnLastWindowClosed(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MainWidget widget;
 | 
				
			||||||
 | 
					    widget.prepareApplication();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // receive the message from another process
 | 
				
			||||||
 | 
					    QObject::connect(&app, SIGNAL(messageAvailable(QString)), &widget, SLOT(receiveMessage(QString)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return app.exec();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										155
									
								
								mainwidget.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								mainwidget.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "mainwidget.h"
 | 
				
			||||||
 | 
					#include "qcma.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QAction>
 | 
				
			||||||
 | 
					#include <QApplication>
 | 
				
			||||||
 | 
					#include <QDir>
 | 
				
			||||||
 | 
					#include <QMenu>
 | 
				
			||||||
 | 
					#include <QSettings>
 | 
				
			||||||
 | 
					#include <QTimer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const QStringList MainWidget::path_list = QStringList() << "photoPath" << "musicPath" << "videoPath" << "appsPath" << "urlPath";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MainWidget::MainWidget(QWidget *parent) :
 | 
				
			||||||
 | 
					    QWidget(parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWidget::checkSettings()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QSettings settings;
 | 
				
			||||||
 | 
					    // make sure that all the paths are set, else show the config dialog
 | 
				
			||||||
 | 
					    foreach(const QString &path, path_list) {
 | 
				
			||||||
 | 
					        if(!settings.contains(path)) {
 | 
				
			||||||
 | 
					            first_run = true;
 | 
				
			||||||
 | 
					            dialog.show();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    CmaWorker.start();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWidget::dialogResult(int result)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(result == QDialog::Accepted) {
 | 
				
			||||||
 | 
					        if(first_run) {
 | 
				
			||||||
 | 
					            first_run = false;
 | 
				
			||||||
 | 
					            CmaWorker.start();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if(first_run) {
 | 
				
			||||||
 | 
					        qApp->quit();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWidget::deviceDisconnect()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    setTrayTooltip(tr("Disconnected"));
 | 
				
			||||||
 | 
					    receiveMessage(tr("The device has been disconnected"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWidget::connectSignals()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    connect(&dialog, SIGNAL(finished(int)), this, SLOT(dialogResult(int)));
 | 
				
			||||||
 | 
					    connect(&CmaWorker, SIGNAL(createdPin(int)), this, SLOT(showPin(int)));
 | 
				
			||||||
 | 
					    connect(&CmaWorker, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString)));
 | 
				
			||||||
 | 
					    connect(&CmaWorker, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString)));
 | 
				
			||||||
 | 
					    connect(&CmaWorker, SIGNAL(statusUpdated(QString)), this, SLOT(receiveMessage(QString)));
 | 
				
			||||||
 | 
					    connect(&CmaWorker, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect()));
 | 
				
			||||||
 | 
					    connect(&CmaWorker, SIGNAL(finished()), qApp, SLOT(quit()));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWidget::showPin(int pin)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    receiveMessage(QString(tr("Received PIN: %1").arg(QString::number(pin), 8, QChar('0'))));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWidget::prepareApplication()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    connectSignals();
 | 
				
			||||||
 | 
					    createTrayIcon();
 | 
				
			||||||
 | 
					    trayIcon->show();
 | 
				
			||||||
 | 
					    checkSettings();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWidget::setTrayTooltip(QString message)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    trayIcon->setToolTip(message);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWidget::toggleWireless()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QSettings settings;
 | 
				
			||||||
 | 
					    if(wireless->isChecked()) {
 | 
				
			||||||
 | 
					        wireless->setText(tr("&Wireless enabled"));
 | 
				
			||||||
 | 
					        settings.setValue("wireless", true);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        wireless->setText(tr("&Wireless disabled"));
 | 
				
			||||||
 | 
					        settings.setValue("wireless", false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    CmaWorker.reload();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWidget::createTrayIcon()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QSettings settings;
 | 
				
			||||||
 | 
					    wireless = new QAction(this);
 | 
				
			||||||
 | 
					    wireless->setCheckable(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(settings.value("wireless", false).toBool()) {
 | 
				
			||||||
 | 
					        wireless->setText(tr("&Wireless enabled"));
 | 
				
			||||||
 | 
					        wireless->setChecked(true);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        wireless->setText(tr("&Wireless disabled"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    options = new QAction(tr("&Settings"), this);
 | 
				
			||||||
 | 
					    reload = new QAction(tr("&Refresh database"), this);
 | 
				
			||||||
 | 
					    quit = new QAction(tr("&Quit"), this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    connect(options, SIGNAL(triggered()), &dialog, SLOT(open()));
 | 
				
			||||||
 | 
					    connect(reload, SIGNAL(triggered()), &CmaWorker, SLOT(allowRefresh()), Qt::DirectConnection);
 | 
				
			||||||
 | 
					    connect(quit, SIGNAL(triggered()), &CmaWorker, SLOT(stop()), Qt::DirectConnection);
 | 
				
			||||||
 | 
					    connect(wireless, SIGNAL(triggered()), this, SLOT(toggleWireless()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMenu *trayIconMenu = new QMenu(this);
 | 
				
			||||||
 | 
					    trayIconMenu->addAction(options);
 | 
				
			||||||
 | 
					    trayIconMenu->addAction(reload);
 | 
				
			||||||
 | 
					    trayIconMenu->addAction(wireless);
 | 
				
			||||||
 | 
					    trayIconMenu->addSeparator();
 | 
				
			||||||
 | 
					    trayIconMenu->addAction(quit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trayIcon = new QSystemTrayIcon(this);
 | 
				
			||||||
 | 
					    trayIcon->setContextMenu(trayIconMenu);
 | 
				
			||||||
 | 
					    trayIcon->setIcon(QIcon::fromTheme("image-loading"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWidget::receiveMessage(QString message)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(trayIcon->isVisible()) {
 | 
				
			||||||
 | 
					        trayIcon->showMessage(tr("Information"), message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MainWidget::~MainWidget()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    trayIcon->hide();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										70
									
								
								mainwidget.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								mainwidget.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MAINWIDGET_H
 | 
				
			||||||
 | 
					#define MAINWIDGET_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "configwidget.h"
 | 
				
			||||||
 | 
					#include "qcma.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QAction>
 | 
				
			||||||
 | 
					#include <QWidget>
 | 
				
			||||||
 | 
					#include <QSystemTrayIcon>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QMenu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ui
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					class MainWidget;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MainWidget : public QWidget
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit MainWidget(QWidget *parent = 0);
 | 
				
			||||||
 | 
					    ~MainWidget();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void prepareApplication();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    void createTrayIcon();
 | 
				
			||||||
 | 
					    void checkSettings();
 | 
				
			||||||
 | 
					    void connectSignals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool first_run;
 | 
				
			||||||
 | 
					    QCMA CmaWorker;
 | 
				
			||||||
 | 
					    ConfigWidget dialog;
 | 
				
			||||||
 | 
					    QSystemTrayIcon *trayIcon;
 | 
				
			||||||
 | 
					    QAction *quit;
 | 
				
			||||||
 | 
					    QAction *reload;
 | 
				
			||||||
 | 
					    QAction *options;
 | 
				
			||||||
 | 
					    QAction *wireless;
 | 
				
			||||||
 | 
					    const static QStringList path_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
					    void deviceDisconnect();
 | 
				
			||||||
 | 
					    void dialogResult(int result);
 | 
				
			||||||
 | 
					    void receiveMessage(QString message);
 | 
				
			||||||
 | 
					    void setTrayTooltip(QString message);
 | 
				
			||||||
 | 
					    void toggleWireless();
 | 
				
			||||||
 | 
					    void showPin(int pin);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // MAINWIDGET_H
 | 
				
			||||||
							
								
								
									
										39
									
								
								psp2-updatelist.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								psp2-updatelist.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<update_data_list>
 | 
				
			||||||
 | 
					<region id="au">
 | 
				
			||||||
 | 
					    <np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
 | 
				
			||||||
 | 
					    <version system_version="00.000.000" label="0.00"></version>
 | 
				
			||||||
 | 
					</region>
 | 
				
			||||||
 | 
					<region id="eu">
 | 
				
			||||||
 | 
					    <np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
 | 
				
			||||||
 | 
					    <version system_version="00.000.000" label="0.00"></version>
 | 
				
			||||||
 | 
					</region>
 | 
				
			||||||
 | 
					<region id="jp">
 | 
				
			||||||
 | 
					    <np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
 | 
				
			||||||
 | 
					    <version system_version="00.000.000" label="0.00"></version>
 | 
				
			||||||
 | 
					</region>
 | 
				
			||||||
 | 
					<region id="kr">
 | 
				
			||||||
 | 
					    <np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
 | 
				
			||||||
 | 
					    <version system_version="00.000.000" label="0.00"></version>
 | 
				
			||||||
 | 
					</region>
 | 
				
			||||||
 | 
					<region id="mx">
 | 
				
			||||||
 | 
					    <np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
 | 
				
			||||||
 | 
					    <version system_version="00.000.000" label="0.00"></version>
 | 
				
			||||||
 | 
					</region>
 | 
				
			||||||
 | 
					<region id="ru">
 | 
				
			||||||
 | 
					    <np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
 | 
				
			||||||
 | 
					    <version system_version="00.000.000" label="0.00"></version>
 | 
				
			||||||
 | 
					</region>
 | 
				
			||||||
 | 
					<region id="tw">
 | 
				
			||||||
 | 
					    <np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
 | 
				
			||||||
 | 
					    <version system_version="00.000.000" label="0.00"></version>
 | 
				
			||||||
 | 
					</region>
 | 
				
			||||||
 | 
					<region id="uk">
 | 
				
			||||||
 | 
					    <np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
 | 
				
			||||||
 | 
					    <version system_version="00.000.000" label="0.00"></version>
 | 
				
			||||||
 | 
					</region>
 | 
				
			||||||
 | 
					<region id="us">
 | 
				
			||||||
 | 
					    <np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
 | 
				
			||||||
 | 
					    <version system_version="00.000.000" label="0.00"></version>
 | 
				
			||||||
 | 
					</region>
 | 
				
			||||||
 | 
					</update_data_list>
 | 
				
			||||||
							
								
								
									
										174
									
								
								qcma.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								qcma.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,174 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qcma.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "capability.h"
 | 
				
			||||||
 | 
					#include "listenerworker.h"
 | 
				
			||||||
 | 
					#include "wirelessworker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QApplication>
 | 
				
			||||||
 | 
					#include <QDebug>
 | 
				
			||||||
 | 
					#include <QDir>
 | 
				
			||||||
 | 
					#include <QSettings>
 | 
				
			||||||
 | 
					#include <QWaitCondition>
 | 
				
			||||||
 | 
					#include <QElapsedTimer>
 | 
				
			||||||
 | 
					#include <QHostInfo>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RETRY_TIMEOUT 2000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QCMA::QCMA(QObject *parent) :
 | 
				
			||||||
 | 
					    BaseWorker(parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    exit_thread = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vita_device_t *QCMA::connectWireless()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int num_tries = 0;
 | 
				
			||||||
 | 
					    vita_device_t *vita = NULL;
 | 
				
			||||||
 | 
					    WirelessWorker *broadcast = new WirelessWorker();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // bubble up the pin received signal
 | 
				
			||||||
 | 
					    connect(broadcast, SIGNAL(createdPin(int)), this, SIGNAL(createdPin(int)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qDebug("Starting broadcast");
 | 
				
			||||||
 | 
					    broadcast->start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QMutex mutex;
 | 
				
			||||||
 | 
					    QString hostname = QHostInfo::localHostName();
 | 
				
			||||||
 | 
					    WirelessWorker::info.name = hostname.toUtf8().data();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(!break_loop && (vita = VitaMTP_Get_First_Wireless_Vita(
 | 
				
			||||||
 | 
					                                      &WirelessWorker::info, 0, 10,
 | 
				
			||||||
 | 
					                                      WirelessWorker::deviceRegistered,
 | 
				
			||||||
 | 
					                                      WirelessWorker::generatePin)) == NULL) {
 | 
				
			||||||
 | 
					        qDebug("Error connecting to device. Attempt %d", ++num_tries);
 | 
				
			||||||
 | 
					        //FIXME: use a proper sleep function
 | 
				
			||||||
 | 
					        mutex.lock();
 | 
				
			||||||
 | 
					        waitCondition.wait(&mutex, RETRY_TIMEOUT);
 | 
				
			||||||
 | 
					        mutex.unlock();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qDebug("Stopping broadcast");
 | 
				
			||||||
 | 
					    broadcast->stopBroadcast();
 | 
				
			||||||
 | 
					    return vita;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vita_device_t *QCMA::connectUsb()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int num_tries = 0;
 | 
				
			||||||
 | 
					    vita_device_t *vita = NULL;
 | 
				
			||||||
 | 
					    QMutex mutex;
 | 
				
			||||||
 | 
					    while(!break_loop && (vita = VitaMTP_Get_First_USB_Vita()) == NULL) {
 | 
				
			||||||
 | 
					        qDebug("No Vita found. Attempt %d", ++num_tries);
 | 
				
			||||||
 | 
					        //FIXME: use a proper sleep function
 | 
				
			||||||
 | 
					        mutex.lock();
 | 
				
			||||||
 | 
					        waitCondition.wait(&mutex, RETRY_TIMEOUT);
 | 
				
			||||||
 | 
					        mutex.unlock();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return vita;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QCMA::process()
 | 
				
			||||||
 | 
					{    
 | 
				
			||||||
 | 
					    QSettings settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qDebug() << "From QCMA: "<< QThread::currentThreadId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(!exit_thread) {
 | 
				
			||||||
 | 
					        break_loop = false;
 | 
				
			||||||
 | 
					        VitaMTP_Set_Logging(VitaMTP_NONE);
 | 
				
			||||||
 | 
					        bool wireless = settings.value("wireless", false).toBool();
 | 
				
			||||||
 | 
					        emit statusUpdated("Searching for device...");
 | 
				
			||||||
 | 
					        vita_device_t *device = wireless ? connectWireless() : connectUsb();
 | 
				
			||||||
 | 
					        if(!device) {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        qDebug("Vita connected: id %s", VitaMTP_Get_Identification(device));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // create a listener thread to receive the vita events
 | 
				
			||||||
 | 
					        ListenerWorker *listener = new ListenerWorker();
 | 
				
			||||||
 | 
					        listener->setDevice(device);
 | 
				
			||||||
 | 
					        connect(listener, SIGNAL(refreshDatabase()), this, SLOT(allowRefresh()), Qt::DirectConnection);
 | 
				
			||||||
 | 
					        connect(listener, SIGNAL(finished()), this, SIGNAL(deviceDisconnected()), Qt::DirectConnection);
 | 
				
			||||||
 | 
					        connect(listener, SIGNAL(finished()), this, SLOT(reload()), Qt::DirectConnection);
 | 
				
			||||||
 | 
					        listener->start();
 | 
				
			||||||
 | 
					        qDebug("Exchanging info with vita");
 | 
				
			||||||
 | 
					        DeviceCapability *vita_info = new DeviceCapability();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!vita_info->exchangeInfo(device)) {
 | 
				
			||||||
 | 
					            qCritical("Error while exchanging info with the vita");
 | 
				
			||||||
 | 
					            VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection);
 | 
				
			||||||
 | 
					            VitaMTP_Release_Device(device);
 | 
				
			||||||
 | 
					            sleep(RETRY_TIMEOUT);
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Conection successful, inform the user
 | 
				
			||||||
 | 
					        emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        delete vita_info;
 | 
				
			||||||
 | 
					        QElapsedTimer timer;
 | 
				
			||||||
 | 
					        qint64 sec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while(listener->isConnected()) {
 | 
				
			||||||
 | 
					            sema.acquire();
 | 
				
			||||||
 | 
					            if(break_loop) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            qDebug("Updating database");
 | 
				
			||||||
 | 
					            timer.start();
 | 
				
			||||||
 | 
					            int scanned_objects = listener->rebuildDatabase();
 | 
				
			||||||
 | 
					            sec = timer.elapsed();
 | 
				
			||||||
 | 
					            qDebug("Scanned %i objects in %lli milliseconds", scanned_objects, sec);
 | 
				
			||||||
 | 
					            emit statusUpdated(QString("Scanned %1 objects in %2 milliseconds").arg(scanned_objects, sec));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        qDebug("Ending device connection...");
 | 
				
			||||||
 | 
					        VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection);
 | 
				
			||||||
 | 
					        VitaMTP_Release_Device(device);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qDebug("QCMA thread end");
 | 
				
			||||||
 | 
					    emit finished();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QCMA::allowRefresh()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    sema.release();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QCMA::reload()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Stopping QCMA workers...");
 | 
				
			||||||
 | 
					    break_loop = true;
 | 
				
			||||||
 | 
					    waitCondition.wakeAll();
 | 
				
			||||||
 | 
					    sema.release();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QCMA::stop()
 | 
				
			||||||
 | 
					{    
 | 
				
			||||||
 | 
					    exit_thread = true;
 | 
				
			||||||
 | 
					    reload();
 | 
				
			||||||
 | 
					    qDebug("Stopping QCMA thread...");
 | 
				
			||||||
 | 
					    emit stopCMA();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										70
									
								
								qcma.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								qcma.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef QCMA_H
 | 
				
			||||||
 | 
					#define QCMA_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "baseworker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QSystemTrayIcon>
 | 
				
			||||||
 | 
					#include <QThread>
 | 
				
			||||||
 | 
					#include <QWidget>
 | 
				
			||||||
 | 
					#include <QMenu>
 | 
				
			||||||
 | 
					#include <QWaitCondition>
 | 
				
			||||||
 | 
					#include <QSemaphore>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QMenu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include <vitamtp.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define QCMA_VERSION_STRING "QCMA 0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QCMA : public BaseWorker
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit QCMA(QObject *parent = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    QSemaphore sema;
 | 
				
			||||||
 | 
					    QWaitCondition waitCondition;
 | 
				
			||||||
 | 
					    volatile bool break_loop;
 | 
				
			||||||
 | 
					    volatile bool exit_thread;
 | 
				
			||||||
 | 
					    vita_device_t *connectUsb();
 | 
				
			||||||
 | 
					    vita_device_t *connectWireless();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
					    void createdPin(int);
 | 
				
			||||||
 | 
					    void deviceConnected(QString);
 | 
				
			||||||
 | 
					    void statusUpdated(QString);
 | 
				
			||||||
 | 
					    void deviceDisconnected();
 | 
				
			||||||
 | 
					    void stopCMA();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public slots:
 | 
				
			||||||
 | 
					    void stop();
 | 
				
			||||||
 | 
					    void reload();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected slots:
 | 
				
			||||||
 | 
					    void allowRefresh();
 | 
				
			||||||
 | 
					    virtual void process();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // QCMA_H
 | 
				
			||||||
							
								
								
									
										58
									
								
								qcma.pro
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								qcma.pro
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					#-------------------------------------------------
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Project created by QtCreator 2013-07-23T15:34:17
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#-------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QT       += core \
 | 
				
			||||||
 | 
					            gui \
 | 
				
			||||||
 | 
					            widgets \
 | 
				
			||||||
 | 
					            network
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TARGET = qcma
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEMPLATE = app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SOURCES += main.cpp \
 | 
				
			||||||
 | 
					    qcma.cpp \
 | 
				
			||||||
 | 
					    wirelessworker.cpp \
 | 
				
			||||||
 | 
					    listenerworker.cpp \
 | 
				
			||||||
 | 
					    capability.cpp \
 | 
				
			||||||
 | 
					    database.cpp \
 | 
				
			||||||
 | 
					    cmaobject.cpp \
 | 
				
			||||||
 | 
					    cmarootobject.cpp \
 | 
				
			||||||
 | 
					    utils.cpp \
 | 
				
			||||||
 | 
					    mainwidget.cpp \
 | 
				
			||||||
 | 
					    configwidget.cpp \
 | 
				
			||||||
 | 
					    singleapplication.cpp \
 | 
				
			||||||
 | 
					    baseworker.cpp \
 | 
				
			||||||
 | 
					    sforeader.cpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HEADERS += \
 | 
				
			||||||
 | 
					    qcma.h \
 | 
				
			||||||
 | 
					    wirelessworker.h \
 | 
				
			||||||
 | 
					    listenerworker.h \
 | 
				
			||||||
 | 
					    capability.h \
 | 
				
			||||||
 | 
					    database.h \
 | 
				
			||||||
 | 
					    cmaobject.h \
 | 
				
			||||||
 | 
					    cmarootobject.h \
 | 
				
			||||||
 | 
					    utils.h \
 | 
				
			||||||
 | 
					    mainwidget.h \
 | 
				
			||||||
 | 
					    configwidget.h \
 | 
				
			||||||
 | 
					    singleapplication.h \
 | 
				
			||||||
 | 
					    baseworker.h \
 | 
				
			||||||
 | 
					    sforeader.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG += link_pkgconfig
 | 
				
			||||||
 | 
					PKGCONFIG += libvitamtp libmediainfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QMAKE_CXXFLAGS += -Wno-write-strings -Wall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RESOURCES += \
 | 
				
			||||||
 | 
					    qcmares.qrc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OTHER_FILES += \
 | 
				
			||||||
 | 
					    psp2-updatelist.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FORMS += \
 | 
				
			||||||
 | 
					    configwidget.ui
 | 
				
			||||||
							
								
								
									
										5
									
								
								qcmares.qrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								qcmares.qrc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					<RCC>
 | 
				
			||||||
 | 
					    <qresource prefix="/main">
 | 
				
			||||||
 | 
					        <file>psp2-updatelist.xml</file>
 | 
				
			||||||
 | 
					    </qresource>
 | 
				
			||||||
 | 
					</RCC>
 | 
				
			||||||
							
								
								
									
										49
									
								
								sforeader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								sforeader.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "sforeader.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QFile>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SfoReader::SfoReader()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool SfoReader::load(const QString &path) {
 | 
				
			||||||
 | 
					    QFile file(path);
 | 
				
			||||||
 | 
					    if(file.open(QIODevice::ReadOnly)) {
 | 
				
			||||||
 | 
					        data = file.readAll();
 | 
				
			||||||
 | 
					        key_offset = data.constData();
 | 
				
			||||||
 | 
					        header = (sfo_header *)key_offset;
 | 
				
			||||||
 | 
					        index = (sfo_index *)(key_offset + sizeof(sfo_header));
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *SfoReader::value(const char *key, const char *defaultValue) {
 | 
				
			||||||
 | 
					    const char *base_key = key_offset + header->key_offset;
 | 
				
			||||||
 | 
					    for(uint i = 0; i < header->pair_count; i++) {
 | 
				
			||||||
 | 
					        const char *curr_key = base_key + index[i].key_offset;
 | 
				
			||||||
 | 
					        if(strcmp(key, curr_key) == 0) {
 | 
				
			||||||
 | 
					           return key_offset + header->value_offset + index[i].data_offset;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return defaultValue;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										56
									
								
								sforeader.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								sforeader.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef SFOREADER_H
 | 
				
			||||||
 | 
					#define SFOREADER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QString>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SfoReader
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    SfoReader();
 | 
				
			||||||
 | 
					    bool load(const QString &path);
 | 
				
			||||||
 | 
					    const char *value(const char *key, const char *defaultValue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    typedef struct {
 | 
				
			||||||
 | 
					        quint16 key_offset;
 | 
				
			||||||
 | 
					        uchar alignment;
 | 
				
			||||||
 | 
					        uchar data_type;
 | 
				
			||||||
 | 
					        quint32 value_size;
 | 
				
			||||||
 | 
					        quint32 value_size_with_padding;
 | 
				
			||||||
 | 
					        quint32 data_offset;
 | 
				
			||||||
 | 
					    }__attribute__((packed)) sfo_index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    typedef struct {
 | 
				
			||||||
 | 
					        char id[4];
 | 
				
			||||||
 | 
					        quint32 version;
 | 
				
			||||||
 | 
					        quint32 key_offset;
 | 
				
			||||||
 | 
					        quint32 value_offset;
 | 
				
			||||||
 | 
					        quint32 pair_count;
 | 
				
			||||||
 | 
					    }__attribute__((packed)) sfo_header;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QByteArray data;
 | 
				
			||||||
 | 
					    const char *key_offset;
 | 
				
			||||||
 | 
					    const sfo_header *header;
 | 
				
			||||||
 | 
					    const sfo_index *index;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // SFOREADER_H
 | 
				
			||||||
							
								
								
									
										78
									
								
								singleapplication.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								singleapplication.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "singleapplication.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QDebug>
 | 
				
			||||||
 | 
					#include <QFile>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const int SingleApplication::timeout = 500;
 | 
				
			||||||
 | 
					const QString SingleApplication::SHARED_KEY = "QCMA_KEY";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SingleApplication::SingleApplication(int &argc, char **argv) :
 | 
				
			||||||
 | 
					    QApplication(argc, argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    server = new QLocalServer(this);
 | 
				
			||||||
 | 
					    connect(server, SIGNAL(newConnection()), this, SLOT(receiveMessage()));
 | 
				
			||||||
 | 
					#ifdef Q_OS_UNIX
 | 
				
			||||||
 | 
					    // Make sure that the socket file is deleted
 | 
				
			||||||
 | 
					    QFile address(QString("/tmp/" +  SHARED_KEY));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(address.exists()) {
 | 
				
			||||||
 | 
					        address.remove();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    server->listen(SHARED_KEY);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SingleApplication::receiveMessage()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QLocalSocket *socket = server->nextPendingConnection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!socket->waitForReadyRead(timeout)) {
 | 
				
			||||||
 | 
					        qDebug() << socket->errorString();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QByteArray byteArray = socket->readAll();
 | 
				
			||||||
 | 
					    QString message = QString::fromUtf8(byteArray.constData());
 | 
				
			||||||
 | 
					    emit messageAvailable(message);
 | 
				
			||||||
 | 
					    socket->disconnectFromServer();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool SingleApplication::sendMessage(const QString &message)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    QLocalSocket socket;
 | 
				
			||||||
 | 
					    socket.connectToServer(SHARED_KEY, QIODevice::WriteOnly);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!socket.waitForConnected(timeout)) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket.write(message.toUtf8());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!socket.waitForBytesWritten(timeout)) {
 | 
				
			||||||
 | 
					        qDebug() << socket.errorString();
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket.disconnectFromServer();
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										50
									
								
								singleapplication.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								singleapplication.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef SINGLEAPPLICATION_H
 | 
				
			||||||
 | 
					#define SINGLEAPPLICATION_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QApplication>
 | 
				
			||||||
 | 
					#include <QLocalSocket>
 | 
				
			||||||
 | 
					#include <QLocalServer>
 | 
				
			||||||
 | 
					#include <QSharedMemory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SingleApplication : public QApplication
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit SingleApplication(int &argc, char **argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static bool sendMessage(const QString &message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    QLocalServer *server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static const int timeout;
 | 
				
			||||||
 | 
					    static const QString SHARED_KEY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
					    void messageAvailable(QString message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public slots:
 | 
				
			||||||
 | 
					    void receiveMessage();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // SINGLEAPPLICATION_H
 | 
				
			||||||
							
								
								
									
										81
									
								
								utils.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								utils.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QDir>
 | 
				
			||||||
 | 
					#include <QImage>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include <vitamtp.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef Q_OS_WIN32
 | 
				
			||||||
 | 
					#include <windows.h>
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#include <sys/statvfs.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef Q_OS_WIN32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(GetDiskFreeSpaceExW(dir.toStdWString().c_str(), free, total, NULL) != 0) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    struct statvfs64 stat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(statvfs64(dir.toUtf8().data(), &stat) == 0) {
 | 
				
			||||||
 | 
					        *total = stat.f_frsize * stat.f_blocks;
 | 
				
			||||||
 | 
					        *free = stat.f_frsize * stat.f_bfree;
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool removeRecursively(const QString &dirName)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
 | 
				
			||||||
 | 
					    return QDir(dirName).removeRecursively();
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    bool result = false;
 | 
				
			||||||
 | 
					    QDir dir(dirName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(dir.exists(dirName)) {
 | 
				
			||||||
 | 
					        Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden  | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) {
 | 
				
			||||||
 | 
					            if(info.isDir()) {
 | 
				
			||||||
 | 
					                result = removeRecursively(info.absoluteFilePath());
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                result = QFile::remove(info.absoluteFilePath());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(!result) {
 | 
				
			||||||
 | 
					                return result;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        result = dir.rmdir(dirName);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								utils.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef UTILS_H
 | 
				
			||||||
 | 
					#define UTILS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QString>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool removeRecursively(const QString &dirName);
 | 
				
			||||||
 | 
					bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // UTILS_H
 | 
				
			||||||
							
								
								
									
										76
									
								
								wirelessworker.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								wirelessworker.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qcma.h"
 | 
				
			||||||
 | 
					#include "wirelessworker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QTime>
 | 
				
			||||||
 | 
					#include <QHostInfo>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define QCMA_REQUEST_PORT 9309
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					wireless_host_info_t WirelessWorker::info = {"00000000-0000-0000-0000-000000000000", "win", NULL, QCMA_REQUEST_PORT};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WirelessWorker *WirelessWorker::this_object = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WirelessWorker::WirelessWorker(QObject *parent) :
 | 
				
			||||||
 | 
					    BaseWorker(parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qsrand(QTime::currentTime().msec());
 | 
				
			||||||
 | 
					    this_object = this;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int WirelessWorker::deviceRegistered(const char *deviceid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Got connection request from %s", deviceid);
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int WirelessWorker::generatePin(wireless_vita_info_t *info, int *p_err)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug("Registration request from %s (MAC: %s)", info->name, info->mac_addr);
 | 
				
			||||||
 | 
					    int pin = qrand() % 100000000;
 | 
				
			||||||
 | 
					    qDebug("Your registration PIN for %s is: %08d", info->name, pin);
 | 
				
			||||||
 | 
					    *p_err = 0;
 | 
				
			||||||
 | 
					    emit this_object->createdPin(pin);
 | 
				
			||||||
 | 
					    return pin;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void WirelessWorker::process()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qDebug() <<" Wireless thread ID: "<< QThread::currentThreadId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wireless_host_info_t broadcast_info = info;
 | 
				
			||||||
 | 
					    QString hostname = QHostInfo::localHostName();
 | 
				
			||||||
 | 
					    broadcast_info.name = hostname.toUtf8().data();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qDebug("Starting CMA wireless broadcast...");
 | 
				
			||||||
 | 
					    if(VitaMTP_Broadcast_Host(&broadcast_info, 0) < 0) {
 | 
				
			||||||
 | 
					        qCritical( "An error occured during broadcast. Exiting.");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        qDebug("Broadcast ended.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qDebug("WirelessrWorker thread end.");
 | 
				
			||||||
 | 
					    emit finished();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void WirelessWorker::stopBroadcast()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VitaMTP_Stop_Broadcast();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										58
									
								
								wirelessworker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								wirelessworker.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  QCMA: Cross-platform content manager assistant for the PS Vita
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2013  Codestation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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 <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef WIRELESSWORKER_H
 | 
				
			||||||
 | 
					#define WIRELESSWORKER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "baseworker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QObject>
 | 
				
			||||||
 | 
					#include <QSemaphore>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include <vitamtp.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class WirelessWorker : public BaseWorker
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit WirelessWorker(QObject *parent = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static int deviceRegistered(const char *deviceid);
 | 
				
			||||||
 | 
					    static int generatePin(wireless_vita_info_t *info, int *p_err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static wireless_host_info_t info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    //used to emit a signal from a static method
 | 
				
			||||||
 | 
					    static WirelessWorker *this_object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
					    void createdPin(int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public slots:
 | 
				
			||||||
 | 
					    void stopBroadcast();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected slots:
 | 
				
			||||||
 | 
					    void process();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // WIRELESSWORKER_H
 | 
				
			||||||
		Reference in New Issue
	
	Block a user