From 3966e60efb5d5e96706f6281d2dc7cbc00e1f517 Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Sun, 18 Oct 2020 12:21:52 +0300 Subject: [PATCH] generic: move kfilemetadata and svgpart from kde-extraapps Signed-off-by: Ivailo Monev --- kfilemetadata/CMakeLists.txt | 71 +++ kfilemetadata/COPYING-CMAKE-SCRIPTS | 22 + kfilemetadata/COPYING.LGPL-2 | 481 +++++++++++++++++ kfilemetadata/COPYING.LGPL-2.1 | 502 ++++++++++++++++++ kfilemetadata/COPYING.LGPL-3 | 165 ++++++ kfilemetadata/KFileMetaDataConfig.cmake.in | 18 + kfilemetadata/Messages.sh | 5 + kfilemetadata/autotests/CMakeLists.txt | 30 ++ .../autotests/indexerextractortests.cpp | 118 ++++ .../autotests/indexerextractortests.h | 44 ++ .../indexerextractortestsconfig.h.in | 27 + kfilemetadata/autotests/propertyinfotest.cpp | 49 ++ kfilemetadata/autotests/propertyinfotest.h | 37 ++ kfilemetadata/autotests/samplefiles/README | 4 + .../autotests/samplefiles/plain_text_file.txt | 4 + kfilemetadata/autotests/samplefiles/tux.png | Bin 0 -> 41427 bytes kfilemetadata/autotests/simpleresult.cpp | 59 ++ kfilemetadata/autotests/simpleresult.h | 51 ++ kfilemetadata/src/CMakeLists.txt | 41 ++ kfilemetadata/src/extractionresult.cpp | 57 ++ kfilemetadata/src/extractionresult.h | 100 ++++ kfilemetadata/src/extractorplugin.cpp | 144 +++++ kfilemetadata/src/extractorplugin.h | 112 ++++ kfilemetadata/src/extractorpluginmanager.cpp | 94 ++++ kfilemetadata/src/extractorpluginmanager.h | 65 +++ kfilemetadata/src/extractors/CMakeLists.txt | 207 ++++++++ .../src/extractors/epubextractor.cpp | 184 +++++++ kfilemetadata/src/extractors/epubextractor.h | 39 ++ .../src/extractors/exiv2extractor.cpp | 209 ++++++++ kfilemetadata/src/extractors/exiv2extractor.h | 45 ++ .../src/extractors/ffmpegextractor.cpp | 182 +++++++ .../src/extractors/ffmpegextractor.h | 39 ++ .../kfilemetadata_epubextractor.desktop | 42 ++ .../kfilemetadata_exiv2extractor.desktop | 42 ++ .../kfilemetadata_ffmpegextractor.desktop | 42 ++ .../kfilemetadata_mobiextractor.desktop | 42 ++ .../kfilemetadata_odfextractor.desktop | 42 ++ .../kfilemetadata_office2007extractor.desktop | 42 ++ .../kfilemetadata_officeextractor.desktop | 42 ++ .../kfilemetadata_plaintextextractor.desktop | 42 ++ .../kfilemetadata_popplerextractor.desktop | 42 ++ .../kfilemetadata_taglibextractor.desktop | 42 ++ .../src/extractors/mobiextractor.cpp | 112 ++++ kfilemetadata/src/extractors/mobiextractor.h | 39 ++ kfilemetadata/src/extractors/odfextractor.cpp | 138 +++++ kfilemetadata/src/extractors/odfextractor.h | 41 ++ .../src/extractors/office2007extractor.cpp | 268 ++++++++++ .../src/extractors/office2007extractor.h | 46 ++ .../src/extractors/officeextractor.cpp | 118 ++++ .../src/extractors/officeextractor.h | 50 ++ .../src/extractors/plaintextextractor.cpp | 59 ++ .../src/extractors/plaintextextractor.h | 40 ++ .../src/extractors/popplerextractor.cpp | 174 ++++++ .../src/extractors/popplerextractor.h | 43 ++ .../src/extractors/taglibextractor.cpp | 432 +++++++++++++++ .../src/extractors/taglibextractor.h | 41 ++ kfilemetadata/src/kfilemetadata_export.h | 39 ++ .../src/kfilemetadataextractor.desktop | 42 ++ kfilemetadata/src/properties.h | 126 +++++ kfilemetadata/src/propertyinfo.cpp | 472 ++++++++++++++++ kfilemetadata/src/propertyinfo.h | 81 +++ kfilemetadata/src/typeinfo.cpp | 101 ++++ kfilemetadata/src/typeinfo.h | 58 ++ kfilemetadata/src/types.h | 82 +++ svgpart/CMakeLists.txt | 22 + svgpart/COPYING | 339 ++++++++++++ svgpart/Messages.sh | 3 + svgpart/svgpart.cpp | 109 ++++ svgpart/svgpart.desktop | 67 +++ svgpart/svgpart.h | 56 ++ svgpart/svgpart.rc | 22 + 71 files changed, 6845 insertions(+) create mode 100644 kfilemetadata/CMakeLists.txt create mode 100644 kfilemetadata/COPYING-CMAKE-SCRIPTS create mode 100644 kfilemetadata/COPYING.LGPL-2 create mode 100644 kfilemetadata/COPYING.LGPL-2.1 create mode 100644 kfilemetadata/COPYING.LGPL-3 create mode 100644 kfilemetadata/KFileMetaDataConfig.cmake.in create mode 100644 kfilemetadata/Messages.sh create mode 100644 kfilemetadata/autotests/CMakeLists.txt create mode 100644 kfilemetadata/autotests/indexerextractortests.cpp create mode 100644 kfilemetadata/autotests/indexerextractortests.h create mode 100644 kfilemetadata/autotests/indexerextractortestsconfig.h.in create mode 100644 kfilemetadata/autotests/propertyinfotest.cpp create mode 100644 kfilemetadata/autotests/propertyinfotest.h create mode 100644 kfilemetadata/autotests/samplefiles/README create mode 100644 kfilemetadata/autotests/samplefiles/plain_text_file.txt create mode 100644 kfilemetadata/autotests/samplefiles/tux.png create mode 100644 kfilemetadata/autotests/simpleresult.cpp create mode 100644 kfilemetadata/autotests/simpleresult.h create mode 100644 kfilemetadata/src/CMakeLists.txt create mode 100644 kfilemetadata/src/extractionresult.cpp create mode 100644 kfilemetadata/src/extractionresult.h create mode 100644 kfilemetadata/src/extractorplugin.cpp create mode 100644 kfilemetadata/src/extractorplugin.h create mode 100644 kfilemetadata/src/extractorpluginmanager.cpp create mode 100644 kfilemetadata/src/extractorpluginmanager.h create mode 100644 kfilemetadata/src/extractors/CMakeLists.txt create mode 100644 kfilemetadata/src/extractors/epubextractor.cpp create mode 100644 kfilemetadata/src/extractors/epubextractor.h create mode 100644 kfilemetadata/src/extractors/exiv2extractor.cpp create mode 100644 kfilemetadata/src/extractors/exiv2extractor.h create mode 100644 kfilemetadata/src/extractors/ffmpegextractor.cpp create mode 100644 kfilemetadata/src/extractors/ffmpegextractor.h create mode 100644 kfilemetadata/src/extractors/kfilemetadata_epubextractor.desktop create mode 100644 kfilemetadata/src/extractors/kfilemetadata_exiv2extractor.desktop create mode 100644 kfilemetadata/src/extractors/kfilemetadata_ffmpegextractor.desktop create mode 100644 kfilemetadata/src/extractors/kfilemetadata_mobiextractor.desktop create mode 100644 kfilemetadata/src/extractors/kfilemetadata_odfextractor.desktop create mode 100644 kfilemetadata/src/extractors/kfilemetadata_office2007extractor.desktop create mode 100644 kfilemetadata/src/extractors/kfilemetadata_officeextractor.desktop create mode 100644 kfilemetadata/src/extractors/kfilemetadata_plaintextextractor.desktop create mode 100644 kfilemetadata/src/extractors/kfilemetadata_popplerextractor.desktop create mode 100644 kfilemetadata/src/extractors/kfilemetadata_taglibextractor.desktop create mode 100644 kfilemetadata/src/extractors/mobiextractor.cpp create mode 100644 kfilemetadata/src/extractors/mobiextractor.h create mode 100644 kfilemetadata/src/extractors/odfextractor.cpp create mode 100644 kfilemetadata/src/extractors/odfextractor.h create mode 100644 kfilemetadata/src/extractors/office2007extractor.cpp create mode 100644 kfilemetadata/src/extractors/office2007extractor.h create mode 100644 kfilemetadata/src/extractors/officeextractor.cpp create mode 100644 kfilemetadata/src/extractors/officeextractor.h create mode 100644 kfilemetadata/src/extractors/plaintextextractor.cpp create mode 100644 kfilemetadata/src/extractors/plaintextextractor.h create mode 100644 kfilemetadata/src/extractors/popplerextractor.cpp create mode 100644 kfilemetadata/src/extractors/popplerextractor.h create mode 100644 kfilemetadata/src/extractors/taglibextractor.cpp create mode 100644 kfilemetadata/src/extractors/taglibextractor.h create mode 100644 kfilemetadata/src/kfilemetadata_export.h create mode 100644 kfilemetadata/src/kfilemetadataextractor.desktop create mode 100644 kfilemetadata/src/properties.h create mode 100644 kfilemetadata/src/propertyinfo.cpp create mode 100644 kfilemetadata/src/propertyinfo.h create mode 100644 kfilemetadata/src/typeinfo.cpp create mode 100644 kfilemetadata/src/typeinfo.h create mode 100644 kfilemetadata/src/types.h create mode 100644 svgpart/CMakeLists.txt create mode 100644 svgpart/COPYING create mode 100755 svgpart/Messages.sh create mode 100644 svgpart/svgpart.cpp create mode 100644 svgpart/svgpart.desktop create mode 100644 svgpart/svgpart.h create mode 100644 svgpart/svgpart.rc diff --git a/kfilemetadata/CMakeLists.txt b/kfilemetadata/CMakeLists.txt new file mode 100644 index 00000000..923bfe64 --- /dev/null +++ b/kfilemetadata/CMakeLists.txt @@ -0,0 +1,71 @@ +project(kfilemetadata) + +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + find_package(KDE4 4.19.0 REQUIRED) + include(KDE4Defaults) + include_directories(${KDE4_INCLUDES}) + add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) +endif() + +macro_optional_find_package(PopplerQt4 0.12.1) +set_package_properties(PopplerQt4 PROPERTIES + DESCRIPTION "A PDF rendering library" + URL "http://poppler.freedesktop.org" + PURPOSE "Support for PDF files" +) + +macro_optional_find_package(Taglib 1.4) +set_package_properties(Taglib PROPERTIES + DESCRIPTION "Id3 tag reader" + URL "https://taglib.org/" + PURPOSE "Support for music metadata" +) + +macro_optional_find_package(Exiv2 0.21) +set_package_properties(Exiv2 PROPERTIES + DESCRIPTION "Image Tag reader" + URL "http://www.exiv2.org" + PURPOSE "Support for image metadata" +) + +macro_optional_find_package(FFmpeg 1.0) +set_package_properties(FFmpeg PROPERTIES + DESCRIPTION "Video Tag reader" + URL "http://ffmpeg.org" + PURPOSE "Support for video metadata" +) + +macro_optional_find_package(EPub) +set_package_properties(EPub PROPERTIES + DESCRIPTION "A library for reading EPub documents" + URL "http://sourceforge.net/projects/ebook-tools" + PURPOSE "Support for epub metadata" +) + +macro_optional_find_package(QMobipocket) +set_package_properties(QMobipocket PROPERTIES + DESCRIPTION "A library for reading Mobipocket documents" + URL "https://projects.kde.org/projects/kde/kdegraphics/kdegraphics-mobipocket" + PURPOSE "Support for Mobipocket documents metadata in KFileMetaData" +) + +include_directories( + ${PROJECT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR}/src +) + +add_subdirectory(src) +if(ENABLE_TESTING) + add_subdirectory(autotests) +endif() + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/KFileMetaDataConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/KFileMetaDataConfig.cmake + @ONLY +) + +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/KFileMetaDataConfig.cmake + DESTINATION ${KDE4_LIB_INSTALL_DIR}/cmake/KFileMetaData +) diff --git a/kfilemetadata/COPYING-CMAKE-SCRIPTS b/kfilemetadata/COPYING-CMAKE-SCRIPTS new file mode 100644 index 00000000..4b417765 --- /dev/null +++ b/kfilemetadata/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/kfilemetadata/COPYING.LGPL-2 b/kfilemetadata/COPYING.LGPL-2 new file mode 100644 index 00000000..5bc8fb2c --- /dev/null +++ b/kfilemetadata/COPYING.LGPL-2 @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library 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 Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/kfilemetadata/COPYING.LGPL-2.1 b/kfilemetadata/COPYING.LGPL-2.1 new file mode 100644 index 00000000..4362b491 --- /dev/null +++ b/kfilemetadata/COPYING.LGPL-2.1 @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/kfilemetadata/COPYING.LGPL-3 b/kfilemetadata/COPYING.LGPL-3 new file mode 100644 index 00000000..65c5ca88 --- /dev/null +++ b/kfilemetadata/COPYING.LGPL-3 @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser 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 +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/kfilemetadata/KFileMetaDataConfig.cmake.in b/kfilemetadata/KFileMetaDataConfig.cmake.in new file mode 100644 index 00000000..cccbaf3e --- /dev/null +++ b/kfilemetadata/KFileMetaDataConfig.cmake.in @@ -0,0 +1,18 @@ +# Do not modify this file. Any change will be overwritten by CMake. + +# Config file for KFileMetaData. This file will define: +# KFILEMETADATA_INCLUDE_DIR - The KFileMetaData include directory +# KFILEMETADATA_LIBRARY - The library needed to use KFileMetaData + +get_filename_component(_currentDir ${CMAKE_CURRENT_LIST_FILE} PATH) # The current directory +get_filename_component(rootDir ${_currentDir}/@relInstallDir@ ABSOLUTE) # The install prefix + +# Include directory +set(KFILEMETADATA_INSTALL_PREFIX "${rootDir}") +set(KFILEMETADATA_INCLUDE_DIR "@KDE4_INCLUDE_INSTALL_DIR@") + +include(${_currentDir}/KFileMetaDataTargetsWithPrefix.cmake) + +# Set the library variable +set(KFILEMETADATA_LIBRARY kfilemetadata) + diff --git a/kfilemetadata/Messages.sh b/kfilemetadata/Messages.sh new file mode 100644 index 00000000..5300ca82 --- /dev/null +++ b/kfilemetadata/Messages.sh @@ -0,0 +1,5 @@ +#!bin/sh + +$EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp +$XGETTEXT `find . -name \*.cc -o -name \*.cpp -o -name \*.h -name \*.qml` -o $podir/kfilemetadata.pot +rm -f rc.cpp diff --git a/kfilemetadata/autotests/CMakeLists.txt b/kfilemetadata/autotests/CMakeLists.txt new file mode 100644 index 00000000..c95a9398 --- /dev/null +++ b/kfilemetadata/autotests/CMakeLists.txt @@ -0,0 +1,30 @@ +configure_file( + indexerextractortestsconfig.h.in + ${CMAKE_CURRENT_BINARY_DIR}/indexerextractortestsconfig.h @ONLY +) + +kde4_add_test(kfilemetadata-extractortests + indexerextractortests.cpp + simpleresult.cpp + ../src/extractors/plaintextextractor.cpp +) + +target_link_libraries(kfilemetadata-extractortests + ${QT_QTTEST_LIBRARY} + ${KDE4_KDECORE_LIBS} + kfilemetadata +) + +# +# Property Info +# +kde4_add_test(kfilemetadata-propertyinfotest + propertyinfotest.cpp +) + +target_link_libraries(kfilemetadata-propertyinfotest + ${QT_QTTEST_LIBRARY} + ${KDE4_KDECORE_LIBS} + kfilemetadata +) + diff --git a/kfilemetadata/autotests/indexerextractortests.cpp b/kfilemetadata/autotests/indexerextractortests.cpp new file mode 100644 index 00000000..87f81a80 --- /dev/null +++ b/kfilemetadata/autotests/indexerextractortests.cpp @@ -0,0 +1,118 @@ +/* + This file is part of the Nepomuk KDE project. + Copyright (C) 2013 David Edmundson + Copyright (C) 2014 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#include "indexerextractortests.h" + +#include +#include + +#include "qtest_kde.h" +#include "simpleresult.h" +#include "indexerextractortestsconfig.h" +#include "extractors/plaintextextractor.h" +#include "extractorpluginmanager.h" + +using namespace KFileMetaData; + +IndexerExtractorTests::IndexerExtractorTests(QObject* parent) : + QObject(parent) +{ +} + +QString IndexerExtractorTests::testFilePath(const QString& fileName) const +{ + return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QDir::separator() + fileName; +} + +void IndexerExtractorTests::benchMarkPlainTextExtractor() +{ + PlainTextExtractor plugin(this, QVariantList()); + + // generate a test file with varying number of words per line + QTemporaryFile file("XXXXXX.txt"); + QVERIFY(file.open()); + QByteArray chunk("foo bar "); + for (int line = 0; line < 10000; ++line) { + for (int i = 0; i < line % 100; ++i) { + file.write(chunk); + } + file.write("\n"); + } + + SimpleResult result(file.fileName(), "text/plain"); + + QBENCHMARK { + plugin.extract(&result); + } +} + +void IndexerExtractorTests::benchMarkManager() +{ + QBENCHMARK { + testImageExtractor(); + } +} + +void IndexerExtractorTests::testPlainTextExtractor() +{ + QScopedPointer plugin(new PlainTextExtractor(this, QVariantList())); + + SimpleResult result(testFilePath("plain_text_file.txt"), "text/plain"); + plugin->extract(&result); + + QString content; + QTextStream(&content) << "This is a text file\n" + << "it is four lines long\n" + << "it has 77 characters\n" + << "and 17 words.\n"; + + QCOMPARE(result.types().size(), 1); + QCOMPARE(result.types().first(), Type::Text); + + QCOMPARE(result.properties().size(), 1); + QCOMPARE(result.properties().value(Property::LineCount), QVariant(4)); + + content.replace(QLatin1Char('\n'), QLatin1Char(' ')); + QCOMPARE(result.text(), content); +} + +void IndexerExtractorTests::testImageExtractor() +{ + QScopedPointer manager(new ExtractorPluginManager(this)); + QList extractors = manager->fetchExtractors("image/png"); + if (extractors.isEmpty()) { + QSKIP("No extractors for image/png", SkipAll); + } + + SimpleResult result(testFilePath("tux.png"), "image/png"); + extractors.first()->extract(&result); + + QCOMPARE(result.types().size(), 1); + QCOMPARE(result.types().first(), Type::Image); + + QCOMPARE(result.properties().size(), 2); + QCOMPARE(result.properties().value(Property::Width), QVariant("386")); + QCOMPARE(result.properties().value(Property::Height), QVariant("395")); +} + +QTEST_KDEMAIN_CORE(IndexerExtractorTests) + diff --git a/kfilemetadata/autotests/indexerextractortests.h b/kfilemetadata/autotests/indexerextractortests.h new file mode 100644 index 00000000..bb3b1963 --- /dev/null +++ b/kfilemetadata/autotests/indexerextractortests.h @@ -0,0 +1,44 @@ +/* + This file is part of the Nepomuk KDE project. + Copyright (C) 2013 David Edmundson + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef INDEXEREXTRACTORTESTS_H +#define INDEXEREXTRACTORTESTS_H + +#include +#include + +class IndexerExtractorTests : public QObject +{ + Q_OBJECT +public: + explicit IndexerExtractorTests(QObject* parent = 0); + +private: + QString testFilePath(const QString& fileName) const; + +private slots: + void benchMarkPlainTextExtractor(); + void benchMarkManager(); + void testPlainTextExtractor(); + void testImageExtractor(); +}; + +#endif // INDEXERTESTS_H diff --git a/kfilemetadata/autotests/indexerextractortestsconfig.h.in b/kfilemetadata/autotests/indexerextractortestsconfig.h.in new file mode 100644 index 00000000..0ef657de --- /dev/null +++ b/kfilemetadata/autotests/indexerextractortestsconfig.h.in @@ -0,0 +1,27 @@ +/* + This file is part of the Nepomuk KDE project. + Copyright (C) 2013 David Edmundson + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef INDEXEREXTRACTORTESTSCONFIG_H +#define INDEXEREXTRACTORTESTSCONFIG_H + +#define INDEXER_TESTS_SAMPLE_FILES_PATH "@CMAKE_CURRENT_SOURCE_DIR@/samplefiles" + +#endif diff --git a/kfilemetadata/autotests/propertyinfotest.cpp b/kfilemetadata/autotests/propertyinfotest.cpp new file mode 100644 index 00000000..509cd54e --- /dev/null +++ b/kfilemetadata/autotests/propertyinfotest.cpp @@ -0,0 +1,49 @@ +/* + * This file is part of the KDE KFileMetaData project + * Copyright (C) 2014 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "propertyinfotest.h" +#include "propertyinfo.h" + +#include +#include + +using namespace KFileMetaData; + +void PropertyInfoTest::testNameIdMapping() +{ + // The +1 is to avoid the Empty Property + int i = static_cast(Property::FirstProperty) + 1; + int e = static_cast(Property::LastProperty); + + for (; i <= e; i++) { + Property::Property p = static_cast(i); + PropertyInfo pi(p); + + // qDebug() << pi.name(); + QCOMPARE(pi.property(), p); + QVERIFY(!pi.name().isEmpty()); + QVERIFY(!pi.displayName().isEmpty()); + + PropertyInfo pi2 = PropertyInfo::fromName(pi.name()); + QCOMPARE(pi2.property(), p); + } +} + +QTEST_KDEMAIN_CORE(PropertyInfoTest) diff --git a/kfilemetadata/autotests/propertyinfotest.h b/kfilemetadata/autotests/propertyinfotest.h new file mode 100644 index 00000000..677ade1a --- /dev/null +++ b/kfilemetadata/autotests/propertyinfotest.h @@ -0,0 +1,37 @@ +/* + * This file is part of the KDE KFileMetaData project + * Copyright (C) 2014 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef PROPERTYINFOTEST_H +#define PROPERTYINFOTEST_H + +#include + +namespace KFileMetaData { + +class PropertyInfoTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testNameIdMapping(); +}; + +} + +#endif // PROPERTYINFOTEST_H diff --git a/kfilemetadata/autotests/samplefiles/README b/kfilemetadata/autotests/samplefiles/README new file mode 100644 index 00000000..6e50bdeb --- /dev/null +++ b/kfilemetadata/autotests/samplefiles/README @@ -0,0 +1,4 @@ +This folder contains various small files to be indexed by indexerextractortests. + +plain_text_file.txt + - extract metadata with "cat" and "wc" diff --git a/kfilemetadata/autotests/samplefiles/plain_text_file.txt b/kfilemetadata/autotests/samplefiles/plain_text_file.txt new file mode 100644 index 00000000..c84b8631 --- /dev/null +++ b/kfilemetadata/autotests/samplefiles/plain_text_file.txt @@ -0,0 +1,4 @@ +This is a text file +it is four lines long +it has 77 characters +and 17 words. diff --git a/kfilemetadata/autotests/samplefiles/tux.png b/kfilemetadata/autotests/samplefiles/tux.png new file mode 100644 index 0000000000000000000000000000000000000000..2567fe7ca4fda298a31b02ccf70974dbdd86cb3e GIT binary patch literal 41427 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 Hu0mjfbD)p; literal 0 HcmV?d00001 diff --git a/kfilemetadata/autotests/simpleresult.cpp b/kfilemetadata/autotests/simpleresult.cpp new file mode 100644 index 00000000..8283e1ac --- /dev/null +++ b/kfilemetadata/autotests/simpleresult.cpp @@ -0,0 +1,59 @@ +/* + * + * Copyright (C) 2014 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "simpleresult.h" + +using namespace KFileMetaData; + +SimpleResult::SimpleResult(const QString& url, const QString& mimetype) + : ExtractionResult(url, mimetype) +{ +} + +void SimpleResult::add(Property::Property property, const QVariant& value) +{ + m_properties.insertMulti(property, value); +} + +void SimpleResult::addType(Type::Type type) +{ + m_types << type; +} + +void SimpleResult::append(const QString& text) +{ + m_text.append(text); + m_text.append(QLatin1Char(' ')); +} + +PropertyMap SimpleResult::properties() const +{ + return m_properties; +} + +QString SimpleResult::text() const +{ + return m_text; +} + +QVector SimpleResult::types() const +{ + return m_types; +} diff --git a/kfilemetadata/autotests/simpleresult.h b/kfilemetadata/autotests/simpleresult.h new file mode 100644 index 00000000..f3793b5e --- /dev/null +++ b/kfilemetadata/autotests/simpleresult.h @@ -0,0 +1,51 @@ +/* + * + * Copyright (C) 2014 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef KFILEMETADATA_SIMPLERESULT_H +#define KFILEMETADATA_SIMPLERESULT_H + +#include "extractionresult.h" +#include +#include + +namespace KFileMetaData { + +class SimpleResult : public ExtractionResult +{ +public: + SimpleResult(const QString& url, const QString& mimetype); + + virtual void add(Property::Property property, const QVariant& value); + virtual void addType(Type::Type type); + virtual void append(const QString& text); + + PropertyMap properties() const; + QString text() const; + QVector types() const; + +private: + PropertyMap m_properties; + QString m_text; + QVector m_types; +}; + +} + +#endif // KFILEMETADATA_SIMPLERESULT_H diff --git a/kfilemetadata/src/CMakeLists.txt b/kfilemetadata/src/CMakeLists.txt new file mode 100644 index 00000000..7f6500ed --- /dev/null +++ b/kfilemetadata/src/CMakeLists.txt @@ -0,0 +1,41 @@ +add_library(kfilemetadata SHARED + extractionresult.cpp + extractorplugin.cpp + extractorpluginmanager.cpp + propertyinfo.cpp + typeinfo.cpp +) + +target_link_libraries(kfilemetadata + ${QT_QTCORE_LIBRARY} + ${KDE4_KDECORE_LIBS} +) + +set_target_properties(kfilemetadata PROPERTIES + VERSION ${GENERIC_LIB_VERSION} + SOVERSION ${GENERIC_LIB_SOVERSION} +) + +install(TARGETS kfilemetadata ${INSTALL_TARGETS_DEFAULT_ARGS}) + +install(TARGETS kfilemetadata EXPORT KdeLibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(FILES kfilemetadataextractor.desktop DESTINATION ${KDE4_SERVICETYPES_INSTALL_DIR}) + +install(EXPORT KdeLibsLibraryTargets + DESTINATION ${KDE4_LIB_INSTALL_DIR}/cmake/KFileMetaData + FILE KFileMetaDataTargetsWithPrefix.cmake) + +install(FILES + extractionresult.h + extractorplugin.h + extractorpluginmanager.h + properties.h + propertyinfo.h + types.h + typeinfo.h + kfilemetadata_export.h + DESTINATION ${KDE4_INCLUDE_INSTALL_DIR}/kfilemetadata + COMPONENT Devel +) + +add_subdirectory(extractors) diff --git a/kfilemetadata/src/extractionresult.cpp b/kfilemetadata/src/extractionresult.cpp new file mode 100644 index 00000000..9bc7946f --- /dev/null +++ b/kfilemetadata/src/extractionresult.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#include "extractionresult.h" + +using namespace KFileMetaData; + +class ExtractionResult::Private { +public: + QString url; + QString mimetype; +}; + +ExtractionResult::ExtractionResult(const QString& url, const QString& mimetype) + : d(new Private) +{ + d->url = url; + d->mimetype = mimetype; +} + +ExtractionResult::ExtractionResult(const ExtractionResult& rhs) + : d(new Private(*rhs.d)) +{ +} + +ExtractionResult::~ExtractionResult() +{ + delete d; +} + +QString ExtractionResult::inputUrl() const +{ + return d->url; +} + +QString ExtractionResult::inputMimetype() const +{ + return d->mimetype; +} diff --git a/kfilemetadata/src/extractionresult.h b/kfilemetadata/src/extractionresult.h new file mode 100644 index 00000000..76dfe590 --- /dev/null +++ b/kfilemetadata/src/extractionresult.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2013 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#ifndef _KFILEMETADATA_EXTRACTIONRESULT_H +#define _KFILEMETADATA_EXTRACTIONRESULT_H + +#include +#include + +#include "kfilemetadata_export.h" +#include "properties.h" +#include "types.h" + +namespace KFileMetaData { + +/** + * \class ExtractionResult extractionresult.h + * + * \brief The ExtractionResult class is where all the data extracted by + * the indexer is saved. This class acts as a base class which should be + * dervied from and then passed to the relevant plugins. + * + * The dervied class needs to implement 3 pure virtual functions through + * which it receives the extracted data. + * + * \author Vishesh Handa + */ +class KFILEMETADATA_EXPORT ExtractionResult +{ +public: + ExtractionResult(const QString& url, const QString& mimetype); + ExtractionResult(const ExtractionResult& rhs); + virtual ~ExtractionResult(); + + /** + * The input url which the plugins will use to locate the file + */ + QString inputUrl() const; + + /* + * The input mimetype. This mimetype should correspond with the + * mimetypes supported with the relevant plugin when it is being + * passed to the Extractor + */ + QString inputMimetype() const; + + /** + * This function is called by plugins when they wish for some plain + * text to be indexed without any property. This generally corresponds + * to the text content in a file + */ + virtual void append(const QString& text) = 0; + + /** + * This function is called by the plugins when they wish to + * add a key value pair which should be indexed. This function may be + * called multiple times for the same key. + * + * \p property This specifies a property name. It should be one of the + * properties from the global list of properties. + * + * \p value The value of the property + */ + virtual void add(Property::Property property, const QVariant& value) = 0; + + /** + * This function is caleld by the plugins. + * A type is a higher level classification of the file. Any file can + * have multiple types. Eg - "Audio", "Video" or "Document" + * + * Please choose one type from the list of available types + */ + virtual void addType(Type::Type type) = 0; + +private: + class Private; + Private* d; +}; + +} + +#endif // _KFILEMETADATA_EXTRACTIONRESULT_H diff --git a/kfilemetadata/src/extractorplugin.cpp b/kfilemetadata/src/extractorplugin.cpp new file mode 100644 index 00000000..7980abf6 --- /dev/null +++ b/kfilemetadata/src/extractorplugin.cpp @@ -0,0 +1,144 @@ +/* + + Copyright (C) 2012 Vishesh Handa + Copyright (C) 2012 Jörg Ehrichs + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "extractorplugin.h" + +#include + +using namespace KFileMetaData; + +ExtractorPlugin::ExtractorPlugin(QObject* parent): QObject(parent) +{ +} + +ExtractorPlugin::~ExtractorPlugin() +{ +} + +// +// Helper functions +// + +QDateTime ExtractorPlugin::dateTimeFromString(const QString& dateString) +{ + QDateTime dateTime; + + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("yyyy-MM-dd")); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("dd-MM-yyyy")); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("yyyy-MM")); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("MM-yyyy")); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("yyyy.MM.dd")); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("dd.MM.yyyy")); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("dd MMMM yyyy")); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("MM.yyyy")); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("yyyy.MM")); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("yyyy")); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("yy")); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, Qt::ISODate); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("dddd d MMM yyyy h':'mm':'ss AP")); + dateTime.setTimeSpec(Qt::LocalTime); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, QLatin1String("yyyy:MM:dd hh:mm:ss")); + dateTime.setTimeSpec(Qt::LocalTime); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, Qt::SystemLocaleShortDate); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, Qt::SystemLocaleShortDate); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + dateTime = QDateTime::fromString(dateString, Qt::SystemLocaleLongDate); + dateTime.setTimeSpec(Qt::UTC); + } + if (!dateTime.isValid()) { + kWarning() << "Could not determine correct datetime format from:" << dateString; + return QDateTime(); + } + + return dateTime; +} + +QStringList ExtractorPlugin::contactsFromString(const QString& string) +{ + QString cleanedString = string; + cleanedString = cleanedString.remove('{'); + cleanedString = cleanedString.remove('}'); + + QStringList contactStrings = string.split(',', QString::SkipEmptyParts); + if (contactStrings.size() == 1) + contactStrings = string.split(';', QString::SkipEmptyParts); + + if (contactStrings.size() == 1) + contactStrings = string.split(" ft ", QString::SkipEmptyParts); + + if (contactStrings.size() == 1) + contactStrings = string.split(" feat. ", QString::SkipEmptyParts); + + if (contactStrings.size() == 1) + contactStrings = string.split(" feat ", QString::SkipEmptyParts); + + QStringList list; + foreach(const QString& contactName, contactStrings) { + list << contactName.trimmed(); + } + + return list; +} diff --git a/kfilemetadata/src/extractorplugin.h b/kfilemetadata/src/extractorplugin.h new file mode 100644 index 00000000..d1cddd52 --- /dev/null +++ b/kfilemetadata/src/extractorplugin.h @@ -0,0 +1,112 @@ +/* + + Copyright (C) 2012 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef _KFILEMETADATA_EXTRACTOR_H +#define _KFILEMETADATA_EXTRACTOR_H + +#include +#include + +#include "kfilemetadata_export.h" +#include "extractionresult.h" + +#include +#include + +namespace KFileMetaData +{ + +/** + * \class ExtractorPlugin extractorplugin.h + * + * \brief The ExtractorPlugin is the base class for all file metadata + * extractors. It is responsible for extracting the metadata in a file. + * + * Plugins should derive from this class and implement the mimetypes + * and extract method. + * + * All Plugins should be synchronous and blocking. + * + * \author Vishesh Handa + */ +class KFILEMETADATA_EXPORT ExtractorPlugin : public QObject +{ + Q_OBJECT +public: + ExtractorPlugin(QObject* parent); + virtual ~ExtractorPlugin(); + + /** + * Provide a list of mimetypes which are supported by this plugin. + * Only files with those mimetypes will be provided to the plugin via + * the extract function. + * + * This can also contains partial mimetypes like "text/", in that case + * this plugin will be chosen only if a better plugin does not exist. + * + * \return A StringList containing the mimetypes. + * \sa extract + */ + virtual QStringList mimetypes() const = 0; + + /** + * The main function of the plugin that is responsible for extracting + * the data and filling up the ExtractionResult + * + * The \p result provides the input url and mimetype which + * can be used to identify the file. + * + * This function is synchronous and should be reentrant as it + * can be called by multiple threads. + */ + virtual void extract(ExtractionResult* result) = 0; + + // + // Helper functions + // + + /** + * Tries to extract a valid date time from the string provided. + */ + static QDateTime dateTimeFromString(const QString& dateString); + + /** + * Tries to split the string into names. It cleans up any superflous words + * and removes extra junk such as curly braces + */ + static QStringList contactsFromString(const QString& string); + +private: + class Private; + Private* d; +}; +} + +/** + * Export a file extractor. + * + * \param classname The name of the subclass to export + * \param libname The name of the library which should export the extractor + */ +#define KFILEMETADATA_EXPORT_EXTRACTOR( classname, libname ) \ + K_PLUGIN_FACTORY(factory, registerPlugin();) \ + K_EXPORT_PLUGIN(factory(#libname)) + +#endif // _KFILEMETADATA_EXTRACTOR_H diff --git a/kfilemetadata/src/extractorpluginmanager.cpp b/kfilemetadata/src/extractorpluginmanager.cpp new file mode 100644 index 00000000..27859654 --- /dev/null +++ b/kfilemetadata/src/extractorpluginmanager.cpp @@ -0,0 +1,94 @@ +/* + * + * Copyright (C) 2012 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "extractorplugin.h" +#include "extractorpluginmanager.h" + +#include +#include +#include +#include + +using namespace KFileMetaData; + +class ExtractorPluginManager::Private { +public: + QHash m_extractors; + + QList allExtractors() const; +}; + +ExtractorPluginManager::ExtractorPluginManager(QObject* parent) + : QObject(parent) + , d(new Private) +{ + QList all = d->allExtractors(); + + foreach (ExtractorPlugin* ex, all) { + foreach (const QString& type, ex->mimetypes()) { + d->m_extractors.insertMulti(type, ex); + } + } +} + +ExtractorPluginManager::~ExtractorPluginManager() +{ + qDeleteAll(d->m_extractors.values().toSet()); + delete d; +} + + +QList ExtractorPluginManager::Private::allExtractors() const +{ + // Get all the plugins + KService::List plugins = KServiceTypeTrader::self()->query("KFileMetaDataExtractor"); + + QList extractors; + KService::List::const_iterator it; + for (it = plugins.constBegin(); it != plugins.constEnd(); it++) { + KService::Ptr service = *it; + + QString error; + ExtractorPlugin* ex = service->createInstance(0, QVariantList(), &error); + if (!ex) { + kError() << "Could not create Extractor: " << service->library(); + kError() << error; + continue; + } + + extractors << ex; + } + + return extractors; +} + +QList ExtractorPluginManager::fetchExtractors(const QString& mimetype) const +{ + QList plugins = d->m_extractors.values(mimetype); + if (plugins.isEmpty()) { + QHash::const_iterator it = d->m_extractors.constBegin(); + for (; it != d->m_extractors.constEnd(); it++) { + if (mimetype.startsWith(it.key())) + plugins << it.value(); + } + } + + return plugins; +} diff --git a/kfilemetadata/src/extractorpluginmanager.h b/kfilemetadata/src/extractorpluginmanager.h new file mode 100644 index 00000000..d4a871e7 --- /dev/null +++ b/kfilemetadata/src/extractorpluginmanager.h @@ -0,0 +1,65 @@ +/* + * + * Copyright (C) 2012 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _KFILEMETADATA_EXTRACTORPLUGINMANAGER_H +#define _KFILEMETADATA_EXTRACTORPLUGINMANAGER_H + +#include +#include "kfilemetadata_export.h" + +namespace KFileMetaData +{ + +class ExtractorPlugin; + +/** + * \class ExtractorPluginManager extractorpluginmanager.h + * + * \brief The ExtractorPluginManager is a helper class which internally + * loads all the extractor plugins. It can be used to fetch a certain + * subset of thse pulgins based on a given mimetype. + * + * Once the appropriate plugins have been fetched, an ExtractionResult + * should be created and passed to the plugin's extract function. + * + * \author Vishesh Handa + */ +class KFILEMETADATA_EXPORT ExtractorPluginManager : public QObject +{ +public: + explicit ExtractorPluginManager(QObject* parent = 0); + virtual ~ExtractorPluginManager(); + + /** + * Fetch the extractors which can be used to extract + * data for the respective file with the given mimetype. + * + * If no match is found then all the plugins whose mimetype list + * starts with \p mimetype are returned. + */ + QList fetchExtractors(const QString& mimetype) const; + +private: + class Private; + Private* d; +}; +} + +#endif // _KFILEMETADATA_EXTRACTORPLUGINMANAGER_H diff --git a/kfilemetadata/src/extractors/CMakeLists.txt b/kfilemetadata/src/extractors/CMakeLists.txt new file mode 100644 index 00000000..ca274046 --- /dev/null +++ b/kfilemetadata/src/extractors/CMakeLists.txt @@ -0,0 +1,207 @@ +if(POPPLER_QT4_FOUND) + include_directories(${POPPLER_QT4_INCLUDE_DIR}) + + kde4_add_plugin(kfilemetadata_popplerextractor popplerextractor.cpp) + + target_link_libraries(kfilemetadata_popplerextractor + kfilemetadata + ${KDE4_KIO_LIBS} + ${POPPLER_QT4_LIBRARIES} + ) + + install( + FILES kfilemetadata_popplerextractor.desktop + DESTINATION ${KDE4_SERVICES_INSTALL_DIR}) + + install( + TARGETS kfilemetadata_popplerextractor + DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) + +endif(POPPLER_QT4_FOUND) + +if(TAGLIB_FOUND) + include_directories( ${TAGLIB_INCLUDES} ) + + kde4_add_plugin( kfilemetadata_taglibextractor taglibextractor.cpp ) + + target_link_libraries( kfilemetadata_taglibextractor + kfilemetadata + ${KDE4_KIO_LIBS} + ${TAGLIB_LIBRARIES} + ) + + install( + FILES kfilemetadata_taglibextractor.desktop + DESTINATION ${KDE4_SERVICES_INSTALL_DIR}) + + install( + TARGETS kfilemetadata_taglibextractor + DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) + +endif(TAGLIB_FOUND) + +if(EXIV2_FOUND) + include_directories( ${EXIV2_INCLUDE_DIR} ) + + set_source_files_properties( exiv2extractor.cpp PROPERTIES + COMPILE_FLAGS "${KDE4_ENABLE_EXCEPTIONS}" + ) + + kde4_add_plugin(kfilemetadata_exiv2extractor exiv2extractor.cpp) + + target_link_libraries(kfilemetadata_exiv2extractor + kfilemetadata + ${KDE4_KIO_LIBS} + ${EXIV2_LIBRARIES} + ) + + install( + FILES kfilemetadata_exiv2extractor.desktop + DESTINATION ${KDE4_SERVICES_INSTALL_DIR}) + + install( + TARGETS kfilemetadata_exiv2extractor + DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) + +endif(EXIV2_FOUND) + +if(FFMPEG_FOUND) + include_directories( ${FFMPEG_INCLUDE_DIRS} ) + + kde4_add_plugin(kfilemetadata_ffmpegextractor ffmpegextractor.cpp) + + target_link_libraries(kfilemetadata_ffmpegextractor + kfilemetadata + ${KDE4_KIO_LIBS} + ${FFMPEG_LIBRARIES} + ${AVUTIL_LIBRARIES} + ) + + install( + FILES kfilemetadata_ffmpegextractor.desktop + DESTINATION ${KDE4_SERVICES_INSTALL_DIR}) + + install( + TARGETS kfilemetadata_ffmpegextractor + DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) + +endif(FFMPEG_FOUND) + + +if(EPUB_FOUND) + include_directories( ${EPUB_INCLUDE_DIR} ) + + kde4_add_plugin(kfilemetadata_epubextractor epubextractor.cpp) + + target_link_libraries(kfilemetadata_epubextractor + kfilemetadata + ${KDE4_KIO_LIBS} + ${EPUB_LIBRARIES} + ) + + install( + FILES kfilemetadata_epubextractor.desktop + DESTINATION ${KDE4_SERVICES_INSTALL_DIR}) + + install( + TARGETS kfilemetadata_epubextractor + DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) + +endif(EPUB_FOUND) + +# +# Plain Text +# +kde4_add_plugin( kfilemetadata_plaintextextractor plaintextextractor.cpp ) + +target_link_libraries( kfilemetadata_plaintextextractor + kfilemetadata + ${KDE4_KIO_LIBS} +) + +install( +FILES kfilemetadata_plaintextextractor.desktop +DESTINATION ${KDE4_SERVICES_INSTALL_DIR}) + +install( +TARGETS kfilemetadata_plaintextextractor +DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) + +# +# ODF +# + +kde4_add_plugin(kfilemetadata_odfextractor odfextractor.cpp) + +target_link_libraries(kfilemetadata_odfextractor + kfilemetadata + ${KDE4_KIO_LIBS} +) + +install( +FILES kfilemetadata_odfextractor.desktop +DESTINATION ${KDE4_SERVICES_INSTALL_DIR}) + +install( +TARGETS kfilemetadata_odfextractor +DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) + +# +# Office 2007 +# + +kde4_add_plugin(kfilemetadata_office2007extractor office2007extractor.cpp) + +target_link_libraries(kfilemetadata_office2007extractor + kfilemetadata + ${KDE4_KIO_LIBS} +) + +install( +FILES kfilemetadata_office2007extractor.desktop +DESTINATION ${KDE4_SERVICES_INSTALL_DIR}) + +install( +TARGETS kfilemetadata_office2007extractor +DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) + +# +# Office (binary formats) +# + +kde4_add_plugin(kfilemetadata_officeextractor officeextractor.cpp) + +target_link_libraries(kfilemetadata_officeextractor + kfilemetadata + ${KDE4_KIO_LIBS} +) + +install( +FILES kfilemetadata_officeextractor.desktop +DESTINATION ${KDE4_SERVICES_INSTALL_DIR}) + +install( +TARGETS kfilemetadata_officeextractor +DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) + +# +# Mobipocket +# +if (QMOBIPOCKET_FOUND) + kde4_add_plugin(kfilemetadata_mobiextractor mobiextractor.cpp) + + include_directories(${QMOBIPOCKET_INCLUDE_DIR}) + target_link_libraries(kfilemetadata_mobiextractor + kfilemetadata + ${KDE4_KIO_LIBS} + ${QMOBIPOCKET_LIBRARIES} + ) + + install( + FILES kfilemetadata_mobiextractor.desktop + DESTINATION ${KDE4_SERVICES_INSTALL_DIR}) + + install( + TARGETS kfilemetadata_mobiextractor + DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) +endif(QMOBIPOCKET_FOUND) diff --git a/kfilemetadata/src/extractors/epubextractor.cpp b/kfilemetadata/src/extractors/epubextractor.cpp new file mode 100644 index 00000000..0f83cfdb --- /dev/null +++ b/kfilemetadata/src/extractors/epubextractor.cpp @@ -0,0 +1,184 @@ +/* + Copyright (C) 2013 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "epubextractor.h" + +#include + +#include +#include +#include + +using namespace KFileMetaData; + +EPubExtractor::EPubExtractor(QObject* parent, const QVariantList&) + : ExtractorPlugin(parent) +{ + +} + +QStringList EPubExtractor::mimetypes() const +{ + QStringList types; + types << QLatin1String("application/epub+zip"); + + return types; +} + +namespace +{ +QString fetchMetadata(struct epub* e, const epub_metadata& type) +{ + int size = 0; + + unsigned char** data = epub_get_metadata(e, type, &size); + if (data) { + QStringList strList; + for (int i = 0; i < size; i++) { + strList << QString::fromUtf8((char*)data[i]); + free(data[i]); + } + free(data); + + return strList.join(";"); + } + return QString(); +} +} + + +void EPubExtractor::extract(ExtractionResult* result) +{ + struct epub* ePubDoc = epub_open(result->inputUrl().toUtf8().constData(), 1); + if (!ePubDoc) { + kError() << "Invalid document"; + return; + } + + result->addType(Type::Document); + + QString value = fetchMetadata(ePubDoc, EPUB_TITLE); + if (!value.isEmpty()) { + result->add(Property::Title, value); + } + + value = fetchMetadata(ePubDoc, EPUB_SUBJECT); + if (!value.isEmpty()) { + result->add(Property::Subject, value); + } + + value = fetchMetadata(ePubDoc, EPUB_CREATOR); + if (!value.isEmpty()) { + if (value.startsWith(QLatin1String("aut:"), Qt::CaseInsensitive)) { + value = value.mid(4).simplified(); + } else if (value.startsWith(QLatin1String("author:"), Qt::CaseInsensitive)) { + value = value.mid(7).simplified(); + } + + // A lot of authors have their name written in () again. We discard that part + int index = value.indexOf('('); + if (index) + value = value.mid(0, index); + + result->add(Property::Creator, value); + } + + // The Contributor just seems to be mostly Calibre aka the Generator + /* + value = fetchMetadata(ePubDoc, EPUB_CONTRIB); + if( !value.isEmpty() ) { + SimpleResource con; + con.addType( NCO::Contact() ); + con.addProperty( NCO::fullname(), value ); + + fileRes.addProperty( NCO::contributor(), con ); + graph << con; + }*/ + + value = fetchMetadata(ePubDoc, EPUB_PUBLISHER); + if (!value.isEmpty()) { + result->add(Property::Publisher, value); + } + + value = fetchMetadata(ePubDoc, EPUB_DESCRIPTION); + if (!value.isEmpty()) { + result->add(Property::Description, value); + } + + value = fetchMetadata(ePubDoc, EPUB_DATE); + if (!value.isEmpty()) { + if (value.startsWith("Unspecified:", Qt::CaseInsensitive)) { + value = value.mid(QString("Unspecified:").size()).simplified(); + } + int ind = value.indexOf("publication:", Qt::CaseInsensitive); + if (ind != -1) { + value = value.mid(ind + QString("publication:").size()).simplified(); + } + QDateTime dt = ExtractorPlugin::dateTimeFromString(value); + if (!dt.isNull()) + result->add(Property::CreationDate, value); + } + + // + // Plain Text + // + struct eiterator* iter = epub_get_iterator(ePubDoc, EITERATOR_SPINE, 0); + do { + char* curr = epub_it_get_curr(iter); + if (!curr) + continue; + QString html = QString::fromUtf8(curr); + + QTextDocument doc; + doc.setHtml(html); + result->append(doc.toPlainText()); + } while (epub_it_get_next(iter)); + + epub_free_iterator(iter); + + struct titerator* tit; + + tit = epub_get_titerator(ePubDoc, TITERATOR_NAVMAP, 0); + if (!tit) { + tit = epub_get_titerator(ePubDoc, TITERATOR_GUIDE, 0); + } + + if (epub_tit_curr_valid(tit)) { + do { + char* clink = epub_tit_get_curr_link(tit); + + char* data; + int size = epub_get_data(ePubDoc, clink, &data); + free(clink); + + // epub_get_data returns -1 on failure + if (size > 0 && data) { + QString html = QString::fromUtf8(data, size); + + QTextDocument doc; + doc.setHtml(html); + result->append(doc.toPlainText()); + free(data); + } + } while (epub_tit_next(tit)); + } + epub_free_titerator(tit); +} + +KFILEMETADATA_EXPORT_EXTRACTOR(KFileMetaData::EPubExtractor, "kfilemetadata_epubextractor") diff --git a/kfilemetadata/src/extractors/epubextractor.h b/kfilemetadata/src/extractors/epubextractor.h new file mode 100644 index 00000000..486a0496 --- /dev/null +++ b/kfilemetadata/src/extractors/epubextractor.h @@ -0,0 +1,39 @@ +/* + + Copyright (C) 2013 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef EPUBEXTRACTOR_H +#define EPUBEXTRACTOR_H + +#include "extractorplugin.h" + +namespace KFileMetaData +{ + +class EPubExtractor : public ExtractorPlugin +{ +public: + EPubExtractor(QObject* parent, const QVariantList&); + + virtual void extract(ExtractionResult* result); + virtual QStringList mimetypes() const; +}; +} + +#endif // EPUBEXTRACTOR_H diff --git a/kfilemetadata/src/extractors/exiv2extractor.cpp b/kfilemetadata/src/extractors/exiv2extractor.cpp new file mode 100644 index 00000000..49b39fb6 --- /dev/null +++ b/kfilemetadata/src/extractors/exiv2extractor.cpp @@ -0,0 +1,209 @@ +/* + + Copyright (C) 2012 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "exiv2extractor.h" + +#include + +using namespace KFileMetaData; + + +Exiv2Extractor::Exiv2Extractor(QObject* parent, const QVariantList&) + : ExtractorPlugin(parent) +{ + +} + +QStringList Exiv2Extractor::mimetypes() const +{ + QStringList types; + + types << QLatin1String("image/jp2") + << QLatin1String("image/jpeg") + << QLatin1String("image/pgf") + << QLatin1String("image/png") + << QLatin1String("image/tiff") + << QLatin1String("image/x-exv") + << QLatin1String("image/x-canon-cr2") + << QLatin1String("image/x-canon-crw") + << QLatin1String("image/x-fuji-raf") + << QLatin1String("image/x-minolta-mrw") + << QLatin1String("image/x-nikon-nef") + << QLatin1String("image/x-olympus-orf") + << QLatin1String("image/x-panasonic-rw2") + << QLatin1String("image/x-pentax-pef") + << QLatin1String("image/x-photoshop") + << QLatin1String("image/x-samsung-srw"); + + return types; +} + +namespace +{ +QString toString(const Exiv2::Value& value) +{ + std::string str = value.toString(); + return QString::fromUtf8(str.c_str(), str.length()); +} + +QVariant toVariantDateTime(const Exiv2::Value& value) +{ + if (value.typeId() == Exiv2::asciiString) { + QDateTime val = ExtractorPlugin::dateTimeFromString(value.toString().c_str()); + if (val.isValid()) { + // Datetime is stored in exif as local time. + val.setUtcOffset(0); + return QVariant(val); + } + } + + return QVariant(); +} + +QVariant toVariantLong(const Exiv2::Value& value) +{ + if (value.typeId() == Exiv2::unsignedLong || value.typeId() == Exiv2::signedLong) { + qlonglong val = value.toLong(); + return QVariant(val); + } + + QString str(toString(value)); + bool ok = false; + int val = str.toInt(&ok); + if (ok) + return QVariant(val); + + return QVariant(); +} + +QVariant toVariantDouble(const Exiv2::Value& value) +{ + if (value.typeId() == Exiv2::tiffFloat || value.typeId() == Exiv2::tiffDouble + || value.typeId() == Exiv2::unsignedRational || value.typeId() == Exiv2::signedRational) { + return QVariant(static_cast(value.toFloat())); + } + + QString str(toString(value)); + bool ok = false; + double val = str.toDouble(&ok); + if (ok) + return QVariant(val); + + return QVariant(); +} + +QVariant toVariantString(const Exiv2::Value& value) +{ + QString str = toString(value); + if (!str.isEmpty()) + return QVariant(str); + + return QVariant(); +} + +QVariant toVariant(const Exiv2::Value& value, QVariant::Type type) { + switch (type) { + case QVariant::Int: + return toVariantLong(value); + + case QVariant::DateTime: + return toVariantDateTime(value); + + case QVariant::Double: + return toVariantDouble(value); + + case QVariant::String: + default: + return toVariantString(value); + } +} +} + +void Exiv2Extractor::extract(ExtractionResult* result) +{ + QByteArray arr = result->inputUrl().toUtf8(); + std::string fileString(arr.data(), arr.length()); + + Exiv2::Image::AutoPtr image; + try { + image = Exiv2::ImageFactory::open(fileString); + } catch (const std::exception&) { + return; + } + if (!image.get()) { + return; + } + + try { + image->readMetadata(); + } catch (const std::exception&) { + return; + } + result->addType(Type::Image); + + if (image->pixelHeight()) { + result->add(Property::Height, image->pixelHeight()); + } + + if (image->pixelWidth()) { + result->add(Property::Width, image->pixelWidth()); + } + + std::string comment = image->comment(); + if (!comment.empty()) { + result->add(Property::Comment, QString::fromUtf8(comment.c_str(), comment.length())); + } + + const Exiv2::ExifData& data = image->exifData(); + + add(result, data, Property::ImageMake, "Exif.Image.Make", QVariant::String); + add(result, data, Property::ImageModel, "Exif.Image.Model", QVariant::String); + add(result, data, Property::ImageDateTime, "Exif.Image.DateTime", QVariant::DateTime); + add(result, data, Property::ImageOrientation, "Exif.Image.Orientation", QVariant::Int); + add(result, data, Property::PhotoFlash, "Exif.Photo.Flash", QVariant::Int); + add(result, data, Property::PhotoPixelXDimension, "Exif.Photo.PixelXDimension", QVariant::Int); + add(result, data, Property::PhotoPixelYDimension, "Exif.Photo.PixelYDimension", QVariant::Int); + add(result, data, Property::PhotoDateTimeOriginal, "Exif.Photo.DateTimeOriginal", QVariant::DateTime); + add(result, data, Property::PhotoFocalLength, "Exif.Photo.FocalLength", QVariant::Double); + add(result, data, Property::PhotoFocalLengthIn35mmFilm, "Exif.Photo.FocalLengthIn35mmFilm", QVariant::Double); + add(result, data, Property::PhotoExposureTime, "Exif.Photo.ExposureTime", QVariant::Double); + add(result, data, Property::PhotoExposureBiasValue, "Exif.Photo.ExposureBiasValue", QVariant::Double); + add(result, data, Property::PhotoFNumber, "Exif.Photo.FNumber", QVariant::Double); + add(result, data, Property::PhotoApertureValue, "Exif.Photo.ApertureValue", QVariant::Double); + add(result, data, Property::PhotoWhiteBalance, "Exif.Photo.WhiteBalance", QVariant::Int); + add(result, data, Property::PhotoMeteringMode, "Exif.Photo.MeteringMode", QVariant::Int); + add(result, data, Property::PhotoISOSpeedRatings, "Exif.Photo.ISOSpeedRatings", QVariant::Int); + add(result, data, Property::PhotoSaturation, "Exif.Photo.Saturation", QVariant::Int); + add(result, data, Property::PhotoSharpness, "Exif.Photo.Sharpness", QVariant::Int); +} + +void Exiv2Extractor::add(ExtractionResult* result, const Exiv2::ExifData& data, + Property::Property prop, const char* name, + QVariant::Type type) +{ + Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(name)); + if (it != data.end()) { + QVariant value = toVariant(it->value(), type); + if (!value.isNull()) + result->add(prop, value); + } +} + +KFILEMETADATA_EXPORT_EXTRACTOR(KFileMetaData::Exiv2Extractor, "kmetaddata_exivextractor") diff --git a/kfilemetadata/src/extractors/exiv2extractor.h b/kfilemetadata/src/extractors/exiv2extractor.h new file mode 100644 index 00000000..9c2480b9 --- /dev/null +++ b/kfilemetadata/src/extractors/exiv2extractor.h @@ -0,0 +1,45 @@ +/* + + Copyright (C) 2012 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef EXIV2EXTRACTOR_H +#define EXIV2EXTRACTOR_H + +#include "extractorplugin.h" +#include + +namespace KFileMetaData +{ + +class Exiv2Extractor : public ExtractorPlugin +{ +public: + Exiv2Extractor(QObject* parent, const QVariantList&); + + virtual void extract(ExtractionResult* result); + virtual QStringList mimetypes() const; + +private: + void add(ExtractionResult* result, const Exiv2::ExifData& data, + Property::Property prop, + const char* name, QVariant::Type type); +}; +} + +#endif // EXIV2EXTRACTOR_H diff --git a/kfilemetadata/src/extractors/ffmpegextractor.cpp b/kfilemetadata/src/extractors/ffmpegextractor.cpp new file mode 100644 index 00000000..c835bcdd --- /dev/null +++ b/kfilemetadata/src/extractors/ffmpegextractor.cpp @@ -0,0 +1,182 @@ +/* + + Copyright (C) 2012 Vishesh Handa + + Code adapted from Strigi FFmpeg Analyzer - + Copyright (C) 2010 Evgeny Egorochkin + Copyright (C) 2011 Tirtha Chatterjee + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "ffmpegextractor.h" + +#ifdef __cplusplus +#define __STDC_CONSTANT_MACROS +#ifdef _STDINT_H +#undef _STDINT_H +#endif +# include +#endif + +extern "C" { +#include +#include +#include +} + +#include +#include + +using namespace KFileMetaData; + +FFmpegExtractor::FFmpegExtractor(QObject* parent, const QVariantList&) +: ExtractorPlugin(parent) +{ +} + +QStringList FFmpegExtractor::mimetypes() const +{ + QStringList types; + + types << QLatin1String("video/x-ms-asf"); + types << QLatin1String("video/x-msvideo"); + types << QLatin1String("video/x-flv"); + types << QLatin1String("video/quicktime"); + types << QLatin1String("video/mpeg"); + types << QLatin1String("video/x-ms-wmv"); + types << QLatin1String("video/mp4"); + types << QLatin1String("video/x-matroska"); + types << QLatin1String("video/webm"); + + return types; +} + +void FFmpegExtractor::extract(ExtractionResult* result) +{ + AVFormatContext* fmt_ctx = NULL; + + av_register_all(); + + QByteArray arr = result->inputUrl().toUtf8(); + + fmt_ctx = avformat_alloc_context(); + if (int ret = avformat_open_input(&fmt_ctx, arr.data(), NULL, NULL)) { + kError() << "avformat_open_input error: " << ret; + return; + } + + int ret = avformat_find_stream_info(fmt_ctx, NULL); + if (ret < 0) { + kError() << "avform_find_stream_info error: " << ret; + return; + } + + result->addType(Type::Video); + + int totalSecs = fmt_ctx->duration / AV_TIME_BASE; + int bitrate = fmt_ctx->bit_rate; + + result->add(Property::Duration, totalSecs); + result->add(Property::BitRate, bitrate); + + for (uint i = 0; i < fmt_ctx->nb_streams; i++) { + const AVStream* stream = fmt_ctx->streams[i]; + const AVCodecContext* codec = stream->codec; + + if (codec->codec_type == AVMEDIA_TYPE_AUDIO || codec->codec_type == AVMEDIA_TYPE_VIDEO) { + /* + if( codec->codec_type == AVMEDIA_TYPE_AUDIO ) { + subRes.addType( NFO::Audio() ); + subRes.addProperty( NFO::sampleRate(), codec->sample_rate ); + subRes.addProperty( NFO::channels(), codec->channels ); + + //TODO: Fetch Sample Format + }*/ + + if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { + int aspectRatio = codec->sample_aspect_ratio.num; + int frameRate = stream->avg_frame_rate.num; + + if (codec->sample_aspect_ratio.den) + aspectRatio /= codec->sample_aspect_ratio.den; + if (stream->avg_frame_rate.den) + frameRate /= stream->avg_frame_rate.den; + + result->add(Property::Width, codec->width); + result->add(Property::Height, codec->height); + if (aspectRatio) + result->add(Property::AspectRatio, aspectRatio); + if (frameRate) + result->add(Property::FrameRate, frameRate); + } + } + } + + AVDictionary* dict = fmt_ctx->metadata; + AVDictionaryEntry* entry; + + entry = av_dict_get(dict, "title", NULL, 0); + if (entry) { + result->add(Property::Title, QString::fromUtf8(entry->value)); + } + + + entry = av_dict_get(dict, "author", NULL, 0); + if (entry) { + result->add(Property::Author, QString::fromUtf8(entry->value)); + } + + entry = av_dict_get(dict, "copyright", NULL, 0); + if (entry) { + result->add(Property::Copyright, QString::fromUtf8(entry->value)); + } + + entry = av_dict_get(dict, "comment", NULL, 0); + if (entry) { + result->add(Property::Comment, QString::fromUtf8(entry->value)); + } + + entry = av_dict_get(dict, "album", NULL, 0); + if (entry) { + result->add(Property::Album, QString::fromUtf8(entry->value)); + } + + entry = av_dict_get(dict, "genre", NULL, 0); + if (entry) { + result->add(Property::Genre, QString::fromUtf8(entry->value)); + } + + entry = av_dict_get(dict, "track", NULL, 0); + if (entry) { + QString value = QString::fromUtf8(entry->value); + + bool ok = false; + int track = value.toInt(&ok); + if (ok && track) + result->add(Property::TrackNumber, track); + } + + entry = av_dict_get(dict, "year", NULL, 0); + if (entry) { + int year = QString::fromUtf8(entry->value).toInt(); + result->add(Property::ReleaseYear, year); + } + + avformat_close_input(&fmt_ctx); +} + +KFILEMETADATA_EXPORT_EXTRACTOR(KFileMetaData::FFmpegExtractor, "kfilemetadata_ffmpegextractor") diff --git a/kfilemetadata/src/extractors/ffmpegextractor.h b/kfilemetadata/src/extractors/ffmpegextractor.h new file mode 100644 index 00000000..5165c801 --- /dev/null +++ b/kfilemetadata/src/extractors/ffmpegextractor.h @@ -0,0 +1,39 @@ +/* + + Copyright (C) 2012 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FFMPEGEXTRACTOR_H +#define FFMPEGEXTRACTOR_H + +#include "extractorplugin.h" + +namespace KFileMetaData +{ + +class FFmpegExtractor : public ExtractorPlugin +{ +public: + FFmpegExtractor(QObject* parent, const QVariantList&); + + virtual void extract(ExtractionResult* result); + virtual QStringList mimetypes() const; +}; +} + +#endif // FFMPEGEXTRACTOR_H diff --git a/kfilemetadata/src/extractors/kfilemetadata_epubextractor.desktop b/kfilemetadata/src/extractors/kfilemetadata_epubextractor.desktop new file mode 100644 index 00000000..544e8140 --- /dev/null +++ b/kfilemetadata/src/extractors/kfilemetadata_epubextractor.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KFileMetaDataExtractor +X-KDE-Library=kfilemetadata_epubextractor +Name=KFileMetaData EPub Extractor +Name[bs]=KFileMetaData EPub ekstraktor +Name[ca]=Extractor EPub del KFileMetaData +Name[ca@valencia]=Extractor EPub del KFileMetaData +Name[cs]=Extraktor EPub KFileMetaData +Name[da]=KFileMetaData EPub-udtrækker +Name[de]=EPub-Extraktion für KFileMetaData +Name[el]=Εξαγωγέας EPub KFileMetaData +Name[en_GB]=KFileMetaData EPub Extractor +Name[es]=Extractor de EPub para KFileMetaData +Name[et]=KFileMetaData EPubi ekstraktimine +Name[fi]=KFileMetaDatan EPub-lukuohjelma +Name[fr]=Extracteur EPub de KFileMetaData +Name[gl]=Extractor de EPub de KFileMetaData +Name[hu]=KFileMetaData EPub kibontó +Name[ia]=KFileMetadata Extractor de EPub +Name[it]=Estrattore EPub di KFileMetaData +Name[ko]=KFileMetaData EPub 추출기 +Name[lt]=KFileMetaData EPub ekstraktorius +Name[nb]=KFileMetaData EPub-uttrekker +Name[nds]=KFile-Metadaten-EPub-Leser +Name[nl]=Extractieprogramma voor KFileMetaData EPub +Name[pl]=Wydobywanie z EPub dla KFileMetaData +Name[pt]=Extracção de EPub do KFileMetaData +Name[pt_BR]=Extrator de EPub do KFileMetaData +Name[ru]=Модуль извлечения метаданных из файлов EPub +Name[sk]=Extraktor KFileMetaData EPub +Name[sl]=Program za izvleko EPub za KFileMetaData +Name[sr]=Издвајач ЕПУБ‑а (KFileMetaData) +Name[sr@ijekavian]=Издвајач ЕПУБ‑а (KFileMetaData) +Name[sr@ijekavianlatin]=Izdvajač EPUB‑a (KFileMetaData) +Name[sr@latin]=Izdvajač EPUB‑a (KFileMetaData) +Name[sv]=Kfilmetadata EPub-extrahering +Name[tr]=KFileMetaData EPub Çıkarıcı +Name[uk]=Засіб видобування метаданих EPub +Name[x-test]=xxKFileMetaData EPub Extractorxx +Name[zh_CN]=KFileMetaData EPub 提取工具 +Name[zh_TW]=KFileMetaData EPub 展開器 diff --git a/kfilemetadata/src/extractors/kfilemetadata_exiv2extractor.desktop b/kfilemetadata/src/extractors/kfilemetadata_exiv2extractor.desktop new file mode 100644 index 00000000..0ac14574 --- /dev/null +++ b/kfilemetadata/src/extractors/kfilemetadata_exiv2extractor.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KFileMetaDataExtractor +X-KDE-Library=kfilemetadata_exiv2extractor +Name=KFileMetaData Exiv2 Extractor +Name[bs]=KFileMetaData Exiv2 ekstraktor +Name[ca]=Extractor Exiv2 del KFileMetaData +Name[ca@valencia]=Extractor Exiv2 del KFileMetaData +Name[cs]=Extraktor Exiv2 KFileMetaData +Name[da]=KFileMetaData Exiv2-udtrækker +Name[de]=Exiv2-Extraktion für KFileMetaData +Name[el]=Εξαγωγέας Exiv2 KFileMetaData +Name[en_GB]=KFileMetaData Exiv2 Extractor +Name[es]=Extractor de Exiv2 para KFileMetaData +Name[et]=KFileMetaData Exiv2 ekstraktimine +Name[fi]=KFileMetaDatan Exiv2-lukuohjelma +Name[fr]=Extracteur Exiv2 de KFileMetaData +Name[gl]=Extractor de Exiv2 de KFileMetaData +Name[hu]=KFileMetaData Exiv2 kibontó +Name[ia]=Extractor de KFileMetaData Exiv2 +Name[it]=Estrattore Exiv2 di KFileMetaData +Name[ko]=KFileMetaData Exiv2 추출기 +Name[lt]=KFileMetaData Exiv2 ekstraktorius +Name[nb]=KFileMetaData Eviv2-uttrekker +Name[nds]=KFile-Metadaten-Exiv2-Leser +Name[nl]=Extractieprogramma voor KFileMetaData Exiv2 +Name[pl]=Wydobywanie z Exiv2 dla KFileMetaData +Name[pt]=Extracção de Exiv2 do KFileMetaData +Name[pt_BR]=Extrator de Exiv2 do KFileMetaData +Name[ru]=Модуль извлечения метаданных изображений с помощью Exiv2 +Name[sk]=Extraktor KFileMetaData Exiv2 +Name[sl]=Program za izvleko Exiv2 za KFileMetaData +Name[sr]=Издвајач Ексивом 2 (KFileMetaData) +Name[sr@ijekavian]=Издвајач Ексивом 2 (KFileMetaData) +Name[sr@ijekavianlatin]=Izdvajač Exivom 2 (KFileMetaData) +Name[sr@latin]=Izdvajač Exivom 2 (KFileMetaData) +Name[sv]=Kfilmetadata Exiv2-extrahering +Name[tr]=KFileMetaData Exiv2 Çıkarıcı +Name[uk]=Засіб видобування метаданих Exiv2 +Name[x-test]=xxKFileMetaData Exiv2 Extractorxx +Name[zh_CN]=KFileMetaData Exiv2 提取工具 +Name[zh_TW]=KFileMetaData Exiv2 展開器 diff --git a/kfilemetadata/src/extractors/kfilemetadata_ffmpegextractor.desktop b/kfilemetadata/src/extractors/kfilemetadata_ffmpegextractor.desktop new file mode 100644 index 00000000..296f0f00 --- /dev/null +++ b/kfilemetadata/src/extractors/kfilemetadata_ffmpegextractor.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KFileMetaDataExtractor +X-KDE-Library=kfilemetadata_ffmpegextractor +Name=KFileMetaData FFmpeg Extractor +Name[bs]=KFileMetaData FFmpeg ekstraktor +Name[ca]=Extractor FFmpeg del KFileMetaData +Name[ca@valencia]=Extractor FFmpeg del KFileMetaData +Name[cs]=Extraktor FFmpeg KFileMetaData +Name[da]=KFileMetaData FFmpeg-udtrækker +Name[de]=FFmpeg-Extraktion für KFileMetaData +Name[el]=Εξαγωγέας FFmpeg KFileMetaData +Name[en_GB]=KFileMetaData FFmpeg Extractor +Name[es]=Extractor de FFmpeg para KFileMetaData +Name[et]=KFileMetaData FFmpegi ekstraktimine +Name[fi]=KFileMetaDatan FFmpeg-lukuohjelma +Name[fr]=Extracteur FFmpeg de KFileMetaData +Name[gl]=Extractor de FFmpeg de KFileMetaData +Name[hu]=KFileMetaData FFmpeg kibontó +Name[ia]=Extractor de KFileMetaData FFmpeg +Name[it]=Estrattore FFmpeg di KFileMetaData +Name[ko]=KFileMetaData FFmpeg 추출기 +Name[lt]=KFileMetaData FFmpeg ekstraktorius +Name[nb]=KFileMetaData FFmpeg-uttrekker +Name[nds]=KFile-Metadaten-FFmpeg-Leser +Name[nl]=Extractieprogramma voor KFileMetaData FFmpeg +Name[pl]=Wydobywanie z FFmpeg dla KFileMetaData +Name[pt]=Extracção de FFmpeg do KFileMetaData +Name[pt_BR]=Extrator de FFmpeg do KFileMetaData +Name[ru]=Модуль извлечения метаданных видеофайлов с помощью FFmpeg +Name[sk]=Extraktor KFileMetaData FFmpeg +Name[sl]=Program za izvleko FFmpeg za KFileMetaData +Name[sr]=Издвајач ФФмпегом (KFileMetaData) +Name[sr@ijekavian]=Издвајач ФФмпегом (KFileMetaData) +Name[sr@ijekavianlatin]=Izdvajač FFmpegom (KFileMetaData) +Name[sr@latin]=Izdvajač FFmpegom (KFileMetaData) +Name[sv]=Kfilmetadata FFmpeg-extrahering +Name[tr]=KFileMetaData FFmpeg Çıkarıcı +Name[uk]=Засіб видобування метаданих FFmpeg +Name[x-test]=xxKFileMetaData FFmpeg Extractorxx +Name[zh_CN]=KFileMetaData FFmpeg 提取工具 +Name[zh_TW]=KFileMetaData FFmpeg 展開器 diff --git a/kfilemetadata/src/extractors/kfilemetadata_mobiextractor.desktop b/kfilemetadata/src/extractors/kfilemetadata_mobiextractor.desktop new file mode 100644 index 00000000..50fb6e28 --- /dev/null +++ b/kfilemetadata/src/extractors/kfilemetadata_mobiextractor.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KFileMetaDataExtractor +X-KDE-Library=kfilemetadata_mobiextractor +Name=KFileMetaData Mobi Extractor +Name[bs]=KFileMetaData Mobi ekstraktor +Name[ca]=Extractor Mobi del KFileMetaData +Name[ca@valencia]=Extractor Mobi del KFileMetaData +Name[cs]=Extraktor Mobi KFileMetaData +Name[da]=KFileMetaData Mobi-udtrækker +Name[de]=Mobi-Extraktion für KFileMetaData +Name[el]=Εξαγωγέας Mobi KFileMetaData +Name[en_GB]=KFileMetaData Mobi Extractor +Name[es]=Extractor de Mobi para KFileMetaData +Name[et]=KFileMetaData Mobi ekstraktimine +Name[fi]=KFileMetaDatan Mobi-lukuohjelma +Name[fr]=Extracteur Mobi de KFileMetaData +Name[gl]=Extractor de Mobi de KFileMetaData +Name[hu]=KFileMetaData Mobi kibontó +Name[ia]=Extractor de KFileMetaData Mobi +Name[it]=Estrattore Mobi di KFileMetaData +Name[ko]=KFileMetaData Mobi 추출기 +Name[lt]=KFileMetaData Mobi ekstraktorius +Name[nb]=KFileMetaData Mobi-uttrekker +Name[nds]=KFile-Metadaten-Mobi-Leser +Name[nl]=Extractieprogramma voor KFileMetaData Mobi +Name[pl]=Wydobywanie z Mobi dla KFileMetaData +Name[pt]=Extracção de Mobi do KFileMetaData +Name[pt_BR]=Extrator de Mobi do KFileMetaData +Name[ru]=Модуль извлечения метаданных из файлов Mobi +Name[sk]=Extraktor KFileMetaData Mobi +Name[sl]=Program za izvleko Mobi za KFileMetaData +Name[sr]=Издвајач Мобипокета (KFileMetaData) +Name[sr@ijekavian]=Издвајач Мобипокета (KFileMetaData) +Name[sr@ijekavianlatin]=Izdvajač Mobipocketa (KFileMetaData) +Name[sr@latin]=Izdvajač Mobipocketa (KFileMetaData) +Name[sv]=Kfilmetadata Mobi-extrahering +Name[tr]=KFileMetaData Mobi Çıkarıcı +Name[uk]=Засіб видобування метаданих Mobi +Name[x-test]=xxKFileMetaData Mobi Extractorxx +Name[zh_CN]=KFileMetaData Mobi 提取工具 +Name[zh_TW]=KFileMetaData Mobi 展開器 diff --git a/kfilemetadata/src/extractors/kfilemetadata_odfextractor.desktop b/kfilemetadata/src/extractors/kfilemetadata_odfextractor.desktop new file mode 100644 index 00000000..69220f0b --- /dev/null +++ b/kfilemetadata/src/extractors/kfilemetadata_odfextractor.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KFileMetaDataExtractor +X-KDE-Library=kfilemetadata_odfextractor +Name=KFileMetaData Odf Extractor +Name[bs]=KFileMetaData Odf ekstraktor +Name[ca]=Extractor Odf del KFileMetaData +Name[ca@valencia]=Extractor Odf del KFileMetaData +Name[cs]=Extraktor Odf KFileMetaData +Name[da]=KFileMetaData Odf-udtrækker +Name[de]=ODF-Extraktion für KFileMetaData +Name[el]=Εξαγωγέας Odf KFileMetaData +Name[en_GB]=KFileMetaData ODF Extractor +Name[es]=Extractor de Odf para KFileMetaData +Name[et]=KFileMetaData Odfi ekstraktimine +Name[fi]=KFileMetaDatan Odf-lukuohjelma +Name[fr]=Extracteur Odf de KFileMetaData +Name[gl]=Extractor de Odf de KFileMetaData +Name[hu]=KFileMetaData Odf kibontó +Name[ia]=Extractor de KFileMetaData Odf +Name[it]=Estrattore Odf di KFileMetaData +Name[ko]=KFileMetaData Odf 추출기 +Name[lt]=KFileMetaData Odf ekstraktorius +Name[nb]=KFileMetaData Odf-uttrekker +Name[nds]=KFile-Metadaten-ODF-Leser +Name[nl]=Extractieprogramma voor KFileMetaData Odf +Name[pl]=Wydobywanie z Odf dla KFileMetaData +Name[pt]=Extracção de ODF do KFileMetaData +Name[pt_BR]=Extrator de ODF do KFileMetaData +Name[ru]=Модуль извлечения метаданных из файлов OpenDocument Format +Name[sk]=Extraktor KFileMetaData Odf +Name[sl]=Program za izvleko Odf za KFileMetaData +Name[sr]=Издвајач ОДФ‑а (KFileMetaData) +Name[sr@ijekavian]=Издвајач ОДФ‑а (KFileMetaData) +Name[sr@ijekavianlatin]=Izdvajač ODF‑a (KFileMetaData) +Name[sr@latin]=Izdvajač ODF‑a (KFileMetaData) +Name[sv]=Kfilmetadata ODF-extrahering +Name[tr]=KFileMetaData Odf Çıkarıcı +Name[uk]=Засіб видобування метаданих ODF +Name[x-test]=xxKFileMetaData Odf Extractorxx +Name[zh_CN]=KFileMetaData Odf 提取工具 +Name[zh_TW]=KFileMetaData Odf 展開器 diff --git a/kfilemetadata/src/extractors/kfilemetadata_office2007extractor.desktop b/kfilemetadata/src/extractors/kfilemetadata_office2007extractor.desktop new file mode 100644 index 00000000..4a41aa96 --- /dev/null +++ b/kfilemetadata/src/extractors/kfilemetadata_office2007extractor.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KFileMetaDataExtractor +X-KDE-Library=kfilemetadata_office2007extractor +Name=KFileMetaData Office2007 Extractor +Name[bs]=KFileMetaData Office2007 ekstraktor +Name[ca]=Extractor Office2007 del KFileMetaData +Name[ca@valencia]=Extractor Office2007 del KFileMetaData +Name[cs]=Extraktor Office2007 KFileMetaData +Name[da]=KFileMetaData Office2007-udtrækker +Name[de]=Office 2007-Extraktion für KFileMetaData +Name[el]=Εξαγωγέας Office2007 KFileMetaData +Name[en_GB]=KFileMetaData Office2007 Extractor +Name[es]=Extractor de Office2007 para KFileMetaData +Name[et]=KFileMetaData Office2007 ekstraktimine +Name[fi]=KFileMetaDatan Office2007-lukuohjelma +Name[fr]=Extracteur Office2007 de KFileMetaData +Name[gl]=Extractor de Office2007 de KFileMetaData +Name[hu]=KFileMetaData Office2007 kibontó +Name[ia]=Extractor de KFileMetaData Office2007 +Name[it]=Estrattore Office2007 di KFileMetaData +Name[ko]=KFileMetaData Office2007 추출기 +Name[lt]=KFileMetaData Office2007 ekstraktorius +Name[nb]=KFileMetaData Office2007-uttrekker +Name[nds]=KFile-Metadaten-Office2007-Leser +Name[nl]=Extractieprogramma voor KFileMetaData Office2007 +Name[pl]=Wydobywanie z Office2007 dla KFileMetaData +Name[pt]=Extracção de Office2007 do KFileMetaData +Name[pt_BR]=Extrator de Office 2007 do KFileMetaData +Name[ru]=Модуль извлечения метаданных из файлов Office2007 +Name[sk]=Extraktor KFileMetaData Office2007 +Name[sl]=Program za izvleko Office2007 za KFileMetaData +Name[sr]=Издвајач МС Офиса 2007 (KFileMetaData) +Name[sr@ijekavian]=Издвајач МС Офиса 2007 (KFileMetaData) +Name[sr@ijekavianlatin]=Izdvajač MS Officea 2007 (KFileMetaData) +Name[sr@latin]=Izdvajač MS Officea 2007 (KFileMetaData) +Name[sv]=Kfilmetadata Office 2007-extrahering +Name[tr]=KFileMetaData Office2007 Çıkarıcı +Name[uk]=Засіб видобування метаданих Office2007 +Name[x-test]=xxKFileMetaData Office2007 Extractorxx +Name[zh_CN]=KFileMetaData Office2007 提取工具 +Name[zh_TW]=KFileMetaData Office2007 展開器 diff --git a/kfilemetadata/src/extractors/kfilemetadata_officeextractor.desktop b/kfilemetadata/src/extractors/kfilemetadata_officeextractor.desktop new file mode 100644 index 00000000..c38843f3 --- /dev/null +++ b/kfilemetadata/src/extractors/kfilemetadata_officeextractor.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KFileMetaDataExtractor +X-KDE-Library=kfilemetadata_officeextractor +Name=KFileMetaData Office Extractor +Name[bs]=KFileMetaData Office ekstraktor +Name[ca]=Extractor Office del KFileMetaData +Name[ca@valencia]=Extractor Office del KFileMetaData +Name[cs]=Extraktor Office KFileMetaData +Name[da]=KFileMetaData Office-udtrækker +Name[de]=Office-Extraktion für KFileMetaData +Name[el]=Εξαγωγέας Office KFileMetaData +Name[en_GB]=KFileMetaData Office Extractor +Name[es]=Extractor de Office para KFileMetaData +Name[et]=KFileMetaData Office'i ekstraktimine +Name[fi]=KFileMetaDatan Office-lukuohjelma +Name[fr]=Extracteur Office de KFileMetaData +Name[gl]=Extractor de Office de KFileMetaData +Name[hu]=KFileMetaData Office kibontó +Name[ia]=Extractor de KFileMetaData Office +Name[it]=Estrattore Office di KFileMetaData +Name[ko]=KFileMetaData Office 추출기 +Name[lt]=KFileMetaData Office ekstraktorius +Name[nb]=KFileMetaData Office-uttrekker +Name[nds]=KFile-Metadaten-Office-Leser +Name[nl]=Extractieprogramma voor KFileMetaData Office +Name[pl]=Wydobywanie z Office dla KFileMetaData +Name[pt]=Extracção de Office do KFileMetaData +Name[pt_BR]=Extrator de Office do KFileMetaData +Name[ru]=Модуль извлечения метаданных из файлов Office +Name[sk]=Extraktor KFileMetaData Office +Name[sl]=Program za izvleko Office za KFileMetaData +Name[sr]=Издвајач МС Офиса (KFileMetaData) +Name[sr@ijekavian]=Издвајач МС Офиса (KFileMetaData) +Name[sr@ijekavianlatin]=Izdvajač MS Officea (KFileMetaData) +Name[sr@latin]=Izdvajač MS Officea (KFileMetaData) +Name[sv]=Kfilmetadata Office-extrahering +Name[tr]=KFileMetaData Office Çıkarıcı +Name[uk]=Засіб видобування метаданих Office +Name[x-test]=xxKFileMetaData Office Extractorxx +Name[zh_CN]=KFileMetaData Office 提取工具 +Name[zh_TW]=KFileMetaData Office 展開器 diff --git a/kfilemetadata/src/extractors/kfilemetadata_plaintextextractor.desktop b/kfilemetadata/src/extractors/kfilemetadata_plaintextextractor.desktop new file mode 100644 index 00000000..35e6abd2 --- /dev/null +++ b/kfilemetadata/src/extractors/kfilemetadata_plaintextextractor.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KFileMetaDataExtractor +X-KDE-Library=kfilemetadata_plaintextextractor +Name=KFileMetaData Plain Text Extractor +Name[bs]=KFileMetaData ekstraktor običnog teksta +Name[ca]=Extractor de text del KFileMetaData +Name[ca@valencia]=Extractor de text del KFileMetaData +Name[cs]=Extraktor čistého textu KFileMetaData +Name[da]=KFileMetaData Klartekst-udtrækker +Name[de]=Extraktion von einfachen Text für KFileMetaData +Name[el]=Εξαγωγέας απλού κειμένου KFileMetaData +Name[en_GB]=KFileMetaData Plain Text Extractor +Name[es]=Extractor de texto sin formato para KFileMetaData +Name[et]=KFileMetaData lihtteksti ekstraktimine +Name[fi]=KFileMetaDatan muotoilemattoman tekstin lukuohjelma +Name[fr]=Extracteur texte brut de KFileMetaData +Name[gl]=Extractor de texto simple de KFileMetaData +Name[hu]=KFileMetaData egyszerű szöveg kibontó +Name[ia]=Extractor de KFileMetaData Texto Plan +Name[it]=Estrattore per testo semplice di KFileMetaData +Name[ko]=KFileMetaData 일반 텍스트 추출기 +Name[lt]=KFileMetaData Paprastojo teksti ekstraktorius +Name[nb]=KFileMetaData uttrekker for ren tekst +Name[nds]=KFile-Metadaten-Eenfachtext-Leser +Name[nl]=Extractieprogramma voor KFileMetaData Plain Text +Name[pl]=Wydobywanie zwykłego tekstu dla KFileMetaData +Name[pt]=Extracção de Texto Simples do KFileMetaData +Name[pt_BR]=Extrator de Texto Simples do KFileMetaData +Name[ru]=Модуль извлечения метаданных из простых текстовых файлов +Name[sk]=Extraktor KFileMetaData Plain Text +Name[sl]=Program za izvleko golega besedila za KFileMetaData +Name[sr]=Издвајач обичног текста (KFileMetaData) +Name[sr@ijekavian]=Издвајач обичног текста (KFileMetaData) +Name[sr@ijekavianlatin]=Izdvajač običnog teksta (KFileMetaData) +Name[sr@latin]=Izdvajač običnog teksta (KFileMetaData) +Name[sv]=Kfilmetadata vanlig textextrahering +Name[tr]=KFileMetaData Düz Metin Çıkarıcı +Name[uk]=Засіб видобування метаданих з неформатованого тексту +Name[x-test]=xxKFileMetaData Plain Text Extractorxx +Name[zh_CN]=KFileMetaData 纯文本提取工具 +Name[zh_TW]=KFileMetaData 純文字檔展開器 diff --git a/kfilemetadata/src/extractors/kfilemetadata_popplerextractor.desktop b/kfilemetadata/src/extractors/kfilemetadata_popplerextractor.desktop new file mode 100644 index 00000000..5cf7e8ad --- /dev/null +++ b/kfilemetadata/src/extractors/kfilemetadata_popplerextractor.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KFileMetaDataExtractor +X-KDE-Library=kfilemetadata_popplerextractor +Name=KFileMetaData Poppler Extractor +Name[bs]=KFileMetaData Poppler ekstraktor +Name[ca]=Extractor Poppler del KFileMetaData +Name[ca@valencia]=Extractor Poppler del KFileMetaData +Name[cs]=Extraktor Poppler KFileMetaData +Name[da]=KFileMetaData Poppler-udtrækker +Name[de]=Poppler-Extraktion für KFileMetaData +Name[el]=Εξαγωγέας Poppler KFileMetaData +Name[en_GB]=KFileMetaData Poppler Extractor +Name[es]=Extractor de Poppler para KFileMetaData +Name[et]=KFileMetaData Poppleri ekstraktimine +Name[fi]=KFileMetaDatan Poppler-lukuohjelma +Name[fr]=Extracteur Poppler de KFileMetaData +Name[gl]=Extractor de Poppler de KFileMetaData +Name[hu]=KFileMetaData Poppler kibontó +Name[ia]=Extractor de KFileMetaData Poppler +Name[it]=Estrattore Poppler di KFileMetaData +Name[ko]=KFileMetaData Poppler 추출기 +Name[lt]=KFileMetaData Poppler ekstraktorius +Name[nb]=KFileMetaData Poppler-uttrekker +Name[nds]=KFile-Metadaten-Poppler-Leser +Name[nl]=Extractieprogramma voor KFileMetaData Poppler +Name[pl]=Wydobywanie z Poppler dla KFileMetaData +Name[pt]=Extracção de Poppler do KFileMetaData +Name[pt_BR]=Extrator de Poppler do KFileMetaData +Name[ru]=Модуль извлечения метаданных из файлов PDF с помощью Poppler +Name[sk]=Extraktor KFileMetaData Poppler +Name[sl]=Program za izvleko Poppler za KFileMetaData +Name[sr]=Издвајач Поплером (KFileMetaData) +Name[sr@ijekavian]=Издвајач Поплером (KFileMetaData) +Name[sr@ijekavianlatin]=Izdvajač Popplerom (KFileMetaData) +Name[sr@latin]=Izdvajač Popplerom (KFileMetaData) +Name[sv]=Kfilmetadata Poppler-extrahering +Name[tr]=KFileMetaData Poppler Çıkarıcı +Name[uk]=Засіб видобування метаданих Poppler +Name[x-test]=xxKFileMetaData Poppler Extractorxx +Name[zh_CN]=KFileMetaData Poppler 提取工具 +Name[zh_TW]=KFileMetaData Poppler 展開器 diff --git a/kfilemetadata/src/extractors/kfilemetadata_taglibextractor.desktop b/kfilemetadata/src/extractors/kfilemetadata_taglibextractor.desktop new file mode 100644 index 00000000..066c617d --- /dev/null +++ b/kfilemetadata/src/extractors/kfilemetadata_taglibextractor.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KFileMetaDataExtractor +X-KDE-Library=kfilemetadata_taglibextractor +Name=KFileMetaData TagLib Extractor +Name[bs]=KFileMetaData TagLib ekstraktor +Name[ca]=Extractor TagLib del KFileMetaData +Name[ca@valencia]=Extractor TagLib del KFileMetaData +Name[cs]=Extraktor TagLib KFileMetaData +Name[da]=KFileMetaData TagLib-udtrækker +Name[de]=TagLib-Extraktion für KFileMetaData +Name[el]=Εξαγωγέας TagLib KFileMetaData +Name[en_GB]=KFileMetaData TagLib Extractor +Name[es]=Extractor de TagLib para KFileMetaData +Name[et]=KFileMetaData TagLibi ekstraktimine +Name[fi]=KFileMetaDatan TagLib-lukuohjelma +Name[fr]=Extracteur TagLib de KFileMetaData +Name[gl]=Extractor de TagLib de KFileMetaData +Name[hu]=KFileMetaData TagLib kibontó +Name[ia]=Extractor de KFileMetaData TagLib +Name[it]=Estrattore TagLib di KFileMetaData +Name[ko]=KFileMetaData TagLib 추출기 +Name[lt]=KFileMetaData TagLib ekstraktorius +Name[nb]=KFileMetaData TagLib-uttrekker +Name[nds]=KFile-Metadaten-TagLib-Leser +Name[nl]=Extractieprogramma voor KFileMetaData TagLib +Name[pl]=Wydobywanie z TagLib dla KFileMetaData +Name[pt]=Extracção de TagLib do KFileMetaData +Name[pt_BR]=Extrator de TagLib do KFileMetaData +Name[ru]=Модуль извлечения метаданных из аудиофайлов с помощью TagLib +Name[sk]=Extraktor KFileMetaData TagLib +Name[sl]=Program za izvleko TagLib za KFileMetaData +Name[sr]=Издвајач Таглибом (KFileMetaData) +Name[sr@ijekavian]=Издвајач Таглибом (KFileMetaData) +Name[sr@ijekavianlatin]=Izdvajač TagLibom (KFileMetaData) +Name[sr@latin]=Izdvajač TagLibom (KFileMetaData) +Name[sv]=Kfilmetadata Taglib-extrahering +Name[tr]=KFileMetaData TagLib Çıkarıcı +Name[uk]=Засіб видобування метаданих TagLib +Name[x-test]=xxKFileMetaData TagLib Extractorxx +Name[zh_CN]=KFileMetaData TagLib 提取工具 +Name[zh_TW]=KFileMetaData TagLib 展開器 diff --git a/kfilemetadata/src/extractors/mobiextractor.cpp b/kfilemetadata/src/extractors/mobiextractor.cpp new file mode 100644 index 00000000..38db683c --- /dev/null +++ b/kfilemetadata/src/extractors/mobiextractor.cpp @@ -0,0 +1,112 @@ +/* + Copyright (C) 2013 Vishesh Handa + + Code adapted from kdegraphics-mobipocket/strigi/ + Copyright (C) 2008 by Jakub Stachowski + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "mobiextractor.h" + +#include + +#include +#include +#include +#include + +using namespace KFileMetaData; + +class QFileStream : public Mobipocket::Stream +{ +public: + QFileStream(const QString& name) : d(name) { + d.open(QIODevice::ReadOnly); + } + int read(char* buf, int size) { + return d.read(buf, size); + } + bool seek(int pos) { + return d.seek(pos); + } +private: + QFile d; +}; + +MobiExtractor::MobiExtractor(QObject* parent, const QVariantList&) + : ExtractorPlugin(parent) +{ + +} + +QStringList MobiExtractor::mimetypes() const +{ + QStringList types; + types << QLatin1String("application/x-mobipocket-ebook"); + + return types; +} + +void MobiExtractor::extract(ExtractionResult* result) +{ + QFileStream stream(result->inputUrl()); + Mobipocket::Document doc(&stream); + if (!doc.isValid()) + return; + + QMapIterator it(doc.metadata()); + while (it.hasNext()) { + it.next(); + switch (it.key()) { + case Mobipocket::Document::Title: + result->add(Property::Title, it.value()); + break; + case Mobipocket::Document::Author: { + result->add(Property::Author, it.value()); + break; + } + case Mobipocket::Document::Description: { + QTextDocument document; + document.setHtml(it.value()); + + QString plain = document.toPlainText(); + if (!plain.isEmpty()) + result->add(Property::Description, it.value()); + break; + } + case Mobipocket::Document::Subject: + result->add(Property::Subject, it.value()); + break; + case Mobipocket::Document::Copyright: + result->add(Property::Copyright, it.value()); + break; + } + } + + if (!doc.hasDRM()) { + QString html = doc.text(); + + QTextDocument document; + document.setHtml(html); + + result->append(document.toPlainText()); + } + + result->addType(Type::Document); +} + +KFILEMETADATA_EXPORT_EXTRACTOR(KFileMetaData::MobiExtractor, "kfilemetadata_mobiextractor") diff --git a/kfilemetadata/src/extractors/mobiextractor.h b/kfilemetadata/src/extractors/mobiextractor.h new file mode 100644 index 00000000..90adb9fc --- /dev/null +++ b/kfilemetadata/src/extractors/mobiextractor.h @@ -0,0 +1,39 @@ +/* + + Copyright (C) 2013 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef MOBIEXTRACTOR_H +#define MOBIEXTRACTOR_H + +#include "extractorplugin.h" + +namespace KFileMetaData +{ + +class MobiExtractor : public ExtractorPlugin +{ +public: + MobiExtractor(QObject* parent, const QVariantList&); + + virtual void extract(ExtractionResult* result); + virtual QStringList mimetypes() const; +}; +} + +#endif // MOBIEXTRACTOR_H diff --git a/kfilemetadata/src/extractors/odfextractor.cpp b/kfilemetadata/src/extractors/odfextractor.cpp new file mode 100644 index 00000000..e338440b --- /dev/null +++ b/kfilemetadata/src/extractors/odfextractor.cpp @@ -0,0 +1,138 @@ +/* + + Copyright (C) 2013 Vishesh Handa + Copyright (C) 2012 Jörg Ehrichs + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "odfextractor.h" + +#include +#include + +#include +#include + +using namespace KFileMetaData; + +OdfExtractor::OdfExtractor(QObject* parent, const QVariantList&): ExtractorPlugin(parent) +{ + +} + +QStringList OdfExtractor::mimetypes() const +{ + QStringList list; + list << QLatin1String("application/vnd.oasis.opendocument.text") + << QLatin1String("application/vnd.oasis.opendocument.presentation") + << QLatin1String("application/vnd.oasis.opendocument.spreadsheet"); + + return list; +} + +void OdfExtractor::extract(ExtractionResult* result) +{ + KZip zip(result->inputUrl()); + if (!zip.open(QIODevice::ReadOnly)) { + qWarning() << "Document is not a valid ZIP archive"; + return; + } + + const KArchiveDirectory* directory = zip.directory(); + if (!directory) { + qWarning() << "Invalid document structure (main directory is missing)"; + return; + } + + const QStringList entries = directory->entries(); + if (!entries.contains("meta.xml")) { + qWarning() << "Invalid document structure (meta.xml is missing)"; + return; + } + + QDomDocument metaData("metaData"); + const KArchiveFile* file = static_cast(directory->entry("meta.xml")); + metaData.setContent(file->data()); + + // parse metadata ... + QDomElement docElem = metaData.documentElement(); + + QDomNode n = docElem.firstChild().firstChild(); // ... ... content + while (!n.isNull()) { + QDomElement e = n.toElement(); + if (!e.isNull()) { + const QString tagName = e.tagName(); + + // Dublin Core + if (tagName == QLatin1String("dc:description")) { + result->add(Property::Description, e.text()); + } else if (tagName == QLatin1String("dc:subject")) { + result->add(Property::Subject, e.text()); + } else if (tagName == QLatin1String("dc:title")) { + result->add(Property::Title, e.text()); + } else if (tagName == QLatin1String("dc:creator")) { + result->add(Property::Creator, e.text()); + } else if (tagName == QLatin1String("dc:langauge")) { + result->add(Property::Langauge, e.text()); + } + + // Meta Properties + else if (tagName == QLatin1String("meta:document-statistic")) { + bool ok = false; + int pageCount = e.attribute("meta:page-count").toInt(&ok); + if (ok) { + result->add(Property::PageCount, pageCount); + } + + int wordCount = e.attribute("meta:word-count").toInt(&ok); + if (ok) { + result->add(Property::WordCount, wordCount); + } + } else if (tagName == QLatin1String("meta:keyword")) { + QString keywords = e.text(); + result->add(Property::Keywords, keywords); + } else if (tagName == QLatin1String("meta:generator")) { + result->add(Property::Creator, e.text()); + } else if (tagName == QLatin1String("meta:creation-date")) { + QDateTime dt = ExtractorPlugin::dateTimeFromString(e.text()); + if (!dt.isNull()) + result->add(Property::CreationDate, dt); + } + } + n = n.nextSibling(); + } + + const KArchiveFile* contentsFile = static_cast(directory->entry("content.xml")); + QXmlStreamReader xml(contentsFile->createDevice()); + + while (!xml.atEnd()) { + xml.readNext(); + if (xml.isCharacters()) { + QString str = xml.text().toString(); + result->append(str); + } + + if (xml.hasError() || xml.isEndDocument()) + break; + } + + result->addType(Type::Document); + + return; +} + +KFILEMETADATA_EXPORT_EXTRACTOR(KFileMetaData::OdfExtractor, "kfilemetadata_odfextractor") diff --git a/kfilemetadata/src/extractors/odfextractor.h b/kfilemetadata/src/extractors/odfextractor.h new file mode 100644 index 00000000..d7127807 --- /dev/null +++ b/kfilemetadata/src/extractors/odfextractor.h @@ -0,0 +1,41 @@ +/* + + Copyright (C) 2013 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef ODF_EXTRACTOR_H +#define ODF_EXTRACTOR_H + +#include "extractorplugin.h" + +namespace KFileMetaData +{ + +class OdfExtractor : public ExtractorPlugin +{ +public: + OdfExtractor(QObject* parent, const QVariantList&); + + virtual QStringList mimetypes() const; + virtual void extract(ExtractionResult* result); + +private: +}; +} + +#endif // ODF_EXTRACTOR_H diff --git a/kfilemetadata/src/extractors/office2007extractor.cpp b/kfilemetadata/src/extractors/office2007extractor.cpp new file mode 100644 index 00000000..01447411 --- /dev/null +++ b/kfilemetadata/src/extractors/office2007extractor.cpp @@ -0,0 +1,268 @@ +/* + + Copyright (C) 2013 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "office2007extractor.h" + +#include +#include + +#include +#include + +using namespace KFileMetaData; + +Office2007Extractor::Office2007Extractor(QObject* parent, const QVariantList&): ExtractorPlugin(parent) +{ + +} + + +QStringList Office2007Extractor::mimetypes() const +{ + QStringList list; + list << QLatin1String("application/vnd.openxmlformats-officedocument.wordprocessingml.document") + << QLatin1String("application/vnd.openxmlformats-officedocument.presentationml.presentation") + << QLatin1String("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + + return list; +} + +void Office2007Extractor::extract(ExtractionResult* result) +{ + KZip zip(result->inputUrl()); + if (!zip.open(QIODevice::ReadOnly)) { + qWarning() << "Document is not a valid ZIP archive"; + return; + } + + const KArchiveDirectory* rootDir = zip.directory(); + if (!rootDir) { + qWarning() << "Invalid document structure (main directory is missing)"; + return; + } + + const QStringList rootEntries = rootDir->entries(); + if (!rootEntries.contains("docProps")) { + qWarning() << "Invalid document structure (docProps is missing)"; + return; + } + + const KArchiveEntry* docPropEntry = rootDir->entry("docProps"); + if (!docPropEntry->isDirectory()) { + qWarning() << "Invalid document structure (docProps is not a directory)"; + return; + } + + const KArchiveDirectory* docPropDirectory = dynamic_cast(docPropEntry); + const QStringList docPropsEntries = docPropDirectory->entries(); + + if (docPropsEntries.contains("core.xml")) { + QDomDocument coreDoc("core"); + const KArchiveFile* file = static_cast(docPropDirectory->entry("core.xml")); + coreDoc.setContent(file->data()); + + QDomElement docElem = coreDoc.documentElement(); + + QDomElement elem = docElem.firstChildElement("dc:description"); + if (!elem.isNull()) { + QString str = elem.text(); + if (!str.isEmpty()) { + result->add(Property::Description, str); + } + } + + elem = docElem.firstChildElement("dc:subject"); + if (!elem.isNull()) { + QString str = elem.text(); + if (!str.isEmpty()) { + result->add(Property::Subject, str); + } + } + + elem = docElem.firstChildElement("dc:title"); + if (!elem.isNull()) { + QString str = elem.text(); + if (!str.isEmpty()) { + result->add(Property::Title, str); + } + } + + elem = docElem.firstChildElement("dc:creator"); + if (!elem.isNull()) { + QString str = elem.text(); + if (!str.isEmpty()) { + result->add(Property::Creator, str); + } + } + + elem = docElem.firstChildElement("dc:langauge"); + if (!elem.isNull()) { + QString str = elem.text(); + if (!str.isEmpty()) { + result->add(Property::Langauge, str); + } + } + } + + if (docPropsEntries.contains("app.xml")) { + QDomDocument appDoc("app"); + const KArchiveFile* file = static_cast(docPropDirectory->entry("app.xml")); + appDoc.setContent(file->data()); + + QDomElement docElem = appDoc.documentElement(); + + // According to the ontologies only Documents can have a wordCount and pageCount + const QString mimeType = result->inputMimetype(); + if (mimeType == QLatin1String("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) { + QDomElement elem = docElem.firstChildElement("Pages"); + if (!elem.isNull()) { + bool ok = false; + int pageCount = elem.text().toInt(&ok); + if (ok) { + result->add(Property::PageCount, pageCount); + } + } + + elem = docElem.firstChildElement("Words"); + if (!elem.isNull()) { + bool ok = false; + int wordCount = elem.text().toInt(&ok); + if (ok) { + result->add(Property::WordCount, wordCount); + } + } + } + + QDomElement elem = docElem.firstChildElement("Application"); + if (!elem.isNull()) { + QString app = elem.text(); + if (!app.isEmpty()) { + result->add(Property::Generator, app); + } + } + } + + + if (rootEntries.contains("word")) { + const KArchiveEntry* wordEntry = rootDir->entry("word"); + if (!wordEntry->isDirectory()) { + qWarning() << "Invalid document structure (word is not a directory)"; + return; + } + + const KArchiveDirectory* wordDirectory = dynamic_cast(wordEntry); + const QStringList wordEntries = wordDirectory->entries(); + + if (wordEntries.contains("document.xml")) { + QDomDocument appDoc("document"); + const KArchiveFile* file = static_cast(wordDirectory->entry("document.xml")); + + extractTextWithTag(file->createDevice(), QLatin1String("w:t"), result); + } + + result->addType(Type::Document); + } + + else if (rootEntries.contains("xl")) { + const KArchiveEntry* xlEntry = rootDir->entry("xl"); + if (!xlEntry->isDirectory()) { + qWarning() << "Invalid document structure (xl is not a directory)"; + return; + } + + const KArchiveDirectory* xlDirectory = dynamic_cast(xlEntry); + extractTextFromFiles(xlDirectory, result); + + result->addType(Type::Document); + result->addType(Type::Spreadsheet); + } + + else if (rootEntries.contains("ppt")) { + const KArchiveEntry* pptEntry = rootDir->entry("ppt"); + if (!pptEntry->isDirectory()) { + qWarning() << "Invalid document structure (ppt is not a directory)"; + return; + } + + const KArchiveDirectory* pptDirectory = dynamic_cast(pptEntry); + extractTextFromFiles(pptDirectory, result); + + result->addType(Type::Document); + result->addType(Type::Presentation); + } + + return; +} + +void Office2007Extractor::extractAllText(QIODevice* device, ExtractionResult* result) +{ + QXmlStreamReader xml(device); + + while (!xml.atEnd()) { + xml.readNext(); + if (xml.isCharacters()) { + QString str = xml.text().toString(); + result->append(str); + } + + if (xml.isEndDocument() || xml.hasError()) + break; + } +} + +void Office2007Extractor::extractTextFromFiles(const KArchiveDirectory* archiveDir, ExtractionResult* result) +{ + const QStringList entries = archiveDir->entries(); + foreach(const QString & entryName, entries) { + const KArchiveEntry* entry = archiveDir->entry(entryName); + if (entry->isDirectory()) { + const KArchiveDirectory* subDir = dynamic_cast(entry); + extractTextFromFiles(subDir, result); + continue; + } + + if (!entryName.endsWith(".xml")) + continue; + + const KArchiveFile* file = static_cast(entry); + extractAllText(file->createDevice(), result); + } +} + +void Office2007Extractor::extractTextWithTag(QIODevice* device, const QString& tag, ExtractionResult* result) +{ + QXmlStreamReader xml(device); + + while (!xml.atEnd()) { + xml.readNext(); + if (xml.qualifiedName().startsWith(tag) && xml.isStartElement()) { + QString str = xml.readElementText(QXmlStreamReader::IncludeChildElements); + + if (!str.isEmpty()) { + result->append(str); + } + } + + if (xml.isEndDocument() || xml.hasError()) + break; + } +} + +KFILEMETADATA_EXPORT_EXTRACTOR(KFileMetaData::Office2007Extractor, "kfilemetadata_office2007extractor") diff --git a/kfilemetadata/src/extractors/office2007extractor.h b/kfilemetadata/src/extractors/office2007extractor.h new file mode 100644 index 00000000..d65bdd94 --- /dev/null +++ b/kfilemetadata/src/extractors/office2007extractor.h @@ -0,0 +1,46 @@ +/* + + Copyright (C) 2013 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef OFFICE_2007_EXTRACTOR_H +#define OFFICE_2007_EXTRACTOR_H + +#include "extractorplugin.h" + +class KArchiveDirectory; + +namespace KFileMetaData +{ + +class Office2007Extractor : public ExtractorPlugin +{ +public: + Office2007Extractor(QObject* parent, const QVariantList&); + + virtual QStringList mimetypes() const; + virtual void extract(ExtractionResult* result); + +private: + void extractTextWithTag(QIODevice* device, const QString& tag, ExtractionResult* result); + void extractAllText(QIODevice* device, ExtractionResult* result); + void extractTextFromFiles(const KArchiveDirectory* archiveDir, ExtractionResult* result); +}; +} + +#endif // OFFICE_2007_EXTRACTOR_H diff --git a/kfilemetadata/src/extractors/officeextractor.cpp b/kfilemetadata/src/extractors/officeextractor.cpp new file mode 100644 index 00000000..21bf9745 --- /dev/null +++ b/kfilemetadata/src/extractors/officeextractor.cpp @@ -0,0 +1,118 @@ +/* + This file is part of a KMetaData File Extractor + Copyright (C) 2013 Denis Steckelmacher + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "officeextractor.h" + +#include + +#include +#include + +using namespace KFileMetaData; + +OfficeExtractor::OfficeExtractor(QObject* parent, const QVariantList&) + : ExtractorPlugin(parent) +{ + // Find the executables of catdoc, catppt and xls2csv. If an executable cannot + // be found, indexing its corresponding MIME type will be disabled + findExe("application/msword", "catdoc", m_catdoc); + findExe("application/vnd.ms-excel", "xls2csv", m_xls2csv); + findExe("application/vnd.ms-powerpoint", "catppt", m_catppt); +} + +void OfficeExtractor::findExe(const QString& mimeType, const QString& name, QString& fullPath) +{ + fullPath = KStandardDirs::findExe(name); + + if (!fullPath.isEmpty()) { + m_available_mime_types << mimeType; + } +} + +QStringList OfficeExtractor::mimetypes() const +{ + return m_available_mime_types; +} + + +void OfficeExtractor::extract(ExtractionResult* result) +{ + QVariantMap metadata; + QStringList args; + QString contents; + + args << QLatin1String("-s") << QLatin1String("cp1252"); // FIXME: Store somewhere a map between the user's language and the encoding of the Windows files it may use ? + args << QLatin1String("-d") << QLatin1String("utf8"); + + const QString fileUrl = result->inputUrl(); + const QString mimeType = result->inputMimetype(); + if (mimeType == QLatin1String("application/msword")) { + result->addType(Type::Document); + + args << QLatin1String("-w"); + contents = textFromFile(fileUrl, m_catdoc, args); + + // Now that we have the plain text content, count words, lines and characters + // (original code from plaintextextractor.cpp, authored by Vishesh Handa) + int lines = contents.count(QLatin1Char('\n')); + int words = contents.count(QRegExp("\\b\\w+\\b")); + + result->add(Property::WordCount, words); + result->add(Property::LineCount, lines); + } else if (mimeType == QLatin1String("application/vnd.ms-excel")) { + result->addType(Type::Document); + result->addType(Type::Spreadsheet); + + args << QLatin1String("-c") << QLatin1String(" "); + args << QLatin1String("-b") << QLatin1String(" "); + args << QLatin1String("-q") << QLatin1String("0"); + contents = textFromFile(fileUrl, m_xls2csv, args); + } else if (mimeType == QLatin1String("application/vnd.ms-powerpoint")) { + result->addType(Type::Document); + result->addType(Type::Presentation); + + contents = textFromFile(fileUrl, m_catppt, args); + } + + if (contents.isEmpty()) + return; + + result->append(contents); + + return; +} + +QString OfficeExtractor::textFromFile(const QString& fileUrl, const QString& command, QStringList& arguments) +{ + arguments << fileUrl; + + // Start a process and read its standard output + QProcess process; + + process.setReadChannel(QProcess::StandardOutput); + process.start(command, arguments, QIODevice::ReadOnly); + process.waitForFinished(); + + if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) + return QString(); + else + return QString::fromUtf8(process.readAll()); +} + +KFILEMETADATA_EXPORT_EXTRACTOR(KFileMetaData::OfficeExtractor, "kfilemetadata_officeextractor") diff --git a/kfilemetadata/src/extractors/officeextractor.h b/kfilemetadata/src/extractors/officeextractor.h new file mode 100644 index 00000000..f8e48b11 --- /dev/null +++ b/kfilemetadata/src/extractors/officeextractor.h @@ -0,0 +1,50 @@ +/* + This file is part of a KMetaData File Extractor + Copyright (C) 2013 Denis Steckelmacher + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef OFFICE_EXTRACTOR_H +#define OFFICE_EXTRACTOR_H + +#include "extractorplugin.h" + +namespace KFileMetaData +{ + +class OfficeExtractor : public ExtractorPlugin +{ +public: + OfficeExtractor(QObject* parent, const QVariantList&); + + virtual QStringList mimetypes() const; + virtual void extract(ExtractionResult* result); + +private: + void findExe(const QString& mimeType, const QString& name, QString& fullPath); + QString textFromFile(const QString& fileUrl, const QString& command, QStringList& arguments); + +private: + QStringList m_available_mime_types; + + QString m_catdoc; + QString m_catppt; + QString m_xls2csv; +}; +} + +#endif diff --git a/kfilemetadata/src/extractors/plaintextextractor.cpp b/kfilemetadata/src/extractors/plaintextextractor.cpp new file mode 100644 index 00000000..baac928a --- /dev/null +++ b/kfilemetadata/src/extractors/plaintextextractor.cpp @@ -0,0 +1,59 @@ +/* + + Copyright (C) 2012 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "plaintextextractor.h" +#include + +#include + +using namespace KFileMetaData; + +PlainTextExtractor::PlainTextExtractor(QObject* parent, const QVariantList&) + : ExtractorPlugin(parent) +{ + +} + +QStringList PlainTextExtractor::mimetypes() const +{ + return QStringList() << QLatin1String("text/"); +} + +void PlainTextExtractor::extract(ExtractionResult* result) +{ + std::string line; + int lines = 0; + + std::ifstream fstream(QFile::encodeName(result->inputUrl())); + if (!fstream.is_open()) { + return; + } + + while (std::getline(fstream, line)) { + result->append(QString::fromUtf8(line.c_str(), line.size())); + + lines += 1; + } + + result->add(Property::LineCount, lines); + result->addType(Type::Text); +} + +KFILEMETADATA_EXPORT_EXTRACTOR(KFileMetaData::PlainTextExtractor, "kfilemetadata_plaintextextractor") diff --git a/kfilemetadata/src/extractors/plaintextextractor.h b/kfilemetadata/src/extractors/plaintextextractor.h new file mode 100644 index 00000000..71248a55 --- /dev/null +++ b/kfilemetadata/src/extractors/plaintextextractor.h @@ -0,0 +1,40 @@ +/* + + Copyright (C) 2012 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef PLAINTEXTEXTRACTOR_H +#define PLAINTEXTEXTRACTOR_H + +#include "extractorplugin.h" + +namespace KFileMetaData +{ + +class PlainTextExtractor : public ExtractorPlugin +{ +public: + PlainTextExtractor(QObject* parent, const QVariantList&); + + virtual QStringList mimetypes() const; + virtual void extract(ExtractionResult* result); +}; + +} + +#endif // PLAINTEXTEXTRACTOR_H diff --git a/kfilemetadata/src/extractors/popplerextractor.cpp b/kfilemetadata/src/extractors/popplerextractor.cpp new file mode 100644 index 00000000..4612317a --- /dev/null +++ b/kfilemetadata/src/extractors/popplerextractor.cpp @@ -0,0 +1,174 @@ +/* + + Copyright (C) 2012 Vishesh Handa + Copyright (C) 2012 Jörg Ehrichs + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "popplerextractor.h" + +#include +#include + +using namespace KFileMetaData; + +PopplerExtractor::PopplerExtractor(QObject* parent, const QVariantList&) + : ExtractorPlugin(parent) +{ + +} + +QStringList PopplerExtractor::mimetypes() const +{ + QStringList list; + list << QLatin1String("application/pdf"); + + return list; +} + + +void PopplerExtractor::extract(ExtractionResult* result) +{ + const QString fileUrl = result->inputUrl(); + QScopedPointer pdfDoc(Poppler::Document::load(fileUrl, 0, 0)); + + if (!pdfDoc || pdfDoc->isLocked()) { + return; + } + + result->addType(Type::Document); + + QString title = pdfDoc->info(QLatin1String("Title")).trimmed(); + + // The title extracted from the pdf metadata is in many cases not the real title + // of the document. Especially for research papers that are exported to pdf. + // As mostly the title of a pdf document is written on the first page in the biggest font + // we use this if the pdfDoc title is considered junk + if (title.isEmpty() || + !title.contains(' ') || // very unlikely the title of a document does only contain one word. + title.contains(QLatin1String("Microsoft"), Qt::CaseInsensitive)) { // most research papers i found written with microsoft word + // have a garbage title of the pdf creator rather than the real document title + title = parseFirstPage(pdfDoc.data(), fileUrl); + } + + if (!title.isEmpty()) { + result->add(Property::Title, title); + } + + QString subject = pdfDoc->info(QLatin1String("Subject")); + if (!subject.isEmpty()) { + result->add(Property::Subject, title); + } + + QString author = pdfDoc->info(QLatin1String("Author")); + if (!author.isEmpty()) { + result->add(Property::Author, author); + } + + QString creator = pdfDoc->info(QLatin1String("Creator")); + if (!author.isEmpty()) { + result->add(Property::Creator, creator); + } + + for (int i = 0; i < pdfDoc->numPages(); i++) { + QScopedPointer page(pdfDoc->page(i)); + if (!page) { // broken pdf files do not return a valid page + kWarning() << "Could not read page content from" << fileUrl; + break; + } + result->append(page->text(QRectF())); + } +} + +QString PopplerExtractor::parseFirstPage(Poppler::Document* pdfDoc, const QString& fileUrl) +{ + QScopedPointer p(pdfDoc->page(0)); + + if (!p) { + kWarning() << "Could not read page content from" << fileUrl; + return QString(); + } + + QList tbList = p->textList(); + QMap possibleTitleMap; + + int currentLargestChar = 0; + int skipTextboxes = 0; + + // Iterate over all textboxes. Each textbox can be a single character/word or textblock + // Here we combine the etxtboxes back together based on the textsize + // Important are the words with the biggest font size + foreach(Poppler::TextBox * tb, tbList) { + + // if we added followup words, skip the textboxes here now + if (skipTextboxes > 0) { + skipTextboxes--; + continue; + } + + int height = tb->charBoundingBox(0).height(); + + // if the following text is smaller than the biggest we found up to now, ignore it + if (height >= currentLargestChar) { + QString possibleTitle; + possibleTitle.append(tb->text()); + currentLargestChar = height; + + // if the text has follow up words add them to to create the full title + Poppler::TextBox* next = tb->nextWord(); + while (next) { + possibleTitle.append(QLatin1Char(' ')); + possibleTitle.append(next->text()); + next = next->nextWord(); + skipTextboxes++; + } + + // now combine text for each font size together, very likeley it must be connected + QString existingTitlePart = possibleTitleMap.value(currentLargestChar, QString()); + existingTitlePart.append(QLatin1Char(' ')); + existingTitlePart.append(possibleTitle); + possibleTitleMap.insert(currentLargestChar, existingTitlePart); + } + } + + qDeleteAll(tbList); + + QList titleSizes = possibleTitleMap.keys(); + qSort(titleSizes.begin(), titleSizes.end(), qGreater()); + + QString newPossibleTitle; + + // find the text with the largest font that is not just 1 character + foreach(int i, titleSizes) { + QString title = possibleTitleMap.value(i); + + // sometime the biggest part is a single letter + // as a starting paragraph letter + if (title.size() < 5) { + continue; + } else { + newPossibleTitle = title.trimmed(); + break; + } + } + + // Sometimes the titles that are extracted are too large. This is a way of trimming them. + newPossibleTitle.truncate(50); + return newPossibleTitle; +} + +KFILEMETADATA_EXPORT_EXTRACTOR(KFileMetaData::PopplerExtractor, "kfilemetadata_popplerextractor") diff --git a/kfilemetadata/src/extractors/popplerextractor.h b/kfilemetadata/src/extractors/popplerextractor.h new file mode 100644 index 00000000..7e7554e8 --- /dev/null +++ b/kfilemetadata/src/extractors/popplerextractor.h @@ -0,0 +1,43 @@ +/* + + Copyright (C) 2012 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef POPPLEREXTRACTOR_H +#define POPPLEREXTRACTOR_H + +#include "extractorplugin.h" +#include + +namespace KFileMetaData +{ + +class PopplerExtractor : public ExtractorPlugin +{ +public: + PopplerExtractor(QObject* parent, const QVariantList&); + + virtual QStringList mimetypes() const; + virtual void extract(ExtractionResult* result); + +private: + QString parseFirstPage(Poppler::Document* pdfDoc, const QString& fileUrl); +}; +} + +#endif // POPPLEREXTRACTOR_H diff --git a/kfilemetadata/src/extractors/taglibextractor.cpp b/kfilemetadata/src/extractors/taglibextractor.cpp new file mode 100644 index 00000000..fb8d5942 --- /dev/null +++ b/kfilemetadata/src/extractors/taglibextractor.cpp @@ -0,0 +1,432 @@ +/* + + Copyright (C) 2012 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "taglibextractor.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace KFileMetaData; + +TagLibExtractor::TagLibExtractor(QObject* parent, const QVariantList&) + : ExtractorPlugin(parent) +{ +} + +QStringList TagLibExtractor::mimetypes() const +{ + QStringList types; + // MP3 FLAC, MPC, Speex, WavPack TrueAudio, WAV, AIFF, MP4 and ASF files. + // MP3 + types << QLatin1String("audio/mpeg"); + types << QLatin1String("audio/mpeg3"); types << QLatin1String("audio/x-mpeg"); + + // FLAC + types << QLatin1String("audio/flac"); + + // MPC + types << QLatin1String("audio/x-musepack"); + + //OGG + types << QLatin1String("audio/ogg"); types << QLatin1String("audio/x-vorbis+ogg"); + + // WAV + types << QLatin1String("audio/wav"); + + // AIFF + types << QLatin1String("audio/x-aiff"); + + // APE + types << QLatin1String("audio/x-ape"); + + // WV + types << QLatin1String("audio/x-wavpack"); + + return types; +} + +void TagLibExtractor::extract(ExtractionResult* result) +{ + const QString fileUrl = result->inputUrl(); + const QString mimeType = result->inputMimetype(); + + TagLib::FileRef file(fileUrl.toUtf8().data(), true); + if (file.isNull()) { + return; + } + + TagLib::Tag* tags = file.tag(); + result->addType(Type::Audio); + + TagLib::String artists; + TagLib::String albumArtists; + TagLib::String composers; + TagLib::String lyricists; + TagLib::StringList genres; + + // Handling multiple tags in mpeg files. + if ((mimeType == "audio/mpeg") || (mimeType == "audio/mpeg3") || (mimeType == "audio/x-mpeg")) { + TagLib::MPEG::File mpegFile(fileUrl.toUtf8().data(), true); + if (mpegFile.ID3v2Tag() && !mpegFile.ID3v2Tag()->isEmpty()) { + TagLib::ID3v2::FrameList lstID3v2; + + // Artist. + lstID3v2 = mpegFile.ID3v2Tag()->frameListMap()["TPE1"]; + if (!lstID3v2.isEmpty()) { + for (TagLib::ID3v2::FrameList::ConstIterator it = lstID3v2.begin(); it != lstID3v2.end(); ++it) { + if (!artists.isEmpty()) { + artists += ", "; + } + artists += (*it)->toString(); + } + } + + // Album Artist. + lstID3v2 = mpegFile.ID3v2Tag()->frameListMap()["TPE2"]; + if (!lstID3v2.isEmpty()) { + for (TagLib::ID3v2::FrameList::ConstIterator it = lstID3v2.begin(); it != lstID3v2.end(); ++it) { + if (!albumArtists.isEmpty()) { + albumArtists += ", "; + } + albumArtists += (*it)->toString(); + } + } + + // Composer. + lstID3v2 = mpegFile.ID3v2Tag()->frameListMap()["TCOM"]; + if (!lstID3v2.isEmpty()) { + for (TagLib::ID3v2::FrameList::ConstIterator it = lstID3v2.begin(); it != lstID3v2.end(); ++it) { + if (!composers.isEmpty()) { + composers += ", "; + } + composers += (*it)->toString(); + } + } + + // Lyricist. + lstID3v2 = mpegFile.ID3v2Tag()->frameListMap()["TEXT"]; + if (!lstID3v2.isEmpty()) { + for (TagLib::ID3v2::FrameList::ConstIterator it = lstID3v2.begin(); it != lstID3v2.end(); ++it) { + if (!lyricists.isEmpty()) { + lyricists += ", "; + } + lyricists += (*it)->toString(); + } + } + + // Genre. + lstID3v2 = mpegFile.ID3v2Tag()->frameListMap()["TCON"]; + if (!lstID3v2.isEmpty()) { + for (TagLib::ID3v2::FrameList::ConstIterator it = lstID3v2.begin(); it != lstID3v2.end(); ++it) { + genres.append((*it)->toString()); + } + } + + } + } + + // Handling multiple tags in FLAC files. + if (mimeType == "audio/flac") { + TagLib::FLAC::File flacFile(fileUrl.toUtf8().data(), true); + if (flacFile.xiphComment() && !flacFile.xiphComment()->isEmpty()) { + TagLib::Ogg::FieldListMap lstFLAC = flacFile.xiphComment()->fieldListMap(); + TagLib::Ogg::FieldListMap::ConstIterator itFLAC; + + // Artist. + itFLAC = lstFLAC.find("ARTIST"); + if (itFLAC != lstFLAC.end()) { + if (!artists.isEmpty()) { + artists += ", "; + } + artists += (*itFLAC).second.toString(", "); + } + + // Album Artist. + itFLAC = lstFLAC.find("ALBUMARTIST"); + if (itFLAC != lstFLAC.end()) { + if (!albumArtists.isEmpty()) { + albumArtists += ", "; + } + albumArtists += (*itFLAC).second.toString(", "); + } + + // Composer. + itFLAC = lstFLAC.find("COMPOSER"); + if (itFLAC != lstFLAC.end()) { + if (!composers.isEmpty()) { + composers += ", "; + } + composers += (*itFLAC).second.toString(", "); + } + + // Lyricist. + itFLAC = lstFLAC.find("LYRICIST"); + if (itFLAC != lstFLAC.end()) { + if (!lyricists.isEmpty()) { + lyricists += ", "; + } + lyricists += (*itFLAC).second.toString(", "); + } + + // Genre. + itFLAC = lstFLAC.find("GENRE"); + if (itFLAC != lstFLAC.end()) { + genres.append((*itFLAC).second); + } + } + } + + // Handling multiple tags in Musepack files. + if (mimeType == ("audio/x-musepack")) { + TagLib::MPC::File mpcFile(fileUrl.toUtf8().data(), true); + if (mpcFile.tag() && !mpcFile.tag()->isEmpty()) { + TagLib::APE::ItemListMap lstMusepack = mpcFile.APETag()->itemListMap(); + TagLib::APE::ItemListMap::ConstIterator itMPC; + + // Artist. + itMPC = lstMusepack.find("ARTIST"); + if (itMPC != lstMusepack.end()) { + if (!artists.isEmpty()) { + artists += ", "; + } + artists += (*itMPC).second.toString(); + } + + // Album Artist. + itMPC = lstMusepack.find("ALBUMARTIST"); + if (itMPC != lstMusepack.end()) { + if(!albumArtists.isEmpty()) { + albumArtists += ", "; + } + albumArtists += (*itMPC).second.toString(); + } + + // Composer. + itMPC = lstMusepack.find("COMPOSER"); + if (itMPC != lstMusepack.end()) { + if (!composers.isEmpty()) { + composers += ", "; + } + composers += (*itMPC).second.toString(); + } + + // Lyricist. + itMPC = lstMusepack.find("LYRICIST"); + if (itMPC != lstMusepack.end()) { + if (!lyricists.isEmpty()) { + lyricists += ", "; + } + lyricists += (*itMPC).second.toString(); + } + + // Genre. + itMPC = lstMusepack.find("GENRE"); + if (itMPC != lstMusepack.end()) { + genres.append((*itMPC).second.toString()); + } + } + } + + // Handling multiple tags in OGG files. + if (mimeType == "audio/ogg" || mimeType == "audio/x-vorbis+ogg") { + TagLib::Ogg::Vorbis::File oggFile(fileUrl.toUtf8().data(), true); + if (oggFile.tag() && !oggFile.tag()->isEmpty()) { + TagLib::Ogg::FieldListMap lstOGG = oggFile.tag()->fieldListMap(); + TagLib::Ogg::FieldListMap::ConstIterator itOGG; + + // Artist. + itOGG = lstOGG.find("ARTIST"); + if (itOGG != lstOGG.end()) { + if (!artists.isEmpty()) { + artists += ", "; + } + artists += (*itOGG).second.toString(", "); + } + + // Album Artist. + itOGG = lstOGG.find("ALBUMARTIST"); + if (itOGG != lstOGG.end()) { + if (!albumArtists.isEmpty()) { + albumArtists += ", "; + } + albumArtists += (*itOGG).second.toString(", "); + } + + // Composer. + itOGG = lstOGG.find("COMPOSER"); + if (itOGG != lstOGG.end()) { + if (!composers.isEmpty()) { + composers += ", "; + } + composers += (*itOGG).second.toString(", "); + } + + // Lyricist. + itOGG = lstOGG.find("LYRICIST"); + if (itOGG != lstOGG.end()) { + if (!lyricists.isEmpty()) { + lyricists += ", "; + } + lyricists += (*itOGG).second.toString(", "); + } + + // Genre. + itOGG = lstOGG.find("GENRE"); + if (itOGG != lstOGG.end()) { + genres.append((*itOGG).second); + } + } + } + + if (!tags->isEmpty()) { + QString title = QString::fromUtf8(tags->title().toCString(true)); + if (!title.isEmpty()) { + result->add(Property::Title, title); + } + + QString comment = QString::fromUtf8(tags->comment().toCString(true)); + if (!comment.isEmpty()) { + result->add(Property::Comment, comment); + } + + if (genres.isEmpty()) { + genres.append(tags->genre()); + } + + for (uint i = 0; i < genres.size(); i++) { + QString genre = QString::fromUtf8(genres[i].toCString(true)).trimmed(); + + // Convert from int + bool ok = false; + int genreNum = genre.toInt(&ok); + if (ok) { + genre = QString::fromUtf8(TagLib::ID3v1::genre(genreNum).toCString(true)); + } + + result->add(Property::Genre, genre); + } + + QString artistString; + if (artists.isEmpty()) { + artistString = QString::fromUtf8(tags->artist().toCString(true)); + } else { + artistString = QString::fromUtf8(artists.toCString(true)).trimmed(); + } + + QStringList artists = contactsFromString(artistString); + foreach(const QString& artist, artists) { + result->add(Property::Artist, artist); + } + + QString composersString = QString::fromUtf8(composers.toCString(true)).trimmed(); + QStringList composers = contactsFromString(composersString); + foreach(const QString& comp, composers) { + result->add(Property::Composer, comp); + } + + QString lyricistsString = QString::fromUtf8(lyricists.toCString(true)).trimmed(); + QStringList lyricists = contactsFromString(lyricistsString); + foreach(const QString& lyr, lyricists) { + result->add(Property::Lyricist, lyr); + } + + QString album = QString::fromUtf8(tags->album().toCString(true)); + if (!album.isEmpty()) { + result->add(Property::Album, album); + + QString albumArtistsString = QString::fromUtf8(albumArtists.toCString(true)).trimmed(); + QStringList albumArtists = contactsFromString(albumArtistsString); + foreach(const QString& res, albumArtists) { + result->add(Property::AlbumArtist, res); + } + } + + if (tags->track()) { + result->add(Property::TrackNumber, tags->track()); + } + + if (tags->year()) { + result->add(Property::ReleaseYear, tags->year()); + } + } + + TagLib::AudioProperties* audioProp = file.audioProperties(); + if (audioProp) { + if (audioProp->length()) { + // What about the xml duration? + result->add(Property::Duration, audioProp->length()); + } + + if (audioProp->bitrate()) { + result->add(Property::BitRate, audioProp->bitrate() * 1000); + } + + if (audioProp->channels()) { + result->add(Property::Channels, audioProp->channels()); + } + + if (audioProp->sampleRate()) { + result->add(Property::SampleRate, audioProp->sampleRate()); + } + } + + // TODO: Get more properties based on the file type + // - Codec + // - Album Artist + // - Publisher + + // TAG information (incomplete). + // A good reference: http://qoobar.sourceforge.net/en/documentation.htm + // -- FLAC/OGG -- + // Artist: ARTIST, PERFORMER + // Album artist: ALBUMARTIST + // Composer: COMPOSER + // Lyricist: LYRICIST + // Conductor: CONDUCTOR + // Disc number: DISCNUMBER + // Total discs: TOTALDISCS, DISCTOTAL + // Track number: TRACKNUMBER + // Total tracks: TOTALTRACKS, TRACKTOTAL + // Genre: GENRE + // -- ID3v2 -- + // Artist: TPE1 + // Album artist: TPE2 + // Composer: TCOM + // Lyricist: TEXT + // Conductor: TPE3 + // Disc number[/total dics]: TPOS + // Track number[/total tracks]: TRCK + // Genre: TCON +} + +KFILEMETADATA_EXPORT_EXTRACTOR(KFileMetaData::TagLibExtractor, "kfilemetadata_taglibextextractor") diff --git a/kfilemetadata/src/extractors/taglibextractor.h b/kfilemetadata/src/extractors/taglibextractor.h new file mode 100644 index 00000000..71a7fdce --- /dev/null +++ b/kfilemetadata/src/extractors/taglibextractor.h @@ -0,0 +1,41 @@ +/* + + Copyright (C) 2012 Vishesh Handa + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef TAGLIBEXTRACTOR_H +#define TAGLIBEXTRACTOR_H + +#include "extractorplugin.h" + +namespace KFileMetaData +{ + +class TagLibExtractor : public ExtractorPlugin +{ + +public: + TagLibExtractor(QObject* parent, const QVariantList&); + + virtual void extract(ExtractionResult* result); + virtual QStringList mimetypes() const; +}; + +} + +#endif // TAGLIBEXTRACTOR_H diff --git a/kfilemetadata/src/kfilemetadata_export.h b/kfilemetadata/src/kfilemetadata_export.h new file mode 100644 index 00000000..c7d1ee15 --- /dev/null +++ b/kfilemetadata/src/kfilemetadata_export.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + Copyright (C) 2007 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KFILEMETADATA_EXPORT_H +#define _KFILEMETADATA_EXPORT_H + +/* needed for KDE_EXPORT and KDE_IMPORT macros */ +#include + +#ifndef KFILEMETADATA_EXPORT +# if defined(KDELIBS_STATIC_LIBS) + /* No export/import for static libraries */ +# define KFILEMETADATA_EXPORT +# elif defined(MAKE_KFILEMETADATA_LIB) + /* We are building this library */ +# define KFILEMETADATA_EXPORT KDE_EXPORT +# else + /* We are using this library */ +# define KFILEMETADATA_EXPORT KDE_IMPORT +# endif +#endif + +#endif diff --git a/kfilemetadata/src/kfilemetadataextractor.desktop b/kfilemetadata/src/kfilemetadataextractor.desktop new file mode 100644 index 00000000..246777f9 --- /dev/null +++ b/kfilemetadata/src/kfilemetadataextractor.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=KFileMetaDataExtractor +Comment=KFileMetaData Extractor +Comment[bs]=KFileMetaData ekstraktor +Comment[ca]=Extractor del KFileMetaData +Comment[ca@valencia]=Extractor del KFileMetaData +Comment[cs]=Extraktor KFileMetaData +Comment[da]=KFileMetaData-udtrækker +Comment[de]=KFileMetaData-Extraktion +Comment[el]=Εξαγωγέας KFileMetaData +Comment[en_GB]=KFileMetaData Extractor +Comment[es]=Extractor para KFileMetaData +Comment[et]=KFileMetaData ekstraktimine +Comment[fi]=KFileMetaDatan lukuohjelma +Comment[fr]=Extracteur de KFileMetaData +Comment[gl]=Extractor de KFileMetaData +Comment[hu]=KFileMetaData kibontó +Comment[ia]=Extractor de KFileMetaData +Comment[it]=Estrattore di KFileMetaData +Comment[ko]=KFileMetaData 추출기 +Comment[lt]=KFileMetaData ekstraktorius +Comment[nb]=KFileMetaData uttrekker +Comment[nds]=KFile-Metadaten-Leser +Comment[nl]=Extractieprogramma voor KFileMetaData +Comment[pa]=KFileMetaData ਐਕਸਟਰੈਕਟਰ +Comment[pl]=Wydobywanie KFileMetaData +Comment[pt]=Extracção do KFileMetaData +Comment[pt_BR]=Extrator do KFileMetaData +Comment[ru]=Модуль извлечения метаданных из файлов +Comment[sk]=Extraktor KFileMetaData +Comment[sl]=Program za izvleko za KFileMetaData +Comment[sr]=Издвајач на основу KFileMetaData +Comment[sr@ijekavian]=Издвајач на основу KFileMetaData +Comment[sr@ijekavianlatin]=Izdvajač na osnovu KFileMetaData +Comment[sr@latin]=Izdvajač na osnovu KFileMetaData +Comment[sv]=Kfilmetadata extrahering +Comment[tr]=KFileMetaData Çıkarıcı +Comment[uk]=Засіб видобування метаданих +Comment[x-test]=xxKFileMetaData Extractorxx +Comment[zh_CN]=KFileMetaData 提取工具 +Comment[zh_TW]=KFileMetaData 展開器 diff --git a/kfilemetadata/src/properties.h b/kfilemetadata/src/properties.h new file mode 100644 index 00000000..a96048eb --- /dev/null +++ b/kfilemetadata/src/properties.h @@ -0,0 +1,126 @@ +/* + * This file is part of KFileMetaData + * Copyright (C) 2014 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef KFILEMETADATA_PROPERTIES +#define KFILEMETADATA_PROPERTIES + +#include +#include + +namespace KFileMetaData { +namespace Property { + +enum Property { + FirstProperty = 0, + Empty = 0, + + // Audio + BitRate, + Channels, + Duration, + Genre, + SampleRate, + TrackNumber, + ReleaseYear, + + // Maybe merge this with the description? + Comment, + + // Music + Artist, + Album, + AlbumArtist, + Composer, + Lyricist, + + // Documents + Author, + Title, + Subject, + Creator, + Generator, // What's the difference? + PageCount, + WordCount, + LineCount, + Langauge, + Copyright, + Publisher, + Description, + CreationDate, + Keywords, + + Width, + Height, + AspectRatio, + FrameRate, + + // Images + ImageMake, + ImageModel, + ImageDateTime, + ImageOrientation, + PhotoFlash, + PhotoPixelXDimension, + PhotoPixelYDimension, + PhotoDateTimeOriginal, + PhotoFocalLength, + PhotoFocalLengthIn35mmFilm, + PhotoExposureTime, + PhotoFNumber, + PhotoApertureValue, + PhotoExposureBiasValue, + PhotoWhiteBalance, + PhotoMeteringMode, + PhotoISOSpeedRatings, + PhotoSaturation, + PhotoSharpness, + + LastProperty = PhotoSharpness +}; + +} // namespace Property + +typedef QMap PropertyMap; + +inline QVariantMap toVariantMap(const PropertyMap& propMap) { + QVariantMap varMap; + PropertyMap::const_iterator it = propMap.constBegin(); + for (; it != propMap.constEnd(); ++it) { + int p = static_cast(it.key()); + varMap.insertMulti(QString::number(p), it.value()); + } + + return varMap; +} + +inline PropertyMap toPropertyMap(const QVariantMap& varMap) { + PropertyMap propMap; + QVariantMap::const_iterator it = varMap.constBegin(); + for (; it != varMap.constEnd(); ++it) { + int p = it.key().toInt(); + propMap.insertMulti(static_cast(p), it.value()); + } + + return propMap; +} + +} // namespace KFileMetaData + +#endif diff --git a/kfilemetadata/src/propertyinfo.cpp b/kfilemetadata/src/propertyinfo.cpp new file mode 100644 index 00000000..3dde0a48 --- /dev/null +++ b/kfilemetadata/src/propertyinfo.cpp @@ -0,0 +1,472 @@ +/* + * This file is part of the KFileMetaData project + * Copyright (C) 2014 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#include "propertyinfo.h" + +#include +#include + +static const KCatalogLoader loader("kfilemetadata"); + +using namespace KFileMetaData; + +class PropertyInfo::Private { +public: + Property::Property prop; + QString name; + QString displayName; + QVariant::Type valueType; + bool shouldBeIndexed; +}; + +PropertyInfo::PropertyInfo(Property::Property property) + : d(new Private) +{ + d->prop = property; + d->shouldBeIndexed = true; + + switch (property) { + case Property::Album: + d->name = QLatin1String("album"); + d->displayName = i18nc("@label music album", "Album"); + d->valueType = QVariant::String; + break; + + case Property::AlbumArtist: + d->name = QLatin1String("albumArtist"); + d->displayName = i18nc("@label", "Album Artist"); + d->valueType = QVariant::StringList; + break; + + case Property::Artist: + d->name = QLatin1String("artist"); + d->displayName = i18nc("@label", "Artist"); + d->valueType = QVariant::StringList; + break; + + case Property::AspectRatio: + d->name = QLatin1String("aspectRatio"); + d->displayName = i18nc("@label", "Aspect Ratio"); + d->valueType = QVariant::Int; + break; + + case Property::Author: + d->name = QLatin1String("author"); + d->displayName = i18nc("@label", "Author"); + d->valueType = QVariant::StringList; + break; + + case Property::BitRate: + d->name = QLatin1String("bitRate"); + d->displayName = i18nc("@label", "Bitrate"); + d->valueType = QVariant::Int; + break; + + case Property::Channels: + d->name = QLatin1String("channels"); + d->displayName = i18nc("@label", "Channels"); + d->valueType = QVariant::Int; + break; + + case Property::Comment: + d->name = QLatin1String("comment"); + d->displayName = i18nc("@label", "Comment"); + d->valueType = QVariant::String; + d->shouldBeIndexed = false; + break; + + case Property::Composer: + d->name = QLatin1String("composer"); + d->displayName = i18nc("@label", "Composer"); + d->valueType = QVariant::String; + d->shouldBeIndexed = false; + break; + + case Property::Copyright: + d->name = QLatin1String("copyright"); + d->displayName = i18nc("@label", "Copyright"); + d->valueType = QVariant::String; + d->shouldBeIndexed = false; + break; + + case Property::CreationDate: + d->name = QLatin1String("creationDate"); + d->displayName = i18nc("@label", "Creation Date"); + d->valueType = QVariant::String; + break; + + case Property::Creator: + d->name = QLatin1String("creator"); + d->displayName = i18nc("@label", "Creator"); + d->valueType = QVariant::String; + d->shouldBeIndexed = false; + break; + + case Property::Description: + d->name = QLatin1String("description"); + d->displayName = i18nc("@label", "Description"); + d->valueType = QVariant::String; + d->shouldBeIndexed = false; + break; + + case Property::Duration: + d->name = QLatin1String("duration"); + d->displayName = i18nc("@label", "Duration"); + d->valueType = QVariant::Int; + break; + + case Property::Empty: + d->name = QLatin1String("empty"); + d->valueType = QVariant::Invalid; + break; + + case Property::FrameRate: + d->name = QLatin1String("frameRate"); + d->displayName = i18nc("@label", "Frame Rate"); + d->valueType = QVariant::Int; + break; + + // FIXME: This doesn't tell the user much + case Property::Generator: + d->name = QLatin1String("generator"); + d->displayName = i18nc("@label", "Generator"); + d->valueType = QVariant::String; + d->shouldBeIndexed = false; + break; + + case Property::Genre: + d->name = QLatin1String("genre"); + d->displayName = i18nc("@label music genre", "Genre"); + d->valueType = QVariant::StringList; + d->shouldBeIndexed = false; + break; + + case Property::Height: + d->name = QLatin1String("height"); + d->displayName = i18nc("@label", "Height"); + d->valueType = QVariant::Int; + break; + + case Property::ImageDateTime: + d->name = QLatin1String("imageDateTime"); + d->displayName = i18nc("@label EXIF", "Image Date Time"); + d->valueType = QVariant::DateTime; + break; + + case Property::ImageMake: + d->name = QLatin1String("imageMake"); + d->displayName = i18nc("@label EXIF", "Image Make"); + d->valueType = QVariant::String; + d->shouldBeIndexed = false; + break; + + case Property::ImageModel: + d->name = QLatin1String("imageModel"); + d->displayName = i18nc("@label EXIF", "Image Model"); + d->valueType = QVariant::String; + d->shouldBeIndexed = false; + break; + + case Property::ImageOrientation: + d->name = QLatin1String("imageOrientation"); + d->displayName = i18nc("@label EXIF", "Image Orientation"); + d->valueType = QVariant::Int; + break; + + case Property::Keywords: + d->name = QLatin1String("keywords"); + d->displayName = i18nc("@label", "Keywords"); + d->valueType = QVariant::StringList; + d->shouldBeIndexed = false; + break; + + case Property::Langauge: + d->name = QLatin1String("language"); + d->displayName = i18nc("@label", "Language"); + d->valueType = QVariant::String; + d->shouldBeIndexed = false; + break; + + case Property::LineCount: + d->name = QLatin1String("lineCount"); + d->displayName = i18nc("@label number of lines", "Line Count"); + d->valueType = QVariant::Int; + break; + + case Property::Lyricist: + d->name = QLatin1String("lyricist"); + d->displayName = i18nc("@label", "Lyricist"); + d->valueType = QVariant::StringList; + d->shouldBeIndexed = false; + break; + + case Property::PageCount: + d->name = QLatin1String("pageCount"); + d->displayName = i18nc("@label", "Page Count"); + d->valueType = QVariant::Int; + break; + + case Property::PhotoApertureValue: + d->name = QLatin1String("photoApertureValue"); + d->displayName = i18nc("@label EXIF", "Photo Aperture Value"); + d->valueType = QVariant::Double; + break; + + case Property::PhotoDateTimeOriginal: + d->name = QLatin1String("photoDateTimeOriginal"); + d->displayName = i18nc("@label EXIF", "Photo Original Date Time"); + d->valueType = QVariant::DateTime; + break; + + case Property::PhotoExposureBiasValue: + d->name = QLatin1String("photoExposureBiasValue"); + d->displayName = i18nc("@label EXIF", "Photo Exposure Bias"); + d->valueType = QVariant::Double; + break; + + case Property::PhotoExposureTime: + d->name = QLatin1String("photoExposureTime"); + d->displayName = i18nc("@label EXIF", "Photo Exposure Time"); + d->valueType = QVariant::Double; + break; + + case Property::PhotoFlash: + d->name = QLatin1String("photoFlash"); + d->displayName = i18nc("@label EXIF", "Photo Flash"); + d->valueType = QVariant::Int; + break; + + case Property::PhotoFNumber: + d->name = QLatin1String("photoFNumber"); + d->displayName = i18nc("@label EXIF", "Photo F Number"); + d->valueType = QVariant::Int; + break; + + case Property::PhotoFocalLength: + d->name = QLatin1String("photoFocalLength"); + d->displayName = i18nc("@label EXIF", "Photo Focal Length"); + d->valueType = QVariant::Double; + break; + + case Property::PhotoFocalLengthIn35mmFilm: + d->name = QLatin1String("photoFocalLengthIn35mmFilm"); + d->displayName = i18nc("@label EXIF", "Photo Focal Length 35mm"); + d->valueType = QVariant::Double; + break; + + case Property::PhotoISOSpeedRatings: + d->name = QLatin1String("photoISOSpeedRatings"); + d->displayName = i18nc("@label EXIF", "Photo ISO Speed Rating"); + d->valueType = QVariant::Int; + break; + + case Property::PhotoMeteringMode: + d->name = QLatin1String("photoMeteringMode"); + d->displayName = i18nc("@label EXIF", "Photo Metering Mode"); + d->valueType = QVariant::Int; + break; + + case Property::PhotoPixelXDimension: + d->name = QLatin1String("photoPixelXDimension"); + d->displayName = i18nc("@label EXIF", "Photo X Dimension"); + d->valueType = QVariant::Int; + break; + + case Property::PhotoPixelYDimension: + d->name = QLatin1String("photoPixelYDimension"); + d->displayName = i18nc("@label EXIF", "Photo Y Dimension"); + d->valueType = QVariant::Int; + break; + + case Property::PhotoSaturation: + d->name = QLatin1String("photoSaturation"); + d->displayName = i18nc("@label EXIF", "Photo Saturation"); + d->valueType = QVariant::Int; + break; + + case Property::PhotoSharpness: + d->name = QLatin1String("photoSharpness"); + d->displayName = i18nc("@label EXIF", "Photo Sharpness"); + d->valueType = QVariant::Int; + break; + + case Property::PhotoWhiteBalance: + d->name = QLatin1String("photoWhiteBalance"); + d->displayName = i18nc("@label EXIF", "Photo White Balance"); + d->valueType = QVariant::Int; + break; + + case Property::Publisher: + d->name = QLatin1String("publisher"); + d->displayName = i18nc("@label", "Publisher"); + d->valueType = QVariant::String; + break; + + case Property::ReleaseYear: + d->name = QLatin1String("releaseYear"); + d->displayName = i18nc("@label", "Release Year"); + d->valueType = QVariant::Int; + break; + + case Property::SampleRate: + d->name = QLatin1String("sampleRate"); + d->displayName = i18nc("@label", "Sample Rate"); + d->valueType = QVariant::Int; + break; + + case Property::Subject: + d->name = QLatin1String("subject"); + d->displayName = i18nc("@label", "Subject"); + d->valueType = QVariant::String; + d->shouldBeIndexed = false; + break; + + case Property::Title: + d->name = QLatin1String("title"); + d->displayName = i18nc("@label", "Title"); + d->valueType = QVariant::String; + break; + + case Property::TrackNumber: + d->name = QLatin1String("trackNumber"); + d->displayName = i18nc("@label music track number", "Track Number"); + d->valueType = QVariant::Int; + break; + + case Property::Width: + d->name = QLatin1String("width"); + d->displayName = i18nc("@label", "Width"); + d->valueType = QVariant::Int; + break; + + case Property::WordCount: + d->name = QLatin1String("wordCount"); + d->displayName = i18nc("@label number of words", "Word Count"); + d->valueType = QVariant::Int; + break; + + default: + break; + } + + if (d->valueType == QVariant::Int || d->valueType == QVariant::DateTime || + d->valueType == QVariant::Double) + { + d->shouldBeIndexed = false; + } +} + +PropertyInfo::PropertyInfo(const PropertyInfo& pi) + : d(new Private(*pi.d)) +{ +} + +PropertyInfo::~PropertyInfo() +{ + delete d; +} + +QString PropertyInfo::displayName() const +{ + return d->displayName; +} + +QString PropertyInfo::name() const +{ + return d->name; +} + +Property::Property PropertyInfo::property() const +{ + return d->prop; +} + +QVariant::Type PropertyInfo::valueType() const +{ + return d->valueType; +} + +bool PropertyInfo::shouldBeIndexed() const +{ + return d->shouldBeIndexed; +} + +PropertyInfo PropertyInfo::fromName(const QString& name) +{ + static QHash propertyHash; + + // FIXME: Multi-threading? + if (propertyHash.isEmpty()) { + propertyHash.insert(QLatin1String("bitrate"), Property::BitRate); + propertyHash.insert(QLatin1String("channels"), Property::Channels); + propertyHash.insert(QLatin1String("duration"), Property::Duration); + propertyHash.insert(QLatin1String("genre"), Property::Genre); + propertyHash.insert(QLatin1String("samplerate"), Property::SampleRate); + propertyHash.insert(QLatin1String("tracknumber"), Property::TrackNumber); + propertyHash.insert(QLatin1String("releaseyear"), Property::ReleaseYear); + propertyHash.insert(QLatin1String("comment"), Property::Comment); + propertyHash.insert(QLatin1String("artist"), Property::Artist); + propertyHash.insert(QLatin1String("album"), Property::Album); + propertyHash.insert(QLatin1String("albumartist"), Property::AlbumArtist); + propertyHash.insert(QLatin1String("composer"), Property::Composer); + propertyHash.insert(QLatin1String("lyricist"), Property::Lyricist); + propertyHash.insert(QLatin1String("author"), Property::Author); + propertyHash.insert(QLatin1String("title"), Property::Title); + propertyHash.insert(QLatin1String("subject"), Property::Subject); + propertyHash.insert(QLatin1String("creator"), Property::Creator); + propertyHash.insert(QLatin1String("generator"), Property::Generator); + propertyHash.insert(QLatin1String("pagecount"), Property::PageCount); + propertyHash.insert(QLatin1String("wordcount"), Property::WordCount); + propertyHash.insert(QLatin1String("linecount"), Property::LineCount); + propertyHash.insert(QLatin1String("language"), Property::Langauge); + propertyHash.insert(QLatin1String("copyright"), Property::Copyright); + propertyHash.insert(QLatin1String("publisher"), Property::Publisher); + propertyHash.insert(QLatin1String("description"), Property::Description); + propertyHash.insert(QLatin1String("creationdate"), Property::CreationDate); + propertyHash.insert(QLatin1String("keywords"), Property::Keywords); + propertyHash.insert(QLatin1String("width"), Property::Width); + propertyHash.insert(QLatin1String("height"), Property::Height); + propertyHash.insert(QLatin1String("aspectratio"), Property::AspectRatio); + propertyHash.insert(QLatin1String("framerate"), Property::FrameRate); + propertyHash.insert(QLatin1String("imagemake"), Property::ImageMake); + propertyHash.insert(QLatin1String("imagemodel"), Property::ImageModel); + propertyHash.insert(QLatin1String("imagedatetime"), Property::ImageDateTime); + propertyHash.insert(QLatin1String("imageorientation"), Property::ImageOrientation); + propertyHash.insert(QLatin1String("photoflash"), Property::PhotoFlash); + propertyHash.insert(QLatin1String("photopixelxdimension"), Property::PhotoPixelXDimension); + propertyHash.insert(QLatin1String("photopixelydimension"), Property::PhotoPixelYDimension); + propertyHash.insert(QLatin1String("photodatetimeoriginal"), Property::PhotoDateTimeOriginal); + propertyHash.insert(QLatin1String("photofocallength"), Property::PhotoFocalLength); + propertyHash.insert(QLatin1String("photofocallengthin35mmfilm"), Property::PhotoFocalLengthIn35mmFilm); + propertyHash.insert(QLatin1String("photoexposuretime"), Property::PhotoExposureTime); + propertyHash.insert(QLatin1String("photofnumber"), Property::PhotoFNumber); + propertyHash.insert(QLatin1String("photoaperturevalue"), Property::PhotoApertureValue); + propertyHash.insert(QLatin1String("photoexposurebiasvalue"), Property::PhotoExposureBiasValue); + propertyHash.insert(QLatin1String("photowhitebalance"), Property::PhotoWhiteBalance); + propertyHash.insert(QLatin1String("photometeringmode"), Property::PhotoMeteringMode); + propertyHash.insert(QLatin1String("photoisospeedratings"), Property::PhotoISOSpeedRatings); + propertyHash.insert(QLatin1String("photosaturation"), Property::PhotoSaturation); + propertyHash.insert(QLatin1String("photosharpness"), Property::PhotoSharpness); + } + + return PropertyInfo(propertyHash.value(name.toLower())); +} diff --git a/kfilemetadata/src/propertyinfo.h b/kfilemetadata/src/propertyinfo.h new file mode 100644 index 00000000..bb54f58c --- /dev/null +++ b/kfilemetadata/src/propertyinfo.h @@ -0,0 +1,81 @@ +/* + * This file is part of the KFileMetaData project + * Copyright (C) 2014 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#ifndef _KFILEMETADATA_PROPERTYINFO_H +#define _KFILEMETADATA_PROPERTYINFO_H + +#include +#include +#include "properties.h" +#include "kfilemetadata_export.h" + +namespace KFileMetaData { + +class KFILEMETADATA_EXPORT PropertyInfo +{ +public: + PropertyInfo(Property::Property property); + PropertyInfo(const PropertyInfo& pi); + ~PropertyInfo(); + + /** + * The enumeration which represents this property + */ + Property::Property property() const; + + /** + * The internal developer named used to refer to the property + */ + QString name() const; + + /** + * A user visible name of the property + */ + QString displayName() const; + + /** + * The type the value of this property should be. + * Eg - Property::Height should be an integer + */ + QVariant::Type valueType() const; + + /** + * Indicates if this property requires indexing or should just be stored. + * Eg - Property::Height does not need to be part of the global index. + * When a user searches for 600, they should not get images with + * that height + */ + bool shouldBeIndexed() const; + + /** + * Construct a PropertyInfo from the internal property name. + * The internal property name is case insensitive + */ + static PropertyInfo fromName(const QString& name); + +private: + class Private; + Private* d; +}; + +} +#endif // _KFILEMETADATA_PROPERTYINFO_H diff --git a/kfilemetadata/src/typeinfo.cpp b/kfilemetadata/src/typeinfo.cpp new file mode 100644 index 00000000..4ae1a65b --- /dev/null +++ b/kfilemetadata/src/typeinfo.cpp @@ -0,0 +1,101 @@ +/* + * + * Copyright (C) 2014 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "typeinfo.h" + +#include + +using namespace KFileMetaData; + +class TypeInfo::Private { +public: + Type::Type type; + QString name; + QString displayName; +}; + +TypeInfo::TypeInfo(Type::Type type) + : d(new Private) +{ + d->type = type; + + switch (type) { + case Type::Archive: + d->name = QLatin1String("Archive"); + d->displayName = i18nc("@label", "Archive"); + break; + + case Type::Audio: + d->name = QLatin1String("Audio"); + d->displayName = i18nc("@label", "Audio"); + break; + + case Type::Document: + d->name = QLatin1String("Document"); + d->displayName = i18nc("@label", "Document"); + break; + + case Type::Image: + d->name = QLatin1String("Image"); + d->displayName = i18nc("@label", "Image"); + break; + + case Type::Presentation: + d->name = QLatin1String("Presentation"); + d->displayName = i18nc("@label", "Presentation"); + break; + + case Type::Spreadsheet: + d->name = QLatin1String("Spreadsheet"); + d->displayName = i18nc("@label", "Spreadsheet"); + break; + + case Type::Text: + d->name = QLatin1String("Text"); + d->displayName = i18nc("@label", "Text"); + break; + + case Type::Video: + d->name = QLatin1String("Video"); + d->displayName = i18nc("@label", "Video"); + break; + } +} + +TypeInfo::TypeInfo(const TypeInfo& ti) + : d(new Private(*ti.d)) +{ +} + +TypeInfo::~TypeInfo() +{ + delete d; +} + +QString TypeInfo::displayName() const +{ + return d->displayName; +} + +QString TypeInfo::name() const +{ + return d->name; +} + diff --git a/kfilemetadata/src/typeinfo.h b/kfilemetadata/src/typeinfo.h new file mode 100644 index 00000000..2675cbbd --- /dev/null +++ b/kfilemetadata/src/typeinfo.h @@ -0,0 +1,58 @@ +/* + * + * Copyright (C) 2014 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef KFILEMETADATA_TYPEINFO_H +#define KFILEMETADATA_TYPEINFO_H + +#include "types.h" +#include "kfilemetadata_export.h" +#include + +namespace KFileMetaData { + +class KFILEMETADATA_EXPORT TypeInfo +{ +public: + TypeInfo(Type::Type type); + TypeInfo(const TypeInfo& ti); + ~TypeInfo(); + + /** + * The type identifier + */ + Type::Type type() const; + + /** + * An internal name for the type + */ + QString name() const; + + /** + * A user visible translated name for this type + */ + QString displayName() const; + +private: + class Private; + Private* d; +}; +} + +#endif // KFILEMETADATA_TYPEINFO_H diff --git a/kfilemetadata/src/types.h b/kfilemetadata/src/types.h new file mode 100644 index 00000000..77b63db8 --- /dev/null +++ b/kfilemetadata/src/types.h @@ -0,0 +1,82 @@ +/* + * This file is part of KFileMetaData + * Copyright (C) 2014 Vishesh Handa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef KFILEMETADATA_TYPES +#define KFILEMETADATA_TYPES + +namespace KFileMetaData { +namespace Type { + +enum Type { + FirstType = 0, + + /** + * Any file which contains a compressed collection of other files + * eg - tar, zip, rar, gz + */ + Archive = 0, + + /** + * Used to mark any file which just contains audio. Do not use this + * type if the file also contains Video + */ + Audio, + + /** + * Any file which contains Video. It may also contain Audio + */ + Video, + + /** + * Any Image file. This includes both raster and vector formats. + */ + Image, + + /** + * Any file which counts as a document. Documents are generally + * files which contain rich text, formatting and maybe images + */ + Document, + + /** + * A SpreadSheet file. This is a specialization of the Document type + * Any file which has this type should also have the Document type + */ + Spreadsheet, + + /** + * A Presentation file. This is a specialization of the Document type. + * Any file which has this type should also have the Document type + */ + Presentation, + + /** + * Any file which just contains plain text data counts + * as a Text file + */ + Text, + + LastType = Text +}; + +} +} + +#endif diff --git a/svgpart/CMakeLists.txt b/svgpart/CMakeLists.txt new file mode 100644 index 00000000..2d6800a2 --- /dev/null +++ b/svgpart/CMakeLists.txt @@ -0,0 +1,22 @@ +project(svgpart) + +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + find_package(KDE4 4.19.0 REQUIRED) + include(KDE4Defaults) + include_directories(${KDE4_INCLUDES}) + add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) +endif() + +include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}) + +set(svgpart_SRCS + svgpart.cpp +) + +kde4_add_plugin(svgpart ${svgpart_SRCS}) + +target_link_libraries(svgpart ${KDE4_KPARTS_LIBS}) + +install(TARGETS svgpart DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) +install(FILES svgpart.desktop DESTINATION ${KDE4_SERVICES_INSTALL_DIR}) +install(FILES svgpart.rc DESTINATION ${KDE4_DATA_INSTALL_DIR}/svgpart) diff --git a/svgpart/COPYING b/svgpart/COPYING new file mode 100644 index 00000000..d511905c --- /dev/null +++ b/svgpart/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/svgpart/Messages.sh b/svgpart/Messages.sh new file mode 100755 index 00000000..afee0945 --- /dev/null +++ b/svgpart/Messages.sh @@ -0,0 +1,3 @@ +#! /bin/sh +$EXTRACTRC *.rc >> rc.cpp +$XGETTEXT *.cpp -o $podir/svgpart.pot diff --git a/svgpart/svgpart.cpp b/svgpart/svgpart.cpp new file mode 100644 index 00000000..7a14b154 --- /dev/null +++ b/svgpart/svgpart.cpp @@ -0,0 +1,109 @@ +/* +Copyright 2007 Aurélien Gâteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ +#include "moc_svgpart.cpp" + +// Qt +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include + +// Local + +static KAboutData createAboutData() +{ + KAboutData aboutData( "svgpart", 0, ki18n("SVG Part"), + "1.0", ki18n("A KPart to display SVG images"), + KAboutData::License_GPL, + ki18n("Copyright 2007, Aurélien Gâteau ")); + return aboutData; +} + +//Factory Code +K_PLUGIN_FACTORY( SvgPartFactory, registerPlugin< SvgPart >(); ) +K_EXPORT_PLUGIN( SvgPartFactory( createAboutData() ) ) + + +SvgPart::SvgPart(QWidget* parentWidget, QObject* parent, const QVariantList&) +: KParts::ReadOnlyPart(parent) +{ + mRenderer = new QSvgRenderer(this); + mScene = new QGraphicsScene(this); + mView = new QGraphicsView(mScene, parentWidget); + mView->setFrameStyle(QFrame::NoFrame); + mView->setDragMode(QGraphicsView::ScrollHandDrag); + mItem = 0; + setWidget(mView); + + KStandardAction::actualSize(this, SLOT(zoomActualSize()), actionCollection()); + KStandardAction::zoomIn(this, SLOT(zoomIn()), actionCollection()); + KStandardAction::zoomOut(this, SLOT(zoomOut()), actionCollection()); + setXMLFile("svgpart/svgpart.rc"); +} + + +bool SvgPart::openFile() { + if (!mRenderer->load(localFilePath())) { + return false; + } + mItem = new QGraphicsSvgItem(); + mItem->setSharedRenderer(mRenderer); + mScene->addItem(mItem); + return true; +} + + +bool SvgPart::closeUrl() { + delete mItem; + mItem = 0; + return KParts::ReadOnlyPart::closeUrl(); +} + + +void SvgPart::zoomIn() { + setZoom(zoom() * 2); +} + + +void SvgPart::zoomOut() { + setZoom(zoom() / 2); +} + + +void SvgPart::zoomActualSize() { + setZoom(1.0); +} + + +qreal SvgPart::zoom() const { + return mView->matrix().m11(); +} + + +void SvgPart::setZoom(qreal value) { + QMatrix matrix; + matrix.scale(value, value); + mView->setMatrix(matrix); +} diff --git a/svgpart/svgpart.desktop b/svgpart/svgpart.desktop new file mode 100644 index 00000000..249387ca --- /dev/null +++ b/svgpart/svgpart.desktop @@ -0,0 +1,67 @@ +[Desktop Entry] +Type=Service +Name=Svg Part +Name[ar]=جزء Svg +Name[ast]=Parte SVG +Name[bg]=Модул за Svg +Name[bs]=SVG dio +Name[ca]=Svg Part +Name[ca@valencia]=Svg Part +Name[cs]=SVG komponenta +Name[da]=Svg Part +Name[de]=SVG-Komponente +Name[el]=Τμήμα Svg +Name[en_GB]=Svg Part +Name[eo]=Svg komponanto +Name[es]=Parte SVG +Name[et]=Svg komponent +Name[eu]=SVGren zatia +Name[fi]=SVG-osa +Name[fr]=Composant SVG +Name[ga]=Comhpháirt Svg +Name[gl]=Compoñente de SVG +Name[hne]=एसवीजी पार्ट +Name[hr]=Svg Part +Name[hu]=SVG objektum +Name[ia]=Parte de SVG +Name[is]=Svg hlutur +Name[it]=Componente SVG +Name[ja]=SVG コンポーネント +Name[kk]=Svg компоненті +Name[km]=ផ្នែក Svg +Name[ko]=Svg 부분 +Name[ku]=Beşa Svg +Name[lt]=Svg Part +Name[lv]=Svg daļa +Name[mr]=Svg भाग +Name[nb]=Svg-del +Name[nds]=SVG-Komponent +Name[nl]=SVG-component +Name[nn]=SVG-del +Name[pa]=Svg ਭਾਗ +Name[pl]=Moduł SVG +Name[pt]=Componente de SVG +Name[pt_BR]=Componente SVG +Name[ro]=Componentă SVG +Name[ru]=Компонент просмотра Svg +Name[si]=Svg Part +Name[sk]=Svg komponent +Name[sl]=Sestavni del SVG +Name[sr]=СВГ део +Name[sr@ijekavian]=СВГ део +Name[sr@ijekavianlatin]=SVG deo +Name[sr@latin]=SVG deo +Name[sv]=SVG-delprogram +Name[th]=ส่วนจัดการ Svg +Name[tr]=Svg Parçacığı +Name[ug]=Svg Part +Name[uk]=Компонент Svg +Name[vi]=Phần nhúng đọc SVG +Name[x-test]=xxSvg Partxx +Name[zh_CN]=Svg 组件 +Name[zh_TW]=Svg 部件 +MimeType=image/svg+xml;image/svg+xml-compressed; +ServiceTypes=KParts/ReadOnlyPart +X-KDE-Library=svgpart +InitialPreference=12 +Icon=image-svg+xml diff --git a/svgpart/svgpart.h b/svgpart/svgpart.h new file mode 100644 index 00000000..a447a738 --- /dev/null +++ b/svgpart/svgpart.h @@ -0,0 +1,56 @@ +/* +Copyright 2007 Aurélien Gâteau + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ +#ifndef SVGPART_H +#define SVGPART_H + +// KDE +#include + + +#include +#include +#include +#include + +class SvgPart : public KParts::ReadOnlyPart { + Q_OBJECT +public: + SvgPart(QWidget* parentWidget, QObject* parent, const QVariantList&); + + virtual bool closeUrl(); + +protected: + virtual bool openFile(); + +private Q_SLOTS: + void zoomActualSize(); + void zoomIn(); + void zoomOut(); + +private: + QGraphicsScene* mScene; + QGraphicsView* mView; + QGraphicsSvgItem* mItem; + QSvgRenderer* mRenderer; + + qreal zoom() const; + void setZoom(qreal); +}; + +#endif /* SVGPART_H */ diff --git a/svgpart/svgpart.rc b/svgpart/svgpart.rc new file mode 100644 index 00000000..bd858c45 --- /dev/null +++ b/svgpart/svgpart.rc @@ -0,0 +1,22 @@ + + + + &View + + + + + + +Main Toolbar + + + + + + +